选择器重置样式易出事,因性能开销大且造成继承污染,导致表单控件变形、图标错位;推荐用 all: unset 或 :where() 优化,但需注意兼容性与适用场景。

为什么 * 选择器在重置样式时容易出事
它确实能一次性选中所有元素,但代价是极高的性能开销和不可控的继承污染。浏览器必须为每个 DOM 节点都匹配一次,尤其在深层嵌套或大量动态插入的场景下,* 会显著拖慢渲染速度。更麻烦的是,它会把 box-sizing、margin、padding 这类属性强加给所有元素——包括 <input>、<button></button>、<svg></svg> 等原生有默认样式的控件,结果往往是表单控件变形、图标错位、第三方组件样式崩坏。
常见错误现象:* { margin: 0; padding: 0; } 写完后,<textarea></textarea> 高度异常、<select></select> 下拉箭头消失、emoji 显示被截断。
- 只在极简原型或完全可控的私有组件库中才考虑用
*做初始归一 - 生产环境优先用
*::before, *::after分离伪元素重置,避免影响真实节点 - 若真要重置,改用
html或body作为根容器做继承控制,比通配更安全
替代 * 的现代重置方案:用 all: unset 更精准
all: unset 不是重置“所有元素”,而是重置“当前元素自身所有可继承/非继承属性”——它不递归影响子元素,也不会触发全局匹配开销。这是目前最接近“干净初始化”的 CSS 原语。
使用场景:封装原子级 UI 组件(如自定义 tooltip、badge),需要彻底剥离宿主环境样式干扰。
立即学习“前端免费学习笔记(深入)”;
-
all: unset会清空display,记得手动设回display: inline或block - 它不重置
direction和unicode-bidi,多语言项目需额外处理 - IE 完全不支持,
all: revert兼容性更差,别在兼容旧浏览器时碰
* 和 :where(*) 性能差多少?
:where(*) 看似只是语法糖,但它把选择器权重降为 0,且现代浏览器对 :where() 内部的通配匹配做了优化——跳过部分计算阶段。实测在 5000+ 节点的页面中,:where(*) 的首次渲染耗时比纯 * 低约 35%。
但注意:它只是“看起来像 *”,实际行为不同。例如 :where(*) { color: red; } 会被后续同权重规则轻易覆盖,而 * { color: red; } 因为权重为 0-0-0-1,反而更难被覆盖。
- 别用
:where(*)替代重置逻辑,它的设计目标是“降权覆盖”,不是“初始化” - 仅当你要写一条“无论如何都不该生效”的兜底样式时,
:where(*)才有意义 - Vite / Webpack 构建时,
:where()会被 PostCSS 插件转译,检查你的构建链是否启用postcss-preset-env
真正该初始化的从来不是“所有元素”,而是特定上下文
比如一个卡片组件内部,你不需要重置整个页面,只需要确保 .card > * 的 margin 归零;又比如富文本编辑器输出区域,应锁定为 .editor-content :is(p, h1, h2, ul, ol) { margin-block: 1em; },而不是靠 * 硬扫。
复杂点在于:CSS 没有“作用域内全部重置”的原语。你得靠 BEM 命名、:scope(仍属实验)、或 JS 动态注入 scoped style 来逼近这个目标。而最容易被忽略的,是字体堆栈、行高、颜色这些隐式继承属性——它们不会被 * 触发重置,却恰恰是跨组件样式不一致的根源。








