改个.title会连带崩购物车和弹窗,是因为传统写法如.user-card .title将样式绑定在dom层级上,结构一变即失效,还易意外匹配其他模块的.title;bem强制用.user-card__title,类名自带语义作用域,不依赖html结构或标签类型。

为什么改个 .title 会连带崩掉购物车和弹窗
因为传统写法如 .user-card .title 或 .header h3 把样式生效条件藏在 HTML 层级里。DOM 结构一动(比如把 <h3></h3> 换成 <div role="heading">),样式就静默失效;更糟的是,它可能意外匹配到另一个模块的 <code>.title,导致改 A 却崩 B。BEM 强制写成 .user-card__title,类名自带作用域——不关心嵌多深、用什么标签,只认这个字符串。
.btn--primary 和 .btn-primary 的区别不只是下划线
前者是合规 BEM:块名 btn + 修饰符 --primary,语义明确、可组合、可预测;后者是传统命名,btn-primary 在大型项目中极易与 .modal-primary、.form-primary 冲突,且无法通过工具校验是否属于同一 Block。常见错误包括:
- 漏写 Block 前缀:
className={isFeatured ? 'featured' : ''}→ 应为product-card--featured - 连字符写错:
card__title--large(非法)→ 正确是card__title--large(注意双中划线只用于 modifier) - 大小写混用:
Card__header和card__header在 Linux 构建环境视为不同类名,样式丢失且无报错
stylelint 不配 stylelint-selector-bem-pattern 等于没用
默认的 stylelint 对 BEM 几乎零约束。.btn-primary、.modal-close-btn 全部畅通无阻。必须手动启用插件并严格配置:
-
selector-bem-pattern设为{ "componentName": "[a-z][a-zA-Z0-9]+", "styleType": "bem" } -
ignoreSelectors加上["/^\..+:(hover|focus|active|disabled)/"],避免误报伪类 - 禁用
fix: true—— 语义纠错没法靠机器做,自动修复反而可能生成.card__content__title这种非法嵌套
CI 流程里必须跑 stylelint --config .stylelintrc.js src/**/*.css,不通过就阻断合并。
JS 动态拼接类名时最容易漏掉的三个点
React/Vue 中不是逻辑写错才出问题,而是拼写和结构断裂:
- 漏写 Block 前缀:
className={isFeatured ? 'featured' : ''}→ 应为product-card--featured - 连字符写错:
card__title--large(非法)→ 正确是card__title--large(注意双中划线只用于 modifier) - 大小写混用:
Card__header和card__header在 Linux 构建环境视为不同类名,样式丢失且无报错
建议统一用 clsx 或封装 bem('card', { featured: isFeatured }) 工厂函数,别手写模板字符串。最常被忽略的是:BEM 不解决加载顺序问题。如果 .card__title--small 和 .card__title--large 冲突,不是命名错了,而是 CSS 文件引入顺序或层叠权重没管住——BEM 只管名字,不管谁覆盖谁。











