在 Vue 项目中实现 github-markdown-css 的亮色与暗色模式动态切换
前言
最近项目中需要接入用户协议与隐私政策,法务部门提供的是 Word 文档。为了方便维护和在项目中直接渲染,我将文档转换为 Markdown 格式,并通过 Vite 的 unplugin-vue-markdown 插件将其作为 Vue 组件直接引入:
<template>
<Privacy />
</template>
<script lang="ts" setup>
import Privacy from "@/locales-other/zh-CN/agreements/privacy.md";
</script>内容渲染所在的容器通常带有一个 markdown-body 的类名。由于浏览器默认样式较为简陋,我决定引入 github-markdown-css 来复刻 GitHub 优雅的阅读体验。
首先安装依赖:
pnpm i github-markdown-css然而,在对接项目现有的亮/暗色模式切换机制时,我遇到了一些样式冲突的问题。本文将分享如何优雅地解决这一问题。
项目中的暗色模式实现机制
在介绍解决方案前,先简要说明项目中现有的主题切换方案。通常我们使用 vueuse 库中的 useDark 和 useToggle 来管理:
import { useDark, useToggle } from "@vueuse/core";
const isDark = useDark({
valueDark: "dark",
valueLight: "light"
});
const toggleDark = useToggle(isDark);为了方便全局调用,这部分逻辑通常封装在 Pinia Store 中。该方案会自动监听系统主题变化,或通过用户手动切换,在 html 标签上动态添加或移除 dark 类名:
<html class="dark">
...
</html>配合 CSS 变量,我们可以轻松实现主题切换:
:root {
--bg: #fff;
}
:root.dark {
--bg: #000;
}
body {
background-color: var(--bg);
}遇到的问题:样式适配冲突
在引入 github-markdown-css 时,最直接的方式是在 main.ts 中全局引入:
import "github-markdown-css";问题在于:默认引入的样式文件是通过 CSS 媒体查询 @media (prefers-color-scheme: dark) 来适配系统主题的,它并不识别我们在 html 标签上添加的 .dark 类名。这导致当用户在项目中手动切换主题时,Markdown 的样式无法随之切换。
解决方案:动态加载样式文件
为了解决上述冲突,我们需要根据当前的模式(Light/Dark)动态加载对应的 CSS 文件。
在 github-markdown-css 5.0 及以上版本中,作者提供了独立的文件:github-markdown-light.css 和 github-markdown-dark.css。需要注意的是,这两个文件不能同时引入,否则样式规则会发生冲突。
因此,最佳实践是使用 <link> 标签引入样式,并根据主题状态动态修改其 href 属性。在 Vue 项目中,我们可以利用 @unhead/vue 来优雅地管理头部标签。
题外话:如果你为了更好的响应体验,我觉得可以使用两个link标签,分别对应亮色和暗色模式,然后通过 disabled 属性来控制启用状态。不过本文不展开讨论这一点。1. 安装依赖
pnpm i @unhead/vue2. 实现动态切换逻辑
我们可以在根组件 App.vue 或布局组件中编写如下逻辑。利用 Vite 的 ?url 后缀,我们可以获取 CSS 文件的静态资源路径,而不是将其作为样式直接注入到 JS bundle 中。
<template>
<router-view />
</template>
<script lang="ts" setup>
import { useHead } from "@unhead/vue";
import { useAppStore } from "@/stores";
// 显式获取 CSS 文件的 URL 路径
import markdownLightUrl from "github-markdown-css/github-markdown-light.css?url";
import markdownDarkUrl from "github-markdown-css/github-markdown-dark.css?url";
const appStore = useAppStore();
useHead({
link: [
{
key: "markdown-theme", // 设置 key 以确保 link 标签会被替换而不是追加
rel: "stylesheet",
href: () => (appStore.isDark ? markdownDarkUrl : markdownLightUrl)
}
]
});
</script>总结
通过 ?url 引入资源路径配合 useHead 的响应式处理,我们成功实现了 github-markdown-css 样式跟随项目主题的丝滑切换。这种方式既保留了 GitHub 的原生样式体验,又完美兼容了基于类名的暗色模式方案。
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据