必须用 :root 声明 css 自定义变量,因其是全局作用域且 js 仅能通过 document.documentelement 读取;命名需语义化(如 --color-primary)、统一前缀、避免设计稿编号;深色模式应通过 data-theme 属性控制而非仅依赖 prefers-color-scheme;var() 回退值仅在变量未定义或非法时生效,关键样式须显式提供回退。

必须用 :root 声明,别写在 html 或 body 里
浏览器把 :root 当作 CSS 全局作用域,所有后代元素都能继承这些变量;而 html 或 body 声明的变量在 Shadow DOM、某些框架组件或嵌套上下文中可能失效。更关键的是,JS 读取变量时(比如 getComputedStyle(document.documentElement).getPropertyValue('--primary'))只认 :root 上的声明。
常见错误:
- 直接写 --primary-color: #007bff;(没包裹在选择器里)→ 浏览器静默忽略
- 写成 html { --primary-color: #007bff; } → 在部分 Web Component 场景下无法被子树访问
- 把变量分散到多个组件选择器里(如 .button { --btn-bg: ... })→ 失去全局统一性,改主色要翻十处
正确写法:
:root {
--color-primary: #2563eb;
--color-text: #1e293b;
--color-bg-surface: #ffffff;
}
命名必须语义化,别用 --blue-500 这类“设计稿编号”
语义名指颜色的用途,不是它的视觉表现。一旦设计规范调整(比如主色从蓝色换成紫色),--blue-500 就成了误导性名称,团队协作时极易误用。
-
--color-primary(按钮、链接、强调色)优于--blue-500 -
--color-success(操作成功反馈)优于--green-400 -
--color-border-divider(分隔线/边框)优于--gray-200 - 统一前缀,如全部用
--color-开头,避免和第三方库(如 Tailwind 的--tw-)冲突
额外提示:别混用单位和格式——--color-bg: rgba(0,0,0,0.04) 看似方便,但 JS 无法解析 alpha 值做计算;应拆成 --color-bg: #000000 和 --alpha-overlay: 0.04。
深色模式切换不能只靠 @media (prefers-color-scheme: dark)
系统级暗色偏好可以用媒体查询覆盖变量,但业务中更多是用户手动点击切换主题(比如右上角“?”图标)。这时候仅靠媒体查询会失效——它不响应 JS 触发的主动切换。
稳解法是用 data-theme 属性配合层叠优先级:
:root {
--color-primary: #2563eb;
--color-bg-surface: #ffffff;
}
<p>:root[data-theme="dark"] {
--color-primary: #3b82f6;
--color-bg-surface: #1e293b;
}</p>
然后 JS 只需:
document.documentElement.dataset.theme = 'dark'
注意三点:
- 所有变量必须显式重写,哪怕值和 light 模式相同也要写出来(漏一个,就可能 fallback 到旧值导致文字不可读)
- [data-theme="dark"] :root 的选择器权重是 110,远高于普通 class(10),不会被组件内部的 .dark 类意外覆盖
- 切换前确保 HTML 已解析完成,否则会触发 FOUC(闪白)
var(--color, #000) 的回退值不是“兜底保险”,而是“语法兜底”
很多人以为回退值会在主题未加载或变量为空时起作用,其实它只在两种情况下生效:
- 变量名拼错(如 var(--primar-color))
- 变量根本没定义(整个 :root 块没加载)
- 变量值非法(如 --size: 12 缺单位)
但以下情况回退值**完全不触发**:
- --color-primary: inherit;(合法值)
- --color-primary: transparent;(合法值)
- --color-primary: ;(空值 → 触发回退)
- --color-primary: undefined;(字符串 → 触发回退)
所以关键样式别依赖回退,例如:
background-color: var(--color-bg-surface, #ffffff); color: var(--color-text, #1e293b);
比写成 color: var(--color-text); 更安全——因为一旦变量被设为 inherit,文字就可能变成父级颜色而不可读,且开发者工具里只显示 invalid,很难定位。
真正容易被忽略的点是:HSL 分量变量(如 --h-primary)一旦某个分量未定义,整条 hsl(var(--h), var(--s), var(--l)) 就会失效,回退值也救不了——得每个分量都配回退,或者直接用十六进制保底。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











