主题
Vitepress 切换暗黑模式丝滑动画
移植之前 Hexo 博客中使用的暗黑切换动画,主要用到的原理就是 设置动态css变量
、 原生视图过渡 - startViewTransition 以及 css的clip-path属性
1. 设置全局css
新建 dark.css
,并注入到主题配置 docs/.vitepress/theme/index.ts
中
css
/**
* 黑暗模式切换动画
* -------------------------------------------------------------------------- */
::view-transition-old(*) {
animation: none;
}
::view-transition-new(*) {
animation: globalDark .8s ease-in;
}
@keyframes globalDark {
from {
clip-path: circle(0% at var(--darkX) var(--darkY));
}
to {
clip-path: circle(100% at var(--darkX) var(--darkY));
}
}
/**
* 黑暗模式下图片低亮度化
* -------------------------------------------------------------------------- */
.dark img {
filter: brightness(0.8);
}
切换动画速度,通过 animation
中的时间控制
2. 设置动态css变量
新建 Dark.ts
,并在 Layout
插槽中使用
ts
import { nextTick, provide } from 'vue'
// 判断是否能使用 startViewTransition
const enableTransitions = () => {
return 'startViewTransition' in document && window.matchMedia('(prefers-reduced-motion: no-preference)').matches
}
// 切换动画
export const toggleDark = (isDark) => {
provide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {
//如果不支持动效直接切换
if (!enableTransitions()) {
isDark.value = !isDark.value
return
}
document.documentElement.style.setProperty('--darkX', x + 'px')
document.documentElement.style.setProperty('--darkY', y + 'px')
// 原生的视图转换动画 https://developer.mozilla.org/zh-CN/docs/Web/API/Document/startViewTransition
// pnpm add -D @types/dom-view-transitions 解决 document.startViewTransition 类型错误的问题
await document.startViewTransition(async () => {
isDark.value = !isDark.value
await nextTick()
}).ready
})
}
vue
<script setup lang="ts">
import { useData } from 'vitepress'
import { toggleDark } from './Dark'
const { isDark } = useData()
// 实现切换主题过渡动画
toggleDark(isDark)
</script>
最后将Layout
插槽组件,注入到 主题配置 docs/.vitepress/theme/index.ts
中
ts
import DefaultTheme from 'vitepress/theme'
import Layout from './Layout.vue'
// 暗黑样式
import './style/dark.css'
export default {
extends: DefaultTheme,
// 使用注入插槽的包装组件覆盖 Layout
Layout: Layout
}