在CSS开发中BEM命名规范常见变体有哪些?

作者:袖梨 2026-07-15
BEM变体存在是为适配现代前端约束:React组件粒度、CSS-in-JS、构建体积与团队习惯;双连字符(--)语义清晰且支持SCSS嵌套,单连字符(-)压缩更优但易混淆;UI库加前缀(如el-button)防污染并支持多版本共存,业务组件通常无需。

为什么会有 BEM 变体,而不是统一用 .block__element--modifier

BEM 原始规范由 Yandex 提出,但实际项目中几乎没人 100% 照搬。根本原因是:原生 BEM 对长类名容忍度高、对工具链无要求,而现代前端要兼顾 React 组件粒度、CSS-in-JS、构建产物体积、可读性与团队习惯。变体不是“不守规矩”,而是为解决具体约束做的权衡。

double-dashsingle-dash 修饰符写法怎么选

标准写法是 .block--modifier(双连字符),但有些团队改用 .block-modifier(单连字符)。这不是随意缩写,背后有明确取舍:

  • --:语义清晰,和 __ 形成视觉对称,CSS 预处理器(如 SCSS)能安全嵌套 &--hover;但类名更长,压缩后仍明显
  • -:缩短类名(.btn-primary.btn--primary 少 2 字节),适合对 bundle size 敏感的项目;但容易和 Block 名中的连字符混淆,比如 .user-profile-active 无法判断 profile 是 Block 还是 Element
  • 更危险的是混用:同时存在 .btn--large.btn-primary,会让开发者反复查文档确认规则

带命名空间前缀的 BEM(如 el-button)适用什么场景

像 Element Plus、Ant Design 这类 UI 库普遍采用 [prefix]-[block] 格式(如 el-buttonant-table),这不是 BEM 的“错误用法”,而是封装隔离的刚需:

  • 避免全局类名污染:UI 库被多个项目共用时,button 太通用,el-button 明确归属
  • 支持多主题/多版本并存:el-buttonel-button-v2 可同时加载,而 .button--v2 会和旧版样式冲突
  • 但业务组件一般不需要:你自己的 user-cardmy-user-card 前缀反而增加认知负担,除非跨团队共享组件库

React 中 classnames + BEM 的常见错配点

很多人以为装了 classnames 就算用了 BEM,其实关键在 Block 名是否收敛:

立即学习“前端免费学习笔记(深入)”;

  • 错误写法:className={cx('card__header', { 'card__header--expanded': expanded })} —— Block 名硬编码在 JSX 里,组件重命名或复用时类名全崩
  • 正确写法:顶部定义 const BLOCK = 'user-profile',然后统一用 cx(`${BLOCK}__header`, { [`${BLOCK}__header--expanded`]: expanded })
  • 更进一步:抽成 hook,如 useBem('user-profile') 返回 getBlockgetElement 方法,避免字符串拼接出错

真正难的不是记住 __--,而是每次加一个新 class 时,得判断它该属于 Block、Element 还是 Modifier——这个决策一旦错,后续所有样式都可能变成“修修补补式维护”。

相关文章

精彩推荐