<p>通配符选择器 * 是性能杀手,强制浏览器对每个 DOM 节点执行样式计算,导致样式计算阶段耗时剧增,尤其在大型 SPA 或动画滚动中易掉帧。</p>

通配符选择器 * 在 CSS 中是性能杀手,不是“写起来省事”,而是“跑起来拖垮渲染”。它强制浏览器为每个 DOM 节点执行样式计算,哪怕那个节点压根用不到这条规则。
为什么 * 会导致卡顿
浏览器解析选择器时从右向左匹配,* 没有筛选能力,所以它会成为“起点锚点”——即先抓取全部节点,再逐个验证后续条件(如果有)。哪怕只写一条 * { box-sizing: border-box; },也会触发全量遍历。在拥有数千节点的 SPA 页面中,这直接抬高样式计算(Style Calculation)阶段耗时,尤其在动画或滚动期间容易掉帧。
- DOM 节点越多,开销越非线性增长
- 与
::before/::after配合时(如*::before),还会额外触发伪元素创建和布局重排 - 现代 DevTools 的 “Rendering” 面板里能看到
Recalculate Style时间异常升高
用 html 和 *::before/*::after 替代全局 *
大多数项目用 * 其实就两个目的:重置盒模型、统一伪元素继承。这两者完全可以用更精准的方式实现,且被所有主流浏览器稳定支持。
- 把
* { box-sizing: border-box; }换成html { box-sizing: border-box; }—— 因为box-sizing可继承,html是根,子元素自然继承 - 把
*::before, *::after { box-sizing: inherit; }单独保留 —— 这是必要补充,因为伪元素不自动继承box-sizing - 避免写
body * { ... }这类“伪精确”选择器,它仍是全量后代扫描,没本质改善
重置类名比通配符更可控
真正需要“局部重置”的场景(比如弹窗、卡片、富文本内容区),应该用语义化类名显式控制,而不是靠 * 暗地扫荡。
立即学习“前端免费学习笔记(深入)”;
- 定义
.reset-inset { margin: 0; padding: 0; },只在需要的地方加这个 class - 对富文本内容,用
.content-rich * { max-width: 100%; height: auto; }—— 注意这里限制了作用域,不是全局 - 禁止在 Sass/Less 中用
& *嵌套生成隐式通配,这类代码在编译后难以审计
检查并替换现有 * 的实际路径
别只改 CSS 文件,还要确认构建产物和运行时是否真生效。有些框架(如 Next.js、Remix)会在服务端注入默认 reset,可能藏在 style 标签或第三方 CSS 中。
- 打开 DevTools → Elements → 搜索
<style>或内联style属性,找*出现位置 - 用 Lighthouse 的 “Avoid large, complex render trees” 建议定位高代价选择器
- 运行
getComputedStyle(document.body).boxSizing确认是否仍被*干扰(应返回border-box,否则说明重置未覆盖)
真正难的不是替换那几行 *,而是识别哪些“看起来安全”的选择器(比如 .modal *)其实仍在做无差别遍历。每次加新样式前,先问一句:这个规则,是不是真的必须作用于所有后代?



















