bem 的 __ 和 -- 不能随便改,因为它们是语义契约:block__element 表示子节点归属,block--modifier 表示块的变体;混用下划线或中划线会破坏层级可读性、导致 js 选择器失效,并引发团队理解混乱。

为什么 BEM 的 __ 和 -- 不能随便改
BEM 的命名规则不是装饰,是语义契约:block__element 表示“属于这个块的子节点”,block--modifier 表示“块的某种变体”。一旦改成下划线或中划线混用(比如 block_element),CSS 选择器就失去层级可读性,JS 里用 querySelector 提取元素也会失效。
常见错误现象:.header__logo--large 写成 .header_logo-large,结果团队新人以为 _ 是分隔符、- 是修饰符,导致新写的 .header_menu--active 被误判为“menu 是块名”,实际它只是 header 下的 element。
- 所有 element 必须用双下划线
__,所有 modifier 必须用双中划线--,不接受配置或别名 - 禁止嵌套 BEM:不要写
header__logo__icon,应该拆成logo__icon或提升为独立 block - 如果用 PostCSS 或 Sass,可用
@bem插件自动校验,但别依赖它掩盖命名混乱
怎么给 React 组件加 BEM 类名才不破坏 JSX 可读性
直接拼接字符串(className={`btn btn--primary btn--${size}`})看着短,但一加 modifier 就容易漏空格、错顺序、难 debug。更糟的是,多人协作时有人用模板字面量,有人用数组 join,类名生成逻辑散落在各处。
使用场景:组件需要响应 props 变化动态切换 modifier,同时支持外部传入额外 class(比如 UI 库的 className prop)。
- 用
clsx(轻量,无副作用)而不是classnames(体积稍大):clsx('btn', 'btn--primary', { 'btn--small': size === 's' }, className) - 把 block 名抽成常量:
const BLOCK = 'button',然后写{BLOCK}__label,避免硬编码重复 - 不要在 JSX 里写
__或--拼接逻辑——放到自定义 Hook 或工具函数里,例如useBem(BLOCK, { size, disabled })
:is() 和 :where() 能简化 BEM 选择器吗
能,但只适合局部优化,不能替代 BEM 结构本身。比如你想统一重置所有 element 的 margin,写 .card :is(.card__header, .card__body, .card__footer) { margin: 0; } 看似简洁,实则埋雷:一旦 .card__header 被意外挪到卡片外,样式仍会生效,违背 BEM “作用域封闭” 原则。
性能影响:现代浏览器对 :is() 优化得不错,但旧版 Safari(≤15.4)不支持,且 Webpack + CSS Minifier 可能把它展开成冗长列表,反而增大 CSS 体积。
- 仅在 modifier 组合复杂时用
:is()替代重复前缀,例如.btn:is(:hover, :focus, :active) - 绝对不要用
:where(.block__elem)去“绕过”BEM 层级约束,那等于放弃模块边界 - 构建时若启用 CSS Scope(如 Vue SFC 的
scoped),BEM +:is()叠加可能触发未知优先级冲突,建议先测渲染结果
当设计稿里出现“同一个视觉模块在不同页面有细微差异”时,BEM 怎么应对
这是 BEM 最常被质疑的点,但答案很直白:不是用 modifier 硬扛,而是判断是否该拆成新 block。比如“首页 Banner”和“商品页 Banner”都叫 banner,但前者有动效+渐变标题,后者只有纯色+按钮,它们共享的只是视觉相似性,不是语义一致性。
容易踩的坑:为省事全塞进 banner--home / banner--product,结果 modifier 越来越多,最终 banner--home--with-cta--no-shadow--mobile-only 出现,丧失可维护性。
- 差异点 ≥ 3 处(结构、交互、响应行为任一不同),就该新建 block,比如
hero-banner和product-banner - 如果只是颜色/字体微调,用 CSS 自定义属性(
--banner-bg)配合 modifier 控制,而非新增 element - 共用样式抽到
_shared.css,但命名仍需带 block 前缀,例如.banner-shared-transition,避免污染全局
真正难的不是写对 BEM,是每次加新 class 前,停下来问一句:这个类名,三个月后别人看一眼就知道它属于哪个模块、能不能复用、删掉会不会影响其他地方——这才是 BEM 在 CSS 工程里没被取代的原因。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











