BEM 的 block__element--modifier 不能写成 block-element-modifier,因会破坏语义分层、混淆工具链识别、引发样式优先级与命名冲突问题。

为什么 BEM 的 block__element--modifier 不能写成 block-element-modifier
因为 CSS 选择器解析和样式优先级会出问题,而且破坏了 BEM 的语义分层。连字符写法让 __ 和 -- 的边界彻底消失,工具链(比如 PostCSS 插件、BEM 工具)也认不出结构。
-
__是固定层级标识,表示“属于某个 block 的子元素”,浏览器不关心,但人和工具靠它定位作用域 -
--必须紧贴在__element后面,否则button--primary会被误判为独立 block,而不是button__text--primary这类合法变体 - 用连字符替代双下划线后,
header-logo-dark无法区分是header__logo--dark还是header-logo这个新 block,团队协作时命名冲突概率翻倍
如何给 React 组件的根节点自动注入 BEM class 名
别手写 className="button button--large button__icon",容易漏、难维护。核心是把 BEM 逻辑封装进一个函数或 Hook,让组件只管传参。
- 用
clsx+ 纯函数最轻量:const bem = (block) => (element, modifier) => { if (element) return `${block}__${element}${modifier ? `--${modifier}` : ''}`; return `${block}${modifier ? `--${modifier}` : ''}`; }; // 使用:bem('button')('icon', 'loading') - React 中更推荐用自定义 Hook 封装状态感知逻辑,比如:
useBem('button', { size: 'large', loading: true })返回完整 class 字符串 - 注意:不要在
render里动态拼接字符串,避免每次渲染都新建字符串对象;缓存bem('button')函数实例比缓存结果更可靠
第三方组件库(如 Ant Design)怎么和 BEM 共存
不能强行改它的 class 名,也不该用 !important 覆盖。关键是分清「谁负责样式」——你写的组件用 BEM,它提供的组件只当黑盒用,通过 wrapper 层隔离。
- 给
<antdbutton></antdbutton>包一层<div class="my-button">,所有 BEM 修饰都在 wrapper 上,内部原样透传<li>如果必须定制内部结构(比如改 Icon 颜色),用 CSS-in-JS 或 <code>:where(.my-button) .ant-btn-icon这类低权重选择器,避免污染全局 - 警惕
css-modules和 BEM 混用:模块化生成的哈希名会让 BEM 的可读性归零,要么全用 BEM + 普通 CSS,要么全用 css-modules,别交叉 - 用
stylelint-bem-stylistic可以校验命名格式,但更关键的是用postcss-bem-linter扫描 HTML/JSX 中的 class 是否匹配声明的 block 列表 - CI 流程里加这步,能拦住
modal__footer写成modal-footer这类低级错误,省得上线后查半天 DOM 结构 - 注意:正则提取 class 名时,要排除内联
style、data-*属性、注释里的伪 class,否则误报率高
build 时提取 BEM class 名做静态检查是否必要
有必要,但不是为了“防止写错”,而是为了提前发现结构断裂点,比如某处写了 card__title 却没定义 card 这个 block。
立即学习“前端免费学习笔记(深入)”;
BEM 不是套个命名就完事,真正卡住人的永远是 block 边界的模糊——一个组件到底算独立 block,还是别人家的 element?这个判断没文档、没约定、只靠人盯,时间一长就散了。


















