组件目录结构必须与bem块名严格一一对应,目录名即块名(全小写、中划线分隔),如button组件必须置于/components/button/下,且仅允许button.css、button.tsx等归属该块的文件;禁止将元素(如button__icon)拆分为独立目录,禁止跨块选择器、非bem嵌套、类名变形或大小写混用,__仅表归属、--仅表状态,修饰符须依附宿主,html与css类名必须解耦以保障可复用性。

组件目录结构必须和BEM块名严格一一对应
每个组件必须独占一个目录,目录名就是块名(全小写、中划线分隔),比如按钮是button,就只能放在/components/button/下。这个目录里只允许出现button.css、button.tsx、button.test.tsx等直接归属该块的文件。
常见错误现象:把button__icon单独抽成/components/icon/目录——它不是独立块,只是button的元素,强行拆分会破坏BEM的语义闭环;又或者在button/目录里塞进card.css,CI检查会立刻fail。
- 块名必须可配置但不可变形:导出时支持
prefix="ui",生成ui-button、ui-button__icon,但内部结构不能变成ui-btn__ico - 禁止在CSS里写
.card .button这类跨块选择器——哪怕视觉上它在卡片里,样式也必须靠card__button类名驱动 - SCSS中禁用非
&__/&--的嵌套:& > span或&.is-active全部报错,用stylelint-selector-bem-pattern硬约束
类名拼写错误是BEM落地第一道坎
双下划线__和双短横线--写反不是“风格问题”,而是直接导致样式不生效或意外覆盖。浏览器不会报错,但button--icon匹配的是“一种叫icon的按钮”,而你要改的其实是按钮里的图标——得用button__icon。
典型翻车点:button__text--large合法,button--text-large语法无效,button__icon--primary合理(图标自身状态),但button--primary__icon解析失败,BEM工具直接忽略。
前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。
-
__只用于“属于谁”:dialog__header✅,dialog__header__title❌(应为dialog__title) -
--只用于“是什么状态”:button--disabled✅,button--bg-blue-500❌(颜色细节交给CSS变量,不是BEM职责) - 所有类名强制全小写+中划线:
BtnPrimary或btnPrimary都不合法,grep搜不到,协作就断链
Modifier不能脱离宿主单独使用
修饰符不是独立样式开关,它必须依附于块或元素存在。写class="button--primary"而不带button类,等于扔掉上下文——没人知道这个--primary是按钮、输入框还是弹窗的。
性能上没影响,但维护时极易误判。比如input--error单独出现,你得翻三遍代码才能确认它绑定的是哪个表单控件;而form-field__input--error一眼可知作用域。
- 禁止全局
--disabled类:button--disabled和checkbox--disabled各自独立,不能靠一个disabled类统管 - Modifier不叠加逻辑:
button--primary--large可以,但button--primary--loading--disabled已超出可读阈值,建议用JS控制组合态,CSS只保留原子状态 - 主题切换别塞进Modifier:
theme--dark是合法wrapper,但button--theme-dark会让主题无法运行时热替换
HTML结构和CSS类名必须解耦
BEM要求DOM可以任意嵌套,但CSS类名必须扁平。写<div class="card">
<h3 class="card__title">没问题,但绝不能靠<code>.card h3选中标题——万一将来卡片里加个<section></section>包裹标题,样式就断了。
这种解耦让组件真正可复用。同一个card__title类,既能在首页卡片里用,也能在弹窗摘要里用,不需要改一行CSS。
- 禁止路径式选择器:
.header ul li a❌,必须拆成header__nav、header__link等独立元素 - 元素不能跨块复用:
user-card__avatar和comment__avatar是两个类,哪怕长得一样——它们语义不同,未来可能分叉 - 深层嵌套不等于深类名:表单校验区不是
form__field__input__error,而是input-field块 +validation-message块,各司其职
class属性时,都得问一句:“这个类名脱离当前组件后,是否还有意义?”答案是否定的,那就还没写对。










