通配选择器 在 Less 中原样透传至 CSS,不被优化,导致浏览器遍历全部 DOM 节点匹配,显著拖慢样式计算;应改用显式类名、BEM、:where() 或限定子代选择器(如 > )替代。

通配选择器 * 在编译后仍原样保留,无法被Less优化
Less 不会对 * 做任何简化或剥离——它只是原封不动地透传到输出 CSS 中。这意味着你写 * {}、body * {} 或 .wrapper * {},最终生成的 CSS 里就是一模一样的选择器,浏览器必须照单全收。
浏览器匹配 * 的代价极高:它得遍历整个 DOM 树,对每个节点都执行一次样式计算,哪怕该节点根本不需要这个规则。尤其在长列表、动态渲染内容(如聊天消息流)或频繁 reflow 的页面中,Recalculate Style 时间会明显跳升。
常见错误现象:
- 用
* { box-sizing: border-box; }开头,本意是重置,结果拖慢首屏渲染 - 在混入里默认加
*::before, *::after { content: "" },导致所有伪元素都被强制创建 -
.modal * { pointer-events: none; }这类写法,实际只需作用于几个子元素,却让浏览器检查 modal 下全部子孙
空格 + * 构成最危险的后代通配组合
Less 里一个空格就决定语义:.card * 和 .card > * 看似只差一个 >,但性能差距极大。
.card * 是“后代通配”,浏览器先找所有 *(即全部节点),再逐个向上查祖先是否含 .card;而 .card > * 是“子代通配”,只检查 .card 的直接子节点,范围小得多。
实测显示,在含 2000+ 节点的 DOM 中,.list * 的样式匹配耗时比 .list > * 高出 3.2 倍。更糟的是,这类选择器常被误塞进媒体查询或动画关键帧里,触发高频重计算。
使用场景中容易踩坑:
- 写响应式重置时误用
@media (max-width: 768px) { .nav * { font-size: 14px; } } - 封装“清空所有内边距”的混入:
.reset-padding() { * { padding: 0; } } - 想统一设置文字颜色,却写成
.theme-dark { * { color: #fff; } }
替代方案:用显式类名 + BEM 约束作用域
通配选择器不是不能用,而是绝大多数时候有更轻、更可控的替代方式。
优先考虑这些做法:
- 用
inherit或unset替代全局重置:.card__title { color: inherit; } - 把“影响所有子元素”的逻辑,下沉为组件级约定,比如定义
.card__content并统一设box-sizing - 需要穿透嵌套结构时,用
:is()或:where()(现代浏览器支持),例如.card :where(p, ul, ol) { margin-bottom: 1rem; },权重更低且不触发全量扫描 - 真要兜底重置,限定在极小范围:
.btn > * { margin: 0; }比.btn *安全得多
Less 编译器不会警告你用了 *,也不会自动降权——它信任你写的每一条规则。所以检查源码时,可以用 grep -r "\*\s*{" src/ 快速定位所有通配规则,再逐条评估是否真有必要。
inset 阴影 + 通配选择器 = 滚动卡顿放大器
单独用 box-shadow: inset 已经比普通阴影开销高,若再配合 *,问题会指数级恶化。
原因很直接:inset 阴影强制浏览器对目标元素做层叠上下文重建和局部重绘,而 * {} 让这个动作施加到成百上千个节点上。在 iOS Safari 或低端安卓 WebView 中,快速滚动时会出现明显掉帧,DevTools 的 Rendering 面板里能看到大量 “Paint” 和 “Composite Layers” 尖峰。
典型错误写法:
.dialog * { box-shadow: inset 0 0 8px rgba(0,0,0,0.1); }- 混入里默认启用:
.shadow-inset(@blur: 4px) { * { box-shadow: inset 0 0 @blur rgba(0,0,0,0.1); } }
正确做法是:只给明确需要的容器加,比如 .dialog__body,并用变量控制模糊值上限:@shadow-inset-blur: 2px;。混入注释里必须写明:“此样式禁用于列表项”。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











