Shadow DOM 不解决语义混乱,BEM 通过 user-card__title 等命名明确模块归属,提升调试、协作与测试可靠性,是人机共读的协作契约。

Shadow DOM 并不自动解决类名语义混乱
Shadow DOM 隔离的是样式作用域,不是语义。你在 <user-card></user-card> 里写 class="title",在 <post-list></post-list> 里也写 class="title",浏览器不会报错,但 DevTools 里根本分不清哪个是用户头衔、哪个是文章标题。
常见错误现象:团队成员各自定义 .input、.btn,结果调试时看到十几个同名 class,只能靠逐个点开模板确认上下文;或者用随机哈希类名(如 _a1b2c),连 CSS 文件都懒得维护,改样式全靠全局搜索字符串,极易误伤。
- BEM 把模块归属直接编码进名字:
user-card__title和post-list__title一眼可辨 - 构建产物中
grep user-card__能精准定位所有相关 HTML、CSS、JS 片段 - 第三方集成或 SSR 场景下,Shadow DOM 尚未激活,外部 CSS 仍需靠类名匹配——这时
dialog--open比is-open更安全、更可预测
自动化测试依赖 BEM 类名的稳定性
测试脚本失效,八成是因为 locator 不稳。cy.get('button') 在真实项目里基本不可用:它会匹配 Ant Design 的 <button></button>、自定义 <mybutton></mybutton> 渲染出的底层 <button></button>,甚至被 v-show 隐藏但仍存在的按钮。
而 cy.get('.search-form__submit') 只命中那个提交按钮——前提是类名合规、没被构建工具意外改写。
立即学习“前端免费学习笔记(深入)”;
- Modifier 必须与 Block/Element 同时存在:
button button--disabled✅,button--disabled单独出现 ❌ - CSS Modules 或 CSS-in-JS 哈希后类名变成
search-form__submit_abc123,测试仍写原始名就会失败,需确保测试环境启用localsConvention: 'camelCaseOnly'并通过styles['search-form__submit']引用 - 避免后代选择器退化:
.modal--open .modal__content这种写法破坏 BEM 作用域,PostCSS 插件应拦截
BEM 是跨技术栈的协作契约,不依赖框架或构建器
你在写 Lit 组件,同事用 Stencil 写另一个,设计系统文档里写的 “按钮禁用态应加 button--disabled”,这个约定不靠 JS 注入、不靠构建插件,只靠命名本身传递意图。
UI 设计师交付的标注稿里写 input__field--error,前端不用问 “这是哪个 input?”“error 是修饰整个块还是仅 field?”。Code Review 时发现 card__footer__action,立刻知道违反了 BEM(Element 不得嵌套 Element),哪怕组件完全跑在 Shadow DOM 里。
- BEM Block 名几乎就是组件名直译:
user-profile对应UserProfile.vue或user-profile.js - 禁止用
global、base这类泛义词当 Block 名,它们注定会在第 3 个迭代时变成命名黑洞 - 工具链必须校验:Stylelint 的
selector-bem-pattern规则要开到 error 级别
性能与可维护性来自单类名选择器,而非名字长短
BEM 的性能优势不来自名字冗长,而来自浏览器一次哈希查找。.user-card__avatar--loading 是直接查 class 表;.user-card .avatar 则让浏览器先找所有 .avatar 元素,再逐层向上检查父级是否匹配 .user-card,DOM 越深越慢。
常见陷阱:Sass 中写 .user-card { & .user-card__badge { } },编译出带空格的选择器,破坏性能和隔离性。
- DevTools → Elements → Computed → Styles 面板里一眼就能看出有没有空格——有空格就是潜在隐患
- 构建后用
grep -r "\.[a-z]\+ \.[a-z]" dist/快速揪出残留的空格选择器 - 禁止使用嵌套选择器意味着:即使 DOM 结构被其他子应用意外修改(比如加了中间 wrapper),样式依然生效
dist/main.css 里第 372 行和第 1894 行谁覆盖了谁。


















