Next.js中基于dark类高效切换Prism代码高亮样式的方法
Next.js中结合TailwindCSS与Prism实现高效暗色模式代码样式切换
现状说明
我正在用TailwindCSS和Prism为Next.js应用的MDX文件设置代码样式,已实现暗色模式切换功能——开启时会给<html>标签添加dark类:
亮模式下的HTML标签:
<html class="h-full antialiased"><!-- rest of the html document --></html>
暗模式下的HTML标签:
<html class="h-full antialiased dark"><!-- rest of the html document --></html>
需要为Prism代码块设置分模式的样式:
亮模式(无dark类)样式
pre[class*="language-"]::selection, pre[class*="language-"] ::selection, code[class*="language-"]::selection, code[class*="language-"] ::selection { text-shadow: none; background: rgba(224, 224, 224, 0.99); } .token.comment, .token.prolog, .token.cdata { color: rgb(152, 159, 177); } .token.punctuation { color: rgb(153, 76, 195); }
暗模式(有dark类)样式
pre[class*="language-"]::selection, pre[class*="language-"] ::selection, code[class*="language-"]::selection, code[class*="language-"] ::selection { text-shadow: none; background: rgba(29, 59, 83, 0.99); } .token.comment, .token.prolog, .token.cdata { color: rgb(99, 119, 119); } .token.punctuation { color: rgb(199, 146, 234); }
注:实际样式表包含更多类
问题与尝试过的方法
我想找更高效的实现方式,目前试过两种方案:
- 给每个样式类手动添加
.dark前缀:有效但操作繁琐,示例:
.dark .token.punctuation { color: rgb(199, 146, 234); }
- 使用嵌套写法:完全无效,示例:
.dark { pre[class*="language-"]::selection, pre[class*="language-"] ::selection, code[class*="language-"]::selection, code[class*="language-"] ::selection { text-shadow: none; background: rgba(29, 59, 83, 0.99); } .token.comment, .token.prolog, .token.cdata { color: rgb(99, 119, 119); } .token.punctuation { color: rgb(199, 146, 234); } }
当前实现细节
- 通过
_document.tsx中的脚本切换暗色模式:
import { Head, Html, Main, NextScript } from 'next/document'; const modeScript = ` const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); updateMode(); darkModeMediaQuery.addEventListener('change', updateModeWithoutTransitions); window.addEventListener('storage', updateModeWithoutTransitions); function updateMode() { const isSystemDarkMode = darkModeMediaQuery.matches; const isDarkMode = window.localStorage.isDarkMode === 'true' || (!('isDarkMode' in window.localStorage) && isSystemDarkMode); if (isDarkMode) { document.documentElement.classList.add('dark'); } else { document.documentElement.classList.remove('dark'); } if (isDarkMode === isSystemDarkMode) { delete window.localStorage.isDarkMode; } } function disableTransitionsTemporarily() { document.documentElement.classList.add('[&_*]:!transition-none'); window.setTimeout(() => { document.documentElement.classList.remove('[&_*]:!transition-none'); }, 0); } function updateModeWithoutTransitions() { disableTransitionsTemporarily(); updateMode(); } `; export default function Document() { return ( <Html className="h-full antialiased" lang="en"> <Head> <script dangerouslySetInnerHTML={{ __html: modeScript }} /> // ... </Html> ); }
- 在
pages/_app.tsx中导入样式:globals.css内容:
@tailwind base; @tailwind components; @tailwind utilities; @import './prism.css';
_app.tsx中的导入:
// in _app.tsx import '~/styles/globals.css';
我还考虑过通过TypeScript导入对应CSS文件,但也未能实现。
内容的提问来源于stack exchange,提问作者J. Hesters
相关产品推荐
相关产品推荐

