BEM核心是解耦HTML结构与CSS样式,避免嵌套过深和权重冲突;正确写法为Block__Element--Modifier,禁用三层以上嵌套、不暴露实现细节、不用第三方类名覆盖业务模块。

为什么直接写 .header .nav li a 会越改越崩
嵌套选择器表面看着“结构清晰”,实际是把 HTML 结构耦合进了 CSS,只要 DOM 微调(比如加个 div 包一层、换了个父容器类名),样式就失效;更麻烦的是,多人协作时谁都能往里塞 !important 或更高权重的选择器,最后变成权重军备竞赛。
实操建议:
- 禁止三层及以上嵌套(如
.page .content .list .item) - 不依赖父子关系推导样式,每个组件的样式只作用于它自己
- 把“这个按钮在弹窗里要变小”这种需求,改成给按钮加独立修饰符:
btn--small,而不是写.modal .btn
BEM 的三要素怎么写才不翻车
BEM 不是命名炫技,核心就三点:Block(块)、Element(元素)、Modifier(状态)。写错一个连字符、多一个下划线,CSS 就对不上号。
常见错误现象:
-
header__logo--large写成header_logo--large(少了双下划线,预处理器或工具链直接忽略) - 把 Modifier 当 Element 用:
btn__disabled❌ 应该是btn--disabled✅ - Element 命名暴露实现细节:
header__flex-container→ 改成header__nav,样式怎么布局是 CSS 的事,不是名字的事
正确示例:
.header { }
.header__logo { }
.header__nav { }
.header__nav--mobile { }
.header__nav-item { }
.header__nav-item--active { }
遇到第三方组件库时,BEM 怎么不被覆盖
像 Ant Design、Element Plus 这类库默认用自己的命名空间(.el-button),你用 BEM 写的 .btn--primary 很可能被它们的 .el-button:focus 权重压住。
使用场景:需要定制主题但又不能改库源码。
实操建议:
- 用属性选择器提高可控性:
[class*="btn--"]比单纯.btn--primary更稳,避免被库的后代选择器意外命中 - 必要时加
:where()降权::where(.btn--primary) { color: red; },确保不会反超第三方规则 - 不硬刚,优先用库提供的自定义变量(如
--el-color-primary),BEM 只管业务专属模块
PostCSS 插件能自动转 BEM 吗?别信
像 postcss-bem 或 postcss-nested 看似能帮你省事,但实际会掩盖结构问题:它把 &__item 编译成 .list__item,可如果你忘了写最外层 .list,编译后照样出错,还更难 debug。
性能与兼容性影响:
- 构建时多一道编译,CI 流水线变慢,尤其大项目里每个 CSS 文件都过一遍嵌套解析
- 调试时 DevTools 显示的是编译后类名,和源码对不上,新人排查样式来源要多绕两步
- 真正省事的方式是编辑器片段(snippets):输入
bem-e直出block__element,比靠插件猜意图靠谱得多
最容易被忽略的一点:BEM 不是让类名变长,而是让「谁负责什么」变得不可争议。哪怕只在一个组件里坚持用 card、card__title、card--hover,也能挡住 80% 的样式污染。一旦开始用 card-header 这种模糊命名,边界就松动了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











