真正落地BEM需卡住block唯一性、element直属性、modifier可维护性;block须带业务前缀(如nc-button)并与组件名严格一致,禁止嵌套element(user-card__avatar__icon❌)和视觉型modifier(button--red❌),须通过stylelint、Git Hook、CI三阶校验。
直接定死 block__element--modifier 格式不等于有了规范——真正卡住协作的,是 block 名是否唯一、element 是否越界、modifier 是否可维护。没校验工具链兜底,三天后就会出现 user-card__title 和 user-card-title 并存。
用 button 或 card 作 block 名,等于主动放弃命名空间隔离。Ant Design、Bootstrap、甚至你自己的 ds-button 都可能撞车。
nc-button(nc = team/product 缩写)、myapp-user-card、ds-input
base-button、common-card、ui-header——这些词在 PR 里无法被唯一索引/components/user-profile-card/ → user-profile-card.css → user-profile-card 类profile-card 或 user-card,否则 Figma 插件导出类名和实际 CSS 对不上user-card__avatar__icon 看似“更细”,实则破坏 BEM 基础契约:元素不可再拆解归属。它不是 DOM 深度标记,而是逻辑归属声明。
user-card__avatar、user-card__avatar--compact、user-card__avatar-icon(把 icon 视为 avatar 的视觉变体)user-card__avatar__icon(编译后无效,stylelint 直接报错)、user-card__user-card-title(语义重复,“user-card-”前缀无意义)avatar 自身具备独立交互或复用逻辑,就该升格为新 block:avatar,而非强行挂在 user-card 下user-card__div、user-card__span 是反模式;应是 user-card__content、user-card__badge
button--red 这类 modifier 看似直观,但换主题时根本没法映射——红色可能是 primary、danger、highlight,取决于上下文。它不是状态,是颜色值快照。
button--primary、button--disabled、input--search、modal--fullscreen
button--blue、card--large、text--14px——这些值会随断点、主题、设备变化,无法长期维护--is-loading 是反模式;应保持 button--loading 类,并用变量驱动其样式:.button--loading { background-color: var(--ui-button-bg-loading); }
button--primary--disabled 不合法;应并列使用:button button--primary button--disabled
靠 Code Review 或文档提醒,拦不住手滑。违规类名必须在保存、提交、构建三个环节就被拦截,否则每天都在污染边界。
stylelint-selector-bem-pattern 插件,配置 {"styleType": "bem"},它会立刻报错:.header .logo(结构选择器)、.btn-primary(非 BEM 格式)、CardTitle(大驼峰)、_input(下划线开头)npx stylelint "**/*.{css,scss}",失败即阻断合并&__input { &__icon {} } 会产出 block__input__icon,违反规则;只允许单层:&__input {} &--compact {}
cn('input', 'disabled') 而非 `button__${e}--${m}`——后者漏空格、错连字符、大小写不一致,在 Linux 构建环境直接挂掉最常被忽略的一点:BEM 不是给类名“加长”,而是让每个字符都承担语义责任。user-profile-card__avatar--compact 里少一个 -、多一个 _,都不是“写错了”,而是让工具链失效、团队搜索失焦、重构路径断裂。它必须像函数签名一样精确。