bem不是为加长类名防冲突,而是用block__element--modifier将归属、层级、状态硬编码进名字;双下划线和双横线是工具链识别的语法锚点,写成card-title会被lint忽略、构建漏提、协作失焦,破坏结构契约。

直接说结论:BEM 不是用来“加长类名防冲突”的,而是用 block__element--modifier 把归属、层级、状态三件事硬编码进名字里——写错一个下划线,就等于破坏整个结构契约。
为什么 card__title 不能写成 card-title?
这不是风格之争,是工具链识别失败的起点。card-title 在 stylelint-selector-bem-pattern 规则下直接报错,VS Code 插件无法高亮 __ 结构,CI 构建时提取样式逻辑也会漏掉它。双下划线 __ 和双横线 -- 是 BEM 的语法锚点,不是装饰。
-
card-title→ 被识别为普通类名,lint 不校验,构建不提取,协作时没人知道它属于哪个组件 -
card__title→ 工具链能反推 block 是card,元素是title,修改时自然联想到card.module.css - 错误写法:
.card .title(后代选择器)、card-header(缺__,被当新 block)、card__title--large(修饰符挂错位置,应是card--large或card__title--highlighted)
React + CSS Modules 下,styles['card__body'] 为什么是 undefined?
90% 是文件名、类名、JSX 访问键三者没对齐。CSS Modules 的哈希前缀由文件名决定,不是类名决定。
- 文件必须叫
Card.module.css(PascalCase,与组件名一致),不能是card.module.css或MyCard.module.css - CSS 文件里必须写
.card__body { },不能写.card-body { }或.body { } - JSX 中必须用字符串访问:
styles['card__body'],不能写styles.card__body(语法错误)或styles['Card__body'](大小写不匹配) - 调试建议:配置
localIdentName=[name]__[local]___[hash:base64:5],编译后类名带原始名,一眼可查来源
什么时候该把图标单独抽成 ui-icon,而不是写 btn__icon?
看复用范围。只要图标出现在两个及以上不相关的上下文(比如按钮、表单项、弹窗标题),它就不再是“按钮的图标”,而是“项目的图标组件”。
- ✅ 合理:
ui-icon+ui-icon--success+ui-icon--lg,颜色尺寸全走 CSS 变量 - ❌ 错误:
btn__icon+card__icon+form__icon—— 三套实现,换主题要改三次,加新尺寸要补三处 - 注意:
ui-icon必须显式设font-size,子 SVG 用fill="currentColor",否则继承放大、颜色丢失 - 禁止:
ui-icon--red(视觉描述)、ui-icon--16px(像素值),改用ui-icon--critical或ui-icon--sm
SCSS 嵌套写法怎么不破坏 BEM 封装性?
允许用 &__element 和 &--modifier,但一旦出现空格或标签选择器,就等于悄悄绕开 BEM 约束。
- ✅ 安全:
.card { &__header { padding: 1rem; } &--fluid { width: 100%; } }→ 编译后仍是.card__header和.card--fluid - ❌ 危险:
.card { &__content { p { color: #333; } } }→ 编译出.card__content p,违反“只用类名”原则,且无法反推 DOM 结构 - 伪类别写
&:hover,改用&--hover配合 JS 切换,否则键盘焦点、暗色模式等场景失效 - 禁止
.card__footer__copyright:BEM 不支持三级嵌套,应拆成.card__footer+ 新 block.copyright
BEM 最容易被忽略的点不在命名格式,而在 block 边界的判断——不是所有容器都该是 block,也不是所有子元素都该挂靠父 block;一旦边界模糊,后续所有 __ 和 -- 都会变成无意义的字符串拼接。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











