BEM未过时,但需工程化约束而非仅套命名格式;其价值在于成为团队最小共识接口,依赖目录结构、lint校验、CI扫描与PR检查等协同保障,否则形同虚设。

为什么直接写 .button__icon--large 反而会埋雷
很多人以为照着 BEM 规则写类名就等于落地了规范,结果三个月后出现 .button__icon--large--disabled--hovered 这种嵌套修饰符,说明命名逻辑已经失控。这不是 BEM 的问题,而是缺少配套约束:
- Modifier 值必须原子化且可枚举:
--size-small合法,--size-14px违规 - 禁止用 Modifier 表达响应式断点:
--mobile是错的,应由媒体查询统一收口到断点文件 - 不允许在 JSX 中字符串拼接 class:
className={`button ${props.active ? 'button--active' : ''}`}是反模式 - 第三方样式必须通过 wrapper 隔离,不能直接覆盖或重写
在 React + CSS Modules 场景下,BEM 怎么不和模块化打架
CSS Modules 默认生成哈希类名(如 Button_module__button__abc123),此时硬套 BEM 会破坏语义和可读性。正确做法是让 BEM 成为模块内部的组织逻辑,而非暴露给构建结果:
- 在
Button.module.scss中仍使用.button、.button__icon、.button--primary编写样式 - 通过
css-loader的localIdentName配置保留语义前缀:[path][name]__[local]--[hash:base64:5] - 用
clsx或classnames处理动态 class,避免手拼字符串 - 所有修饰符状态必须来自 props,禁止在组件内基于 DOM 状态(如
:hover)隐式添加修饰符
eslint-plugin-bem 能否真正卡住命名错误
能,但只在配合目录结构与 Code Review 时才有效。单独装个插件不会自动修复失控的命名习惯:
- 它可校验
.header__logo--large--dark是否含多重--,但无法判断--dark是否该属于.theme块 - 需配合目录强制 Block 边界:每个
Button/目录只允许一个Button.module.scss,禁止跨目录引用元素类名 - 构建阶段应启用
stylelint+stylelint-selector-bem-pattern对选择器做正则校验 - CI 流程中加入 class 名扫描脚本,告警非白名单修饰符(如
--ios、--v2)


















