header压垮.theme-dark .nav-link是因为ID选择器权重(0,1,0,0)高位b=1远超类选择器(0,0,2,0)的b=0,四元组比较时第二位已决出胜负,后续位不再参与比较。

为什么#header会压垮.theme-dark .nav-link
浏览器不是在“加权重”,而是在比四元组 (a,b,c,d):ID 数量是第二位,只要有一个 #id,b=1,而任何纯类选择器的 b=0。比较时第一位(行内样式)相等就直接看第二位,1 > 0,后面根本不会读——所以十个类也赢不了一个 ID。
常见错误现象:
-
.nav-link--active写了但没生效,DevTools 里显示被划掉,点开发现是#header .nav-link在压制 - 加暗色模式时被迫写
.theme-dark #header .nav-link,权重升到(0,1,1,0),下个需求只能继续堆 - 第三方 UI 库(如 Ant Design 的
#layout)悄悄注入 ID 规则,你完全没意识到
重复 id="modal" 会让 React/Vue 直接失效
ID 必须全局唯一,但组件化场景下,<modal></modal> 可能被渲染 3 次。结果是:
- CSS 只作用于第一个
modal,后两个弹窗样式丢失 -
document.getElementById('modal')永远只返回第一个,JS 逻辑中断 - 服务端渲染(SSR)时 hydration 失败,控制台报
Hydration failed - E2E 测试用
getElementById查元素,在 CI 环境因 DOM 动态变化而随机失败
想覆盖 ID 样式,堆类名是无效的
.btn.btn-primary.btn-lg 权重仍是 (0,0,3,0),而 #submit 是 (0,1,0,0),高位已败。真正可用的路只有几条:
立即学习“前端免费学习笔记(深入)”;
- 改用属性选择器:
[data-action="submit"],权重同级类,无唯一性限制 - 组合 ID + 类:
#submit.btn,既明确作用域又保留复用能力 - 删掉 ID,用 BEM 类名:
button--primary,CSS 只认 class,彻底规避权重博弈 - 保留 ID 仅用于必要语义场景:
<label for="email"></label>对应<input id="email">,或锚点跳转<h2 id="section-3"></h2>
重构旧项目时最常漏掉的检查项
别只盯着自己写的 CSS 文件。运行这三行命令快速扫雷:
document.querySelectorAll('[id]').lengthdocument.querySelectorAll('#app, #root, #layout')getComputedStyle(document.body).getPropertyValue('--some-var')容易踩的坑:
- SSR 模板里埋了
id="main",构建时没暴露给前端工程师 - reset.css 或 normalize.css 里没动过,但其实含
#root * { box-sizing: border-box } - Vue 的
v-if或 React 的条件渲染导致某些 ID 在部分路由下不存在,getElementById返回 null 却没做容错
ID 的破坏力不在它多难写,而在它无声无息地卡住后续所有样式演进和组件复用——尤其当团队里没人记得那个 #sidebar 是谁加的、为什么不能删的时候。


















