BEM通过.card__title等显式类名切断CSS对DOM结构的依赖,避免样式污染与定位漂移;禁止深层嵌套、伪类替代状态及跨块命名,强调类名即结构契约。

为什么直接写 .card .title 会让组件越来越难维护
因为样式污染和定位漂移:外部样式可能意外覆盖内部元素,而组件一旦被复用到不同上下文(比如嵌套在 .modal 或 .sidebar 里),.card .title 就可能匹配到非本意的节点。BEM 的核心不是“多写类名”,而是切断 CSS 选择器对 DOM 结构的依赖。
-
.card__title永远只属于card块,不靠父级存在,也不因 HTML 加一层div就失效 - 禁止三层及以上嵌套类名(如
card__content__title),那说明结构已超限,该拆成新组件 - 所有子元素必须是
card的直接子节点——card__header、card__body、card__footer平级并列,不嵌套
card__title--hovered 和 :hover 选哪个
BEM 不排斥伪类,但禁止用 :hover 替代语义类名。比如不能靠 .card:hover .card__title 控制悬停变色,而应提前定义 card__title--hovered 并由 JS 切换。
-
:hover在 SSR 场景下不可预判,服务端渲染时样式缺失 - CSS 无法在伪类中触发 transition 的 class 切换,容易卡顿
- 可访问性工具(如屏幕阅读器)通常不识别伪类状态,而
card__title--focused可配合tabindex显式管理 - 性能上,
:has()或大量:not()会拖慢重排,BEM 扁平类名天然规避这类问题
遇到第三方组件(比如 Ant Design 的 .ant-modal)怎么套 BEM
直接覆盖原 class 是自找麻烦。BEM 的解法是「隔离作用域」:用一个 BEM 块名包裹第三方组件,所有样式通过该块向下穿透控制,不碰原 class。
- 例如:
<div class="my-modal"><div class="ant-modal">…</div></div>,然后写.my-modal .ant-modal或更稳妥的.my-modal > .ant-modal - 避免在
.ant-modal上加my-modal__overlay这类跨块命名——它违反 BEM 的边界契约 - 如果需要定制弹窗遮罩层级,用 CSS 自定义属性绑定语义:
.my-modal { z-index: var(--z-dialog); },而非硬写z-index: 9999
修饰符能不能叠加?button--primary button--large 还是 button--primary--large
必须用 button--primary button--large,禁止 button--primary--large 这种复合修饰符。
立即学习“前端免费学习笔记(深入)”;
-
button--primary和button--large是正交变体,可自由组合,CSS 规则也应独立声明(.button--primary { … }+.button--large { … }) -
button--primary--large会导致规则耦合,改尺寸逻辑时不得不动主题色逻辑 - 布尔状态建议用
is-前缀,如is-loading,不与--修饰符混用,避免歧义 - modifier 只能作用于 block 或其直属 element,禁止写
button__text--large——字体大小是按钮整体的视觉变体,不是文字自身的状态
__ 和 -- 背后的结构契约是否还成立。BEM 是协议,不是装饰。


















