id选择器权重固定为100,远高于类选择器(10),导致多个类组合(如.btn.primary.large.active,权重40)仍无法覆盖单个id规则;应将id仅用于js锚点和语义标识,样式全部交由bem类名控制,禁用id参与css匹配。

为什么ID选择器权重高到没法覆盖
ID选择器权重固定为 100,而一个类选择器只有 10。这意味着哪怕你写 .btn.primary.large.active(4个类,总权重 40),也压不过单个 #header。浏览器不看“写了多少个class”,只算权重数字——100 就是天然卡在那儿的门槛。
常见错误现象:
- 改了
.modal__close的颜色,但没生效,DevTools 里看到被#user-modal .modal__close覆盖(权重110) - 想给按钮加
loading状态,结果.btn--loading被父级#sidebar-nav .btn锁死,只能加!important - 第三方组件(比如
el-dialog)内部用了#dialog-root,你的全局.dialog__content直接失效
怎样把ID从CSS里彻底移出去
ID该留在HTML里,但不该出现在CSS文件中。这不是删代码,而是重定向职责:ID归JS和语义用,样式全交给类驱动。
- 把原CSS中所有
#main、#nav这类规则,全部替换成带BEM前缀的类,比如.layout__main、.nav__container - HTML中对应元素,显式加上这个类:
<div id="main" class="layout__main"> —— ID和class共存,但CSS只认后者 <li>JS里定位不再用 <code>document.getElementById('main'),改用document.querySelector('.layout__main');现代框架(Vue/React)中直接用 ref 或useRef,更干净 - 如果必须保留锚点跳转(如
<a href="#section2"></a>),确保目标元素同时有id="section2"和class="section section--2",CSS只对.section--2生效 - 禁用
.card .card__title:这是两个独立类选择器叠加,权重20;正确写法只有.card__title单独一条规则 - 别用标签限定:
h3.card__title权重是11(标签1+ 类10),而纯.card__title是10;BEM约定样式绑定类名,不依赖标签类型 - 修饰符不叠用:
.button--primary.button--large权重20,应合并为.button--primary--large,或拆成独立状态规则(.button--primary+.button--large) - 避免用
:where()包裹多个类来“降权”——它确实权重为0,但仅适合归一化基础样式(如:where(.header__logo, .footer__logo)),不能用于状态类或业务逻辑类 - 服务端渲染(SSR)中需要首屏可访问的锚点,比如
<main id="main-content"></main>,此时CSS里绝不能出现#main-content,只写.main-content或.layout__main - Web Components 或 Shadow DOM 外部通信时,用ID做唯一标识比类更稳妥,但样式仍走
:host或part属性,不碰ID - 无障碍(a11y)要求的
aria-labelledby、for属性值必须是ID,但这些ID只参与ARIA逻辑,不参与样式匹配 - 最易忽略的一点:某些构建工具(如Vite + CSS Modules)会自动加属性选择器(如
[data-v-abc123]),这其实悄悄把类权重抬高了一档(+10),所以它们常能“压过”全局ID规则——但这不是靠ID赢了,是靠类被增强了
类选择器怎么写才不会悄悄拉高权重
BEM本身不保权重低,关键是你怎么组合。很多“看起来合理”的写法,实际把权重翻倍了。
哪些场景真需要ID,又怎么避开权重干扰
ID不是敌人,只是用错了地方。它在JS操作和语义锚点上依然不可替代,但必须和CSS解耦。











