必须优先识别并冻结三类高危类名:泛化名(如.btn、.nav)、JS硬编码类(通过grep定位)、高频修改文件中的混杂类(如.logo);带!important或深层后代选择器的类需加别名过渡,不可直接删除。

不困难,但直接全局替换类名=线上事故。BEM本身没难度,难的是旧项目里那些 document.querySelector('.btn')、!important、#header .nav li a 和嵌套过深的后代选择器——它们才是真正的阻力源。
哪些旧类名必须先识别并冻结
别碰所有类名,只盯三类高危项,它们实际充当“隐式接口”:
-
.btn、.nav、.sidebar这类泛化名:语义混杂,JS 可能硬编码调用,CSS 里还常被!important强压 - 高频修改文件里的混杂类,比如
.logo在登录页和后台页承担不同结构职责,改一处崩两处 - 带
!important或深层后代选择器的类,如#main .content .item a:hover,说明它已失控,靠权重维稳而非归属控制
执行命令:grep -r "document\.querySelector\(['\"].*\.[a-z]\+['\"]\)" src/ --include="*.js",把结果列成迁移清单——这些类不能删,只能加别名过渡。
HTML不动结构,怎么安全套上BEM类名
老项目 DOM 嵌套深、语义乱,硬拆结构会牵连事件绑定和表单校验。务实做法是「语义映射」:
立即学习“前端免费学习笔记(深入)”;
- 原代码:
<div class="form"><input></div>→ 改为:<div class="login-form"><input class="login-form__input"></div> - CSS 中立刻删掉所有孤立的
.input、.error规则,只保留.login-form__input和.login-form__input--error - 禁止写
.login-form .input这类后代选择器——它默认你永远不重构父容器,而 BEM 的契约是“删掉login-form,子元素仍能渲染”
CSS加载顺序和层叠冲突怎么破
新BEM类名写好了,但样式还是被旧CSS覆盖?问题不在命名,而在层叠逻辑没理清:
-
<link>必须严格位于旧 CSS 之后(哪怕只是逻辑上后加载),否则.button__text权重再低也压不住#header .nav li a:hover - 用
@layer显式分层:@layer legacy { /* 旧规则 */ }+@layer bem { /* 新 BEM 规则 */ },现代浏览器按层覆盖 - 对旧 DOM 容器加命名空间根类,如
legacy-header,并在其 CSS 开头写.legacy-header { all: unset; }(慎用,仅限强污染场景) - 新BEM组件必须显式重置基础样式:
box-sizing: border-box、margin: 0、padding: 0,避免继承旧全局重置的副作用
JS里硬编码的类名怎么处理
这是最容易被忽略的断裂点,比CSS更致命:
- 不要立刻改
el.classList.contains('btn-primary'),先临时兼容:el.classList.contains('btn-primary') || el.classList.contains('c-button--primary') - 逐步收敛到语义属性:
data-role="primary-button",再用querySelector('[data-role="primary-button"]') - 禁止动态拼接类名:
`${block}__${elem}--${mod}`—— 若elem含空格或特殊字符,类名直接失效;改用clsx等工具声明式组合
BEM不是重命名运动,而是用命名契约显性化组件边界。真正卡点从来不在语法,而在谁在JS里偷偷改了 style.color,或者那个 body 上的 font-size: 62.5% 到底影响了多少层。每次只动一个模块,上线后盯住 Sentry 里的样式相关报错——比任何文档都准。


















