.class 选择器性能优于 div.class,因其作为关键选择器直接索引 class 列表,而 div.class 需回溯匹配且增加无效过滤;id 最快但复用性差,.class 是日常开发的性能与维护平衡点。

浏览器从右往左解析选择器,.class 直接命中目标元素
关键不是“类比标签高级”,而是匹配路径更短。浏览器把 .class 的 .class 部分当作 key selector(目标选择器),直接查所有带该 class 的元素;而 div 要扫描全部 <div> 标签——哪怕页面里有 5000 个 <code><div>,它就得逐个比对 class 属性是否匹配。实际测试中,DOM 节点超 1000 时,<code>div.foo 比 .foo 慢 3–8 倍。
div.class 不是“更精确”,是额外增加一层无效过滤
很多人误以为加标签前缀能提高准确性,其实它只在极少数场景有用(比如同一 class 名被用在不同语义标签上,且样式必须差异化)。但代价是:浏览器先收集所有 .class 元素,再逐个向上检查父节点是否为 div——这叫“回溯匹配”,开销远高于直接索引 class 列表。
- 除非你明确需要区分
<span class="btn"></span>和<button class="btn"></button>的样式,否则不要写button.btn - 框架组件(如 Vue 的
<mybutton></mybutton>)生成的 class 天然唯一,加标签前缀纯属冗余 - 用
data-role="button"替代button.btn,既能语义化,又避免标签依赖
嵌套层级和属性选择器会放大性能差距
一旦混用,问题会指数级恶化。比如 section .list > ul li.active,浏览器要先找所有 li.active,再往上确认是否在 ul 下、是否在 .list 内、是否被 section 包裹——每层都触发祖先遍历。而 .list-item-active 一步到位。
-
[data-id]、[href^="https://"]这类属性选择器无法被索引,每次都要字符串比对,比.class慢一个数量级 -
:nth-child()在 DOM 动态增删后强制全量重算,.odd/.even类由 JS 控制更稳定 - 在
will-change: transform区域内,任何伪类或复杂选择器都可能打断图层合成
ID 选择器最快,但类选择器才是日常开发的性能平衡点
#main 确实最快——浏览器内部做了哈希查找优化。但 ID 唯一性限制太强,不适合复用场景;而 .class 在速度、复用性、维护性上综合最优。真正拖慢渲染的,从来不是单个 .class,而是成百上千个 div > p > span.highlight 这类写法堆积在全局 CSS 里。
最容易被忽略的是:选择器性能问题往往在首屏不可见区域(比如折叠菜单、虚拟滚动区)悄悄积累,等用户交互触发重排时才集中爆发。别等卡顿了再查,从第一个 div.card 就该换成 .card。











