重构旧CSS不是重命名,而是用BEM将类名转化为可定位、可协作、可推演的标识符;须优先处理泛化类(如.btn)、混杂类(如.sidebar)和JS硬编码类,跳过工具类,HTML结构不动而原地加归属,禁用后代选择器,新旧类名共存并逐步替换。

直接重构旧 CSS 不是重命名,而是用 BEM 把类名变成“可定位、可协作、可推演”的标识符——改错一个 .btn 可能导致 JS 绑定失效、表单校验崩、设计师标注对不上,必须分层处理、带过渡策略。
哪些类名必须优先动,哪些绝对不能碰
先全局搜索三类高危类名,它们才是重构起点:
-
.btn、.card、.nav这类泛化命名:JS 里常被document.querySelector('.btn')硬编码,HTML 中随意复用,还爱配!important - 高频修改文件(如
header.css)里的混杂类名:.sidebar被多人反复改过,说明它已承载多个业务逻辑,语义早已模糊 - JS 中直接依赖的类名:用正则
document\.querySelector\(['"]\.[a-z]+['"]\)扫出所有硬编码点,这些要加别名过渡,不能直接删 - 跳过
.clearfix、.hidden这类工具类,统一迁到u-clearfix、u-hidden前缀下,和 BEM 业务类物理隔离
HTML结构不动,怎么安全套上BEM类名
老项目里 <div class="form"><input></div> 这种结构,硬拆成 form__input 会牵连 JS 事件绑定和表单校验。正确做法是原地加归属:
- 把
class="form"改成class="login-form" -
<input>加class="login-form__input" - CSS 里只保留
.login-form__input规则,删掉所有孤立的.input - 禁止写
.login-form .input这种后代选择器——它默认你永远不重构父容器,而 BEM 的契约是“删掉login-form,子元素仍能渲染” - 如果旧 HTML 里已有
class="btn btn-red",先保留btn-red作别名,新代码只用button--primary,逐步替换
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,避免团队误以为它是全局尺寸标准
Vue/React组件里怎么避免手动拼接BEM类名
写 className={`button ${isDisabled ? 'button--disabled' : ''}` 看似灵活,实际埋了坑:
- 拼错字符串、漏空格、状态组合爆炸(
button--disabled button--loading button--primary)极易出错 - 用
clsx或classnames库,显性组合:className={clsx(styles.button, isDisabled && styles['button--disabled'], isLoading && styles['button--loading'])} - 禁止硬编码哈希后的类名(如
_button_abc123),等于放弃 CSS Modules 的可维护性 - 如果用了 Tailwind,BEM 类名只用于结构标识(如
user-card__avatar),视觉细节交给tw`w-10 h-10 rounded-full bg-gray-200`,二者职责分明
BEM 最容易被忽略的复杂点不在语法,而在边界——第三方组件输出的 class 不可控,老代码里 .user-name 已被 JS 多处引用,这时候不是比谁写得更“规范”,而是谁能守住 wrapper 层、设好别名、监控旧类使用路径,让重构不卡上线节奏。


















