*会让Recalculate Style时间飙升,因浏览器需全量扫描每个DOM节点(含script、meta、注释等),无法复用继承值、干扰缓存,伪元素使匹配节点翻2–3倍,低端设备上耗时可暴涨至40ms+。

为什么*会让Recalculate Style时间飙升
浏览器匹配CSS选择器是从右往左的,而*没有索引、无法剪枝,必须逐个检查每个DOM节点是否匹配——包括<script>、<meta>、注释节点甚至<!-- -->。哪怕只写了一条* { box-sizing: border-box; },每次样式计算都要全量扫描。
- 无法复用继承值:比如
html { font-size: 16px; }本可自然向下继承,但* { font-size: 14px; }会强制重算每个节点 - 后续同级选择器也变慢:浏览器得先排除
*干扰,才能缓存其他规则的匹配结果 -
*::before和*::after更糟:一个真实元素 → 生成两个伪元素 → 实际匹配节点数翻2–3倍(500节点可能变成1500+)
低端设备上延迟为何被放大
低端Android或旧版iOS设备内存小、CPU单核弱,*强制全量扫描的开销会被显著放大。一个800节点的页面,在高端机上Recalculate Style耗时约8ms,到了低端机可能暴涨到40ms+,直接阻塞首屏渲染、导致滚动掉帧。
- Performance面板中
Recalculate Style占比常超35%,Layout阶段频繁触发 -
hover或focus状态切换明显滞后,不是JS卡顿,是样式重算跟不上 - Shadow DOM中
*还会跨封装边界触发额外检查,开销翻倍
*:not(.btn)这类写法更危险
看似“精准排除”,实则完全没跳过匹配过程:*:not(.btn)是先取全部再过滤;*[data-id]则是对每个节点都做属性存在性检查——两者都退化为字符串扫描,比纯*还慢20%+。
- 它们无法利用浏览器的类名哈希索引,每次都要遍历+比对
- DOM动态插入新节点时,这些规则会重新全量扫描
- 在SPA中,这类选择器常藏在第三方组件样式里,不易察觉但持续拖慢
真正有效的替代方式
不是“微调*”,而是彻底替换。重点覆盖你真实用到的、需重置的标签,跳过svg、canvas、iframe等非样式敏感元素。
立即学习“前端免费学习笔记(深入)”;
- 用显式列表:
html, body, div, p, h1, h2, h3, h4, h5, h6, ul, ol, li, a, button, input, textarea, form, img - 全局
box-sizing改用根元素继承:html { box-sizing: border-box; }+*::before, *::after { box-sizing: inherit; } - 现代项目可用
:where(html) { box-sizing: border-box; }降权且不增开销 - 避免在
@media内重复写这套列表,统一放在顶层CSS
实际替换时最容易被忽略的是:即使只在某个局部作用域写了form <em></em>,它仍会触发全量扫描——因为本身无索引,浏览器无法跳过非form子树。性能问题从来不会报错,但它会悄悄抬高LCP、拉长FCP、放大CLS。



















