直接拼字符串赋值 classname 会覆盖原有类、漏空格、无法增量控制;应使用 classlist api 分步操作,并在 react/vue 中交由 clsx 或框架机制处理。

JS 添加 class 时为什么不能直接拼字符串
直接写 el.className = 'btn btn--loading' 容易覆盖已有类、漏空格、无法增量控制状态。比如按钮原本有 btn--primary,这一句会把它彻底清掉。
正确做法是用 classList API 分步操作:
-
el.classList.add('btn--loading')—— 只加不扰动其他类 -
el.classList.remove('btn--disabled')—— 精准移除,不碰其他修饰符 -
el.classList.toggle('btn--disabled', isDisabled)—— 布尔同步最稳妥
尤其注意:不要在 React/Vue 模板里手动拼接 className,应交由 clsx 或框架的 class 绑定机制处理,避免 ${block}__${elem}--${mod} 这种字符串模板出错。
多个 BEM 修饰符共存时 CSS 怎么写才不打架
BEM 允许多修饰符共存(如 btn--primary btn--loading btn--disabled),但前提是它们语义正交、样式互不覆盖。常见错误是把所有逻辑塞进一个组合选择器里。
推荐写法:
- 每个修饰符只负责单一视觉/行为维度:
.btn--loading控制图标旋转 +pointer-events: none;.btn--disabled控制透明度 + 文字颜色 - 叠加效果需显式声明:
.btn--loading.btn--disabled { opacity: 0.5; },而不是指望自动继承 - 禁止嵌套写法:
.btn--primary--disabled是非法命名,破坏 BEM 可预测性 - 尺寸类(
btn--small/btn--large)通常互斥,JS 中应做单选归一,而非布尔平铺
构建工具(如 PurgeCSS)为什么会删掉动态添加的修饰符
PurgeCSS 静态扫描 HTML 和 JS,若 btn--loading 只出现在 JS 的 classList.add() 里,没在任何模板或字符串字面量中出现,就会被判定为“未使用”而删除。
解决方案必须显式保留在 safelist 中:
- 正则匹配更可靠:
/btn--(loading|disabled|error)/ - 避免只写具体类名,否则新增状态要反复改配置
- 若用 Webpack + postcss-purgecss,safelist 配置项需在
content扫描范围之外单独声明
button--disabled 必须和 disabled 属性同步更新
只加 button--disabled 类却不设 disabled 属性,键盘用户仍能聚焦、回车触发,违反可访问性;反之,只设属性不加类,CSS 样式就失效。
正确同步逻辑:
btn.disabled = true; btn.classList.add('button--disabled');- 监听状态变化时,优先读取
btn.disabled值,再同步 class,而不是反过来 - 禁止写
.button--disabled:disabled这种冗余组合选择器
容易被忽略的是:SSR 渲染时,HTML 必须初始就带对的 class 和属性,否则 hydration 后状态不一致会导致闪烁或交互异常。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











