直接用 btn-red 等视觉化命名会导致样式与外观强耦合,修改设计需改类名并牵连 HTML;多人协作时语义模糊,易误用、难维护。应以角色(如 btn-primary)而非外观命名,禁用纯状态词和单单词类名。

为什么直接用 btn-red 这类名字会出问题
因为样式名一旦和视觉强绑定,改个颜色或布局就不得不改类名,甚至牵连 HTML。更麻烦的是,多人协作时没人知道 card-small 是指宽度、高度还是字体大小——它没表达“谁在什么上下文中干了什么”。
常见错误现象:header-blue 用在 footer 上,结果加了 !important 强行覆盖;或者重构时发现 list-inline 其实是垂直排列,但没人敢删——怕影响其他页面。
- 命名应描述「角色」而非「外观」,比如
btn-primary表示主操作按钮,不是“蓝色按钮” - 避免纯状态词(
hidden、active),它们该由 JS 控制 class 切换,不写死在 CSS 里 - 项目初期就禁用单单词类名(如
menu、item),它们几乎必然冲突
BEM 的三个部分怎么拆解才不混乱
BEM 是 Block–Element–Modifier 的缩写,但很多人卡在“哪个是 Block”。关键判断标准:这个模块是否能独立存在、可复用、有明确边界?比如一个搜索框(search-form)是 Block;里面的输入框(search-form__input)是 Element;带加载态的版本(search-form--loading)是 Modifier。
容易踩的坑:header__logo__link 这种嵌套是错的——Element 只能直属 Block,不能套 Element。正确写法是 header__logo-link 或拆成独立 Block logo-link。
立即学习“前端免费学习笔记(深入)”;
- Block 名必须语义清晰、全小写、用短横线分隔,如
user-card,禁用userCard或user_card - Element 名前双下划线:
user-card__avatar,不是user-card-avatar(后者易被当成新 Block) - Modifier 前双短横:
user-card--compact,不是user-card-compact(避免和 Element 混淆)
遇到嵌套组件时,BEM 怎么避免名字爆炸
比如一个 product-list 里包含多个 product-item,而每个 item 又有 price-tag。这时别写成 product-list__product-item__price-tag——BEM 不支持三层嵌套。正确做法是把 price-tag 当作独立 Block,或降级为 product-item__price-tag(前提是它不会脱离 product-item 单独使用)。
性能影响很小,但命名过长会导致 CSS 选择器冗余、开发者阅读成本上升。Chrome DevTools 里看到一长串 sidebar-nav__item__link__icon--hover 就知道设计出问题了。
- 只要某个 UI 片段可能被复用到别处,就该定义为独立 Block,哪怕只用一次
- Element 名不要重复 Block 名,
modal__modal-header是冗余的,直接modal__header - 用 SCSS 时,Modifier 的样式建议写在 Block 文件末尾,别分散在各处,否则搜
--disabled找不到所有地方
要不要用 BEM 工具或预处理器语法糖
像 @bem/react 或 PostCSS 插件确实能自动生成类名,但多数中小型项目没必要。手写 button__label--large 比调用 bem('button', 'label', { large: true }) 更快也更可控。
真正容易被忽略的是:BEM 解决不了逻辑耦合。比如 form__submit--disabled 和 JS 中的 isDisabled 状态不同步,样式就失效。这类问题得靠约定+Code Review,不是靠工具。
- 禁用 CSS-in-JS 库自动生成的 BEM 风格类名(如
css-abc123),它们破坏可读性且无法被设计师理解 - 如果团队已用 Tailwind,别硬套 BEM;可以用
@layer components+ 自定义 class 名模拟 Block 行为 - 最复杂的点其实不在命名规则本身,而在每次新增组件时,要快速判断它是 Block 还是 Element——这需要对业务域有共识,光看 CSS 规范没用


















