必须用btn--disabled,因bem规范强制--为修饰符唯一合法分隔符;btn-disabled或btn_disabled会被工具链误判为独立块或无效类,导致构建误删、devtools无法识别状态。

直接加 class 并写对应 CSS 规则就行,但必须确保修饰符命名合法、绑定位置准确、JS 控制方式可靠——否则样式不生效、状态错乱、调试困难。
为什么 btn--disabled 不能写成 btn-disabled 或 btn_disabled
BEM 规范强制要求修饰符用双中划线 -- 分隔,这是语义识别的底线。工具链(如 PurgeCSS、VS Code BEM 插件、TypeScript 类型推导)靠它区分「状态」和「新块名」。
-
btn--disabled✅ 被识别为btn块的禁用变体,CSS 可统一收口,构建时不会误删 -
btn-disabled❌ 被当成独立块,DevTools 里看不出和btn的关系,协作时易重复造轮子 -
btn_disabled❌ 下划线无 BEM 约定,PostCSS 插件无法提取合法修饰符枚举值
JS 添加修饰符时,classList.toggle 比字符串拼接更安全
动态控制类名不是拼字符串的事,漏空格、覆盖其他类、难调试是常见问题。
- ❌ 错误写法:
el.className = `btn btn--${variant} ${isDisabled ? 'btn--disabled' : ''}`—— 容易多空格、丢类、难维护 - ✅ 推荐写法:
el.classList.toggle('btn--disabled', isDisabled)—— 原子操作,不干扰其他类 - 多个状态叠加时,用
clsx或class-variance-authority枚举控制,比如:clsx('btn', { 'btn--primary': variant === 'primary', 'btn--disabled': isDisabled })
CSS 中修饰符规则必须独立定义,不能依赖组合选择器
修饰符不是“开关”,而是显式声明的视觉契约。写成组合选择器(如 .btn--primary.btn--disabled)会让样式脆弱且不可预测。
- ✅ 正确做法:分别定义
.btn.btn--disabled { opacity: 0.6; }和.btn.btn--loading { cursor: wait; } - ✅ 多状态共存需显式处理:
.btn--disabled.btn--loading { opacity: 0.4; }—— 不写这条,就默认只有--disabled的效果 - ❌ 禁止嵌套修饰符:
btn--primary--disabled是非法写法,语义模糊,破坏可维护性
移动端响应式状态必须由 JS 主动切换修饰符类
媒体查询不会自动往 DOM 上加类,nav__list--mobile 这种修饰符必须靠 window.matchMedia 监听并手动增删。
- 首次加载就要检查一次,避免渲染后监听导致闪屏
- 用
matchMedia('(max-width: 768px)').matches判断当前是否匹配,再调用element.classList.add('nav__list--mobile') - Modifier 名要表达布局意图,不是交互动作:
nav__list--mobile✅(随屏幕尺寸自动生效),nav__list--collapsed❌(这是用户点击触发的交互态) - 多状态叠加时,CSS 必须显式带上父级前缀,比如
.nav__item--active在.nav__list--mobile下失效,就得写成.nav__list--mobile .nav__item--active
最容易被忽略的是:修饰符不是“多写几个 class”那么简单,它是把组件的合法状态显式契约化。一旦允许运行时任意字符串注入,或者靠 [class*="--"] 这类模糊匹配兜底,BEM 就退化成带连字符的普通命名而已。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











