全局选择器 * 会严重拖慢渲染性能,应避免使用;局部样式需依赖构建时方案(如 scoped 或 CSS Modules)而非命名约定,伪类和属性选择器在局部作用域中易失效,禁用 !important 解决冲突。
* 的实际影响远比看起来严重用 * 重置样式看似省事,但会强制浏览器对每个 DOM 节点都做一次匹配计算,哪怕节点没有样式规则要应用。现代页面动辄上千节点,* 会显著拖慢首次渲染和后续重排。
常见错误写法:
* { margin: 0; padding: 0; box-sizing: border-box; }这种写法在大型项目中已成性能隐患。
body、h1~h6、p、ul、ol
html 或 body 作为根选择器批量控制继承属性(如 font-family、line-height),比 * 高效得多reset.css 类库中经过测试的精简版本,而非手写 *
:scope 和 CSS Modules 实现,不是靠“加前缀”很多人以为给类名加项目前缀(如 myapp-button)就算局部化,其实这只是命名约定,无法阻止样式泄漏。真局部化需依赖机制而非命名。
:scope 在 querySelector 中有效,但在纯 CSS 里不触发作用域隔离;真正起效的是构建时方案:
scoped(Vue)或 css-modules(React),它们会在编译后自动为选择器添加哈希后缀,并为对应 DOM 插入 data-v-xxx 属性@layer + @import 显式划分样式层级,避免意外覆盖,例如 @layer base { h1 { font-size: 2rem; } }div p 这类宽泛选择器,它会穿透作用域捕获父级或兄弟节点中的 p
像 :hover、:focus-within、[data-status="active"] 这些选择器本身没问题,但一旦嵌套在局部作用域中(如 Vue scoped style),构建工具可能无法正确重写属性选择器中的属性名,导致匹配失败。
[data-status] 类选择器会被自动加上 scope 属性,但
[data-status="active"] 中的值不会被转义,必须确保 HTML 中的属性值完全一致button--active),避免依赖属性选择器:is() 和 :where() 在局部作用域中可安全使用,但注意 :where() 会清空选择器权重,可能破坏预期优先级!important 解决全局 vs 局部冲突当局部样式被全局规则覆盖(比如第三方 UI 库的 .btn 定义了 !important),第一反应不是加更多 !important,而是检查作用域边界是否被打破。
是否漏写了 scoped,React 是否正确导入了 xxx.module.css
style-loader 插入顺序错乱).my-component .my-button 替代 .my-button,而不是加 !important
局部样式本意是降低耦合,一旦开始堆 !important,就等于主动放弃隔离能力。