应优先处理高风险共用模块类名而非泛化类名,通过grep锁定JS硬编码类名并加别名过渡,HTML仅做语义映射,CSS用@layer分层并重置基础样式,严格遵循BEM命名边界。

先别动.btn、.card这些泛化类名
直接全局搜索替换 .btn 或 .card,90% 会触发样式崩坏和 JS 断裂。因为这些类名在旧项目里往往承担多重语义:可能是按钮、链接、标签;也可能被 document.querySelector('.btn') 硬编码绑定;还可能出现在 data-class="btn" 这类非标准位置。真正该优先处理的,是那些你改完一个地方、第二天收到三张样式 bug 工单的模块——比如被登录页和后台页共用但表现不一致的 .nav,或靠 #main .content .item a:hover 这种深层选择器强压样式的区域。
用 grep 锁定 JS 中硬编码的类名再动手
执行命令:grep -r "document\.querySelector\(['\"].*\.[a-z]\+['\"]\)" src/ --include="*.js",把结果列成迁移清单。这些类不能删,只能加别名过渡。例如原 JS 里有 el.classList.contains('error'),HTML 就得保留 class="form-item__input--error error",CSS 中则只维护 .form-item__input--error 规则,逐步替换 JS 中的判断逻辑。同时检查 classList.toggle、埋点上报字段、服务端模板渲染点——漏掉一处,就可能让某个按钮永远无法变 disabled。
HTML 不动结构,只做语义映射
老项目 DOM 嵌套深、语义乱,硬拆结构会牵连事件绑定和表单校验。务实做法是「语义映射」:
原代码:<div class="form"><input></div> → 改为:<div class="form-item"><input class="form-item__input"></div>
对应 CSS 必须立刻删掉所有孤立的 .input、.error 规则,只保留 .form-item__input 及其修饰符(如 .form-item__input--error)。禁止写 .form-item .input 这类后代选择器——它默认你永远不重构父容器,而 BEM 的契约是“删掉 form-item,子元素仍能渲染”。
@layer 分层 + 后加载新 CSS 才能压住旧权重
新 BEM 类名写好了,但样式还是被旧 CSS 覆盖?问题不在命名,而在层叠逻辑没理清:
– <link> 必须严格位于旧 CSS 之后(哪怕只是逻辑上后加载)
– 用 @layer 显式分层:@layer legacy { /* 旧规则 */ } + @layer bem { /* 新 BEM 规则 */ }
– 对旧 DOM 容器加命名空间根类(如 legacy-header),并在其 CSS 开头写 .legacy-header { all: unset; }(仅限强污染场景)
– 新 BEM 组件必须显式重置基础样式:box-sizing: border-box、margin: 0、padding: 0,避免继承旧全局重置的副作用
立即学习“前端免费学习笔记(深入)”;
最易被忽略的是 Block 名的归属边界——card 是错的,product-card 才对;card--loading 是反模式,is-loading 才是状态类的合理归宿。每次加新类名前,得确认它脱离当前上下文是否仍有意义。


















