必须将所有主题变量声明在 :root 中,因为 css 自定义属性依赖继承,只有 :root(即 )能确保全局可访问;错误写法如 html、.dark 或 body 下声明会导致表单控件等无法继承而回退默认值。

必须把所有主题变量写在 :root 里,否则切换必然失效——这不是风格选择,是 CSS 自定义属性作用域的硬性限制。
为什么只能在 :root 声明变量
CSS 自定义属性靠继承传播,而只有 :root(等价于 元素)能确保任意元素,包括 <input>、<select></select>、::before、SVG 和 Shadow DOM 内部(需手动传入),都能通过 var(--bg-color) 正确读取。常见错误包括:
-
html { --color: red; }:非标准写法,部分环境(如旧版 Safari)直接忽略 -
.dark { --color: #121212; }:变量只在该类子树生效,表单控件若未被包裹就 fallback 到浏览器默认值 -
body { --text-color: #eee; }:上求值时根本找不到定义
:root 里变量怎么写才不 fallback
所有用到的变量必须在默认 :root 块中完整声明,哪怕深色/浅色下值相同也不能漏。否则页面一渲染就 fallback 成 transparent 或浏览器默认色。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 变量名必须以
--开头,且不含空格或非法字符:--font-size-lg✅,--font size lg❌ - 值要带单位:
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);,不能只写0 1 2 - 用
rem或em时,必须提前设好html { font-size: 16px; },否则响应式错乱 - 正确示例:
:root { --bg-primary: #ffffff; --text-primary: #1a1a1a; --border-color: #e0e0e0; --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05); }
手动切换时别碰 style.setProperty()
调用 document.documentElement.style.setProperty('--bg-primary', '#121212') 看似直白,实际会破坏整套机制:
- 覆盖
@media (prefers-color-scheme: dark)的自动响应逻辑,系统切换主题后页面毫无反应 - 逐个设置大量变量会卡 UI 线程,低端设备上明显卡顿
- 新增一个颜色就得同步改 JS 和 CSS 两处,维护成本爆炸
- 真正轻量的做法是只操作 class:
document.documentElement.classList.add('dark'),让 CSS 规则自动重算
初始化必须早于首屏渲染,且联动 localStorage
页面闪屏(白底→黑底)90% 是因为 class 没在 DOM 加载完成前设置。初始化逻辑必须三步到位:
- 读取
localStorage.getItem('theme'),而非依赖matchMedia初始值 - 在
<script></script>标签内直接操作document.documentElement.classList,不要等DOMContentLoaded - 切换按钮点击后,同步执行
classList.toggle('dark')和localStorage.setItem('theme', newTheme)
漏掉任一环,用户刷新后主题就回退,或者原生控件颜色不一致。最易被忽略的是:变量声明必须放在 最上方的 <style></style> 中,且 @media (prefers-color-scheme: dark) 必须紧接在默认 :root 声明之后,不能嵌套、不能错序。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










