必须用:root声明css变量,因其是规范指定的全局锚点,特异性更高、跨文档兼容且继承可靠;body声明会导致继承失效、旧版safari不识别、层叠不可预测。

直接在 :root 中定义语义化变量并绑定到关键重置属性,比硬写数值快得多——改一个值,font-size、line-height、padding、margin 全自动响应,且不破坏继承链。
为什么不能只在 body 里设 font-size: 16px?
因为 body 的 font-size 不是全局基准源:它本身可能被父级(比如 html)缩放覆盖;JS 动态调整时无法精准控制;第三方组件若依赖 rem,但根元素没暴露变量,就完全失联。
-
:root是唯一能保证变量全局可读、可被 JS 修改、且不受嵌套影响的作用域 - 必须显式让
html或body消费该变量,例如html { font-size: var(--font-base, 16px); } - 如果只写
:root { --font-base: 16px; }却不绑定到font-size,所有1rem仍按浏览器默认(通常是 16px),变量形同虚设
box-sizing: border-box 必须覆盖伪元素和 SVG
仅写 * { box-sizing: border-box; } 会导致 ::before、::after 和内联 <svg></svg> 仍用 content-box,结果 padding 撑出滚动条、SVG 图标尺寸错乱。
- 正确写法:
*, *::before, *::after, svg { box-sizing: border-box; } - 如果项目用了 CSS 变量控制圆角或边框,也要确保这些变量在
:root定义,而非局部选择器下 - 检查 DevTools 的 Computed 面板,确认
box-sizing在伪元素上显示为border-box,而不是inherited或空值
表单控件重置必须用 font: inherit
把 input、button 的 font-size 设成 1rem 或 100%,会切断继承链——父容器若用 --text-sm: 0.875rem 控制字号,表单控件收不到。
- 统一写:
button, input, select, textarea { font: inherit; line-height: normal; } - 这样它们的
font-size在 Computed 面板中显示为inherited from body,而非固定像素值 - 后续只需改
body或:root中的字体变量,所有表单控件自动同步,无需单独 selector 覆盖
normalize.css 加载顺序和变量配合的关键点
normalize.css 是基线修复者,不是样式兜底层——它必须在所有含变量的 CSS 之前加载,否则你定义的 --color-primary 或 --space-md 可能被它的更具体规则覆盖。
- 错误做法:在
main.css顶部 import normalize,底部才写:root { --space-md: 1rem; } - 正确做法:确保
normalize.css是第一个被解析的 CSS 文件;:root声明紧随其后 - 如果用 PostCSS,启用
postcss-normalize插件时,要关掉自动注入,改用手动@import,避免构建时顺序失控
最易被忽略的是变量作用域与继承的边界:伪元素、iframe、Shadow DOM 默认拿不到 :root 变量,而很多 UI 库内部用了 Shadow DOM —— 这时候得在组件根节点手动 setProperty,不能只靠全局声明。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











