bem是通过命名结构显性化组件边界、切断css隐式样式依赖的工程手段,解决修改一个组件时意外影响其他同名组件的问题,强制用block__element和block--modifier形式隔离样式作用域。

BEM 不是给 class 加长名字的技巧,而是用命名结构显性化组件边界、切断隐式样式依赖的工程手段。 它解决的不是“怎么起名好看”,而是“改一个 .button 时,为什么侧边栏的 .button 也崩了”这种真实协作灾难。
为什么后代选择器一写就失控:BEM 切断的是 CSS 的全局天性
CSS 没有作用域,.card .title 这种写法等于把样式控制权交给了 HTML 结构——只要父级 class 名或嵌套层级一变,样式就失效;更糟的是,它让所有带 .title 的元素都暴露在风险中。BEM 强制用 .card__title 替代,本质是把“属于 card 的 title”这个语义直接编码进类名,浏览器只匹配字符串,不认父子关系,自然不会跨块污染。
PigX UI Pro 前端开发指南 - Vue 3 + TypeScript + Element Plus。当用户提到 PigX UI、PigX 前端、lgb-mgui 项目、Vue 3 企业级后台开发、Element Plus 后台开发时使用此技能。
- 常见错误现象:
.header .logo→ 后来加了个.sidebar .logo,结果两个 logo 样式互相覆盖 - 正确做法:统一用
.header__logo和.sidebar__logo,哪怕样式完全一样,也各自声明 - 性能影响:看似多写了几个字符,但避免了浏览器反复计算复杂后代选择器的匹配路径,尤其在动态插入大量 DOM 时更稳定
modifier 不能嵌套:.button__icon--hidden 是反模式
修饰符只能作用于 block 或 element 本身,不能“再修饰 element 的子元素”。.button__icon--hidden 违背了 BEM 的层级契约——它暗示 icon 是可独立状态化的,但实际 icon 的隐藏逻辑往往和 button 的整体禁用状态强绑定。
- 应改为:
.button--disabled(控制整个按钮),然后在 CSS 中统一隐藏其内部.button__icon - 或拆出新 block:
.icon--hidden,但前提是这个 icon 确实能脱离 button 单独存在、复用 - 容易踩的坑:用 Sass 嵌套写
.button { &__icon { &--hidden { ... } } },编译后看似合法,但语义已模糊——维护者无法判断这个 hidden 是按钮状态的一部分,还是 icon 自身的独立变体
HTML 中 class 属性必须严格“单职责”:禁止混用 BEM 类与工具类
给 <div class="button__text text-center"> 这种写法看似省事,实则破坏了 BEM 的可追溯性。<code>text-center 是通用行为,button__text 是业务语义,两者混在同一元素上,团队无法快速区分哪些 class 是组件契约、哪些是临时补丁。
- 正确方式:所有布局/排版逻辑应下沉到 block 内部,例如在
.button中定义text-align: center,而非靠外部工具类注入 - 例外场景:仅限真正全局、无语义的辅助类,如
sr-only(屏幕阅读器专用),且需团队明确约定白名单 - 兼容性注意:某些 UI 库(如 Tailwind)默认鼓励工具类组合,接入 BEM 项目前必须建立转换层或约束使用范围,否则很快退化为“BEM 名 + 工具类”混合体
最常被忽略的一点是:BEM 的威力不在写的时候,而在改的时候——当你删掉一个 .card--hover,你得确信它只影响 .card 及其子元素,不会牵扯到任何其他模块。这要求每个 block 的命名必须真正独立、不可歧义,比如 .user-card 比 .card 更安全,哪怕多敲两个字母。










