必须优先处理.btn、.nav、.modal等泛化类名及JS硬编码类,因其在JS中被querySelector硬依赖、HTML中随意复用、常含!important;绝对不可直接全局替换,须通过语义映射、@layer分层和Block命名规范渐进迁移。

直接全局搜索替换 .btn 或 .card 类名,90% 会导致样式大面积错乱、JS 绑定断裂、回滚困难——这不是操作失误,而是把 BEM 当成了重命名工具。
哪些类名必须优先动,哪些绝对不能碰
重构不是从“最眼熟的”开始,而是从“最容易引发连锁故障”的地方切入:
-
.btn、.nav、.modal这类泛化名:它们在 JS 中被document.querySelector('.btn')硬编码,在 HTML 中随意复用,还常搭配!important强行覆盖,属于高危起点 - 高频修改文件里的混杂类名:比如
common.css中的.sidebar,git blame显示多人反复修改,说明它已承载多个业务逻辑,边界早已模糊 - JS 里直接依赖的类名:全局搜索
document\.querySelector\(['"]\.[a-z]+['"]\),找出所有被硬编码的类,这些要加别名过渡,不能直接删 - 跳过
.clearfix、.hidden这类工具类:统一迁到u-clearfix、u-hidden前缀下,和 BEM 业务类物理隔离
HTML 不动,怎么安全套上 BEM 类名
老项目结构深、语义乱,硬拆 DOM 会牵一发而动全身。务实做法是「语义映射」而非「结构重排」:
- 原代码:
<div class="form"><input></div>→ 改为:<div class="login-form"><input class="login-form__input"></div> - CSS 中只保留
.login-form__input规则,删掉所有孤立的.input、.error规则 - 禁止写
.login-form .input这种后代选择器——它绕过 BEM 隔离,且未来无法迁移到 CSS Modules 或 Shadow DOM - 若旧 JS 依赖
.form input,先加临时 wrapper:<div class="legacy-form"></div>,CSS 里用.legacy-form .login-form__input过渡
Block 名怎么起才不埋雷
Block 名不是加前缀,而是定义归属边界。起错名字,三年后没人敢动它:
立即学习“前端免费学习笔记(深入)”;
-
card❌ —— 全局冲突高,别人写时根本不知道你在哪个业务域 -
product-card✅ —— 明确归属,和user-card、cart-card天然隔离 -
card--featured✅ —— Modifier 表达视觉变体;card--loading❌ —— 这是 JS 状态,不该由 CSS 类控制 - Block 必须是功能闭环单元:
.search-form合格(含输入框+提交按钮+清空逻辑),.section-2不合格(纯视觉分组)
SCSS 嵌套怎么写才不破坏 BEM 语义
&__icon 看着省事,但一不小心就写出 &__input &__icon(带空格),编译出来是后代选择器,等于悄悄绕过 BEM 隔离:
- 只允许单层嵌套:
.search-form { &__input {} &--compact {} } - 禁止
&__input { &__icon {} }—— 这会生成.search-form__input__icon,违反 BEM 元素不可嵌套原则 -
@extend禁用跨 block:哪怕.button--small和.input--small样式相同,也必须各自定义,否则修改一处,两处同时崩 - 变量名同步 BEM 化:
$button-padding-vertical,而不是$padding-sm,避免团队误以为它是全局尺寸标准
真正难的不是记住双下划线,而是每次写新类名时多停半秒:它是谁的一部分?它有没有独立存在的意义?改一个 modifier 会不会意外影响别的 element?


















