bem通过仅使用类名(权重10分)替代元素选择器(权重1分)直接压低选择器权重,避免嵌套路径导致权重累积和覆盖困难。

为什么BEM能直接压低选择器权重
因为BEM强制你只用类名,彻底避开 div.header ul li a 这种嵌套路径写法。浏览器计算选择器权重时,每个类名算10分,而元素名(div、ul)只算1分——但关键是:BEM让你根本不用元素名组合。一个 .menu__item--active 就是10分;而传统写法里 .menu ul li.active a 轻松凑到 1+1+1+10+1 = 14 分,还更难覆盖。
常见错误现象:.sidebar .widget h3 看似清晰,但权重12,想在局部覆盖它就得写 .sidebar .widget .title--highlight(10+10+10=30),越改越肥。BEM下直接 .widget__title--highlight(10分),干净利落。
- 所有样式必须通过类名驱动,禁止用标签、ID 或属性选择器做样式主干
- 模块名(Block)必须唯一且语义化,比如
.card,不是.ui-card或.mod-card - Element 和 Modifier 都用双下划线
__和双中划线--,这是硬约定,别自创.card-element
BEM命名怎么避免“过度拆分”和“语义模糊”
很多人一上手就疯狂套BEM,把 .button__icon__svg__path 这种写出来,既违反层级限制(BEM只允许 Block → Element 或 Block → Modifier),又让结构失控。BEM的Element必须是Block的直接组成部分,不能嵌套Element。
使用场景:一个卡片 .card,里面头像、标题、操作按钮都是它的Element,所以是 .card__avatar、.card__title、.card__actions;但按钮里的图标?它属于 .card__actions 这个Element的内部实现,不该暴露为 .card__actions__icon —— 正确做法是让按钮自己成为独立Block:.button,再配 .button__icon。
- Element 名必须可读、可预测,拒绝
.card__el-1或.card__part-a - Modifier 不是状态快照,而是有意图的变体,比如
.button--primary合理,.button--is-loading就越界了(该用JS加类控制,而非BEM命名) - 遇到“组件内嵌组件”,优先提取为独立Block,而不是拉长BEM链
CSS-in-JS或CSS Modules里怎么守BEM规则
很多人以为用了 styled-components 或 css-modules 就不用BEM了,结果写出一堆 const Title = styled.h3,最后全局样式冲突、复用困难。BEM本质是命名契约,跟是否用预处理器无关。
参数差异:在CSS Modules中,styles.card__title 生成的类名可能是 Card_card__title__abc123,看似冗余,但它保证了局部作用域 + BEM语义双收益;而 styled-components 需手动命名,比如 const CardTitle = styled.h3.attrs({ className: 'card__title' }),否则就丢了BEM意义。
- CSS Modules中,文件名即Block名:
card.module.css对应.card,里面只写.card__title、.card--fluid - 不要在JSX里拼接类名字符串,比如
className={`card ${isActive ? 'card--active' : ''}`—— 改用clsx或对象写法,保持可维护性 - 如果用Tailwind,BEM不适用,但可以靠
@layer components+ 命名前缀模拟同等约束力
当老项目要渐进式引入BEM,哪些地方最容易翻车
最常被忽略的是CSS重置和第三方UI库。比如全局写了 button { padding: 8px; },然后你在BEM里定义 .button { padding: 12px; },结果按钮实际表现是两者叠加(padding没被覆盖,只是新增)。这不是BEM的问题,是权重和层叠逻辑没理清。
性能影响很小,但兼容性坑在IE11:BEM本身无问题,但如果你用PostCSS自动补全 :focus-visible 这类新特性,又没关掉对旧选择器的转换,可能产出 .button__text:focus-visible 在IE里直接失效,且不报错。
- 先删掉所有通配符重置(
* { box-sizing: border-box; }保留,但h1, h2, p, ul { margin: 0; }这类必须收归到具体Block下) - 第三方库(如Ant Design)的样式要包裹在独立scope里,比如用
:where(.legacy-ui) .ant-btn降权,避免污染BEM体系 - 构建工具里检查CSS输出,确认没有意外生成
div.card__header这类带标签的选择器(Sass的嵌套语法容易偷偷干这事)
平坦化的真正难点不在命名,而在团队每次加新样式时,能不能忍住不写 .modal .content p strong —— 那一行代码省事,但之后十次覆盖都得绕路。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











