必须删掉.card .card__title,因为它违反bem单类名生效原则:权重升高导致覆盖困难,且样式强耦合dom结构;正确写法是独立使用.card__title,所有bem类选择器须扁平、无空格、不嵌套。

为什么 .card .card__title 这种写法必须删掉
它看起来“更安全”,实则破坏BEM核心契约:所有样式必须只靠单个类名生效。.card .card__title权重变成 0,2,0,比.card__title高一倍,后续加.card__title--large就盖不住;更关键的是,它把样式绑死在 DOM 结构上——万一哪天.card__title被包进一个<div class="wrapper">里,规则直接失效。
<ul>
<li>所有 BEM 类选择器必须独立使用:<code>.card、.card__title、.card--featured 各自一条规则,不拼接、不嵌套
.card__header .card__logo 是错的,应拆成 .card__header 和 .card__logo 两个平级类[data-theme="dark"] .card__title,而非依赖父类名嵌套超过 3 层时,Less/Sass 里该停手了
Less 的 &__item 嵌套本身没问题,但一旦出现 .modal { .overlay { .content { .header { h1 {} } } } },说明结构已失控。编译后生成的选择器像 .modal .overlay .content .header h1,权重飙升,且 DevTools 里根本找不到源码对应位置。
- 嵌套只用于收口同 Block 下的 BEM 变体,如
.btn { &--primary { &:hover {} } }→ 输出.btn--primary和.btn--primary:hover - Element 之间不嵌套:
.card { .card__title { .card__title-icon {} } }错,应写成.card__title-icon平级类,或提取为新 Block.icon - 媒体查询一律提级写:
@media (max-width: 768px) { .card__title { font-size: 1rem; } },别塞进嵌套块里
遇到第三方组件库时,怎么避免被迫加深层级
Ant Design 的 .ant-btn 自带 !important 或深层嵌套,很多人第一反应是写 .my-form .ant-btn 去覆盖——这等于主动加一层,还让样式依赖外部类名。
- 用容器隔离:
<div class="my-form__submit-wrapper"><button></button></div>,再写.my-form__submit-wrapper .ant-btn—— 至少把影响范围锁死在 Block 内 - 不直接覆盖第三方类名,优先改其 wrapper 的 BEM 类,例如
.my-form__submit-wrapper--loading控制整体状态 - 如果对方真用了
!important,你只能也用,但必须带完整 BEM 路径:.my-form__submit-wrapper .ant-btn--override,而不是.ant-btn
工具链怎么帮你守住扁平底线
人会疏忽,但工具不会。光靠约定很难长期坚持,尤其多人协作时。
- 用
postcss-bem-linter检查类名格式,报错.card-header-title(缺双下划线)或.btn_primary(单下划线) - 配置
stylelint-selector-bem-pattern拦截 CSS 中出现的.card .card__title类选择器组合 - CI 流程里加入
lessc --lint检测嵌套深度,超 3 层自动失败
真正容易被忽略的点是:BEM 的扁平化不是为了“写得短”,而是为了让每个类名都具备可移植性——今天复制到弹窗里能用,明天抽成独立组件也不用改一行 CSS。











