直接写 btn-primary 会引发样式泄漏,因其未声明归属关系、语义模糊,易被不同上下文复用导致冲突;bem 要求明确归属,如 buttontext--primary 或 cardbutton--primary,通过 __ 和 -- 强制绑定 block,杜绝孤立类名与泛义修饰符。

为什么直接写 btn-primary 会引发样式泄漏
因为 btn-primary 没有声明归属关系,它看起来像一个独立类,但实际语义模糊:是所有按钮的“主要样式”?还是某个特定按钮组件的变体?一旦其他地方也用 btn-primary(比如侧边栏的 sidebar-btn),两个不同上下文的样式就可能互相覆盖。
真正起作用的是明确归属:button__text--primary 表明这是 button 这个 block 下的 text 元素,且处于 primary 状态;card__button--primary 则属于 card 组件——哪怕都叫 “primary”,也不会冲突。
- 所有元素类名必须带
__明确挂靠到某个 block,禁止孤立使用__text或text - 修饰符不能脱离主体存在,
button--large合法,large单独用就是错的 - 避免用
primary这类泛义词单独作 modifier,优先用描述性状态,如button--submit、button--loading
如何把模糊的“标题”“内容”翻译成 BEM 类名
“标题”不是通用概念,而是某个 block 的一部分。比如卡片里的标题,应写作 card__title;文章页的标题,应是 article__header;导航里的标题,则是 nav__label。关键不是词义,而是它“属于谁”。
常见错误是把结构当语义:div class="title" 看起来清晰,但无法回答“这个 title 是哪个模块的?”——BEM 要求答案必须写进类名里。
- 先确认 block:是
card?form?modal?命名必须小写+短横线,如user-profile - 再定义 element:用
__连接,如user-profile__avatar、user-profile__name - 不强行统一“title”“content”这类词,允许同一语义在不同 block 中重复出现:
card__content和faq__content是两个完全隔离的样式域
React 中动态拼接 BEM 类名容易踩哪些坑
JSX 里写 className={`card__header ${isSticky ? 'card__header--sticky' : ''}`} 看似可行,但维护成本高、易拼错、难 lint。更危险的是用模板字符串生成嵌套结构:`${block}__${elem}--${mod}` —— 一旦 elem 值含空格或特殊字符,类名就失效。
推荐用 clsx 声明式组合,而不是运行时拼接:
className={clsx('card__header', {
'card__header--sticky': isSticky,
'card__header--compact': isCompact
})}
- 所有 BEM 全称必须硬编码,不从 props 动态构造
__或--部分 - 避免在组件内定义中间变量,如
const headerClass = 'card__header',这会让 DevTools 里看不到完整语义 - 如果用了 CSS Modules,确保
:local(.card__header)和 JSX 中写的字符串完全一致,否则哈希化后类名失配
为什么 __ 和 -- 不能替换成 _ 或 -
这不是风格偏好,而是工具链契约。stylelint-selector-bem-pattern、VS Code 的 BEM 插件、Webpack 的 CSS 提取逻辑,全都依赖正则 /__[a-z]/ 和 /--[a-z]/ 来识别结构。改成 _item 或 -large,这些工具就无法判断哪个是 element、哪个是 modifier。
更隐蔽的问题是样式泄漏:.card-header--large(单下划线)会被误认为是普通 class,可能被全局 reset 规则意外覆盖;而 .card__header--large 因为双下划线+双短横的唯一性,几乎不会被外部样式干扰。
- 所有
__前后不能有空格,card__header合法,card __header直接失效 - 不允许嵌套 modifier:
card__header--large--dark是错的,应拆成两个独立类:card__header--large card__header--dark - 构建工具如 cssnano 在启用
reduceIds时,可能把超长 BEM 名误判为可压缩项,需在配置中排除__和--模式
<h2></h2> 就写 h2 类,却忘了它实际是 product-card__title。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











