应优先使用 className 或 classList 切换 CSS 类名,而非直接修改选择器规则或内联样式;因前者保持样式层分离、支持伪类/媒体查询/主题系统,且性能可控、易于维护。

直接修改CSS选择器规则会破坏样式层分离原则
浏览器不提供标准 API 让 JS 直接增删或重写 .btn:hover、#header .nav-item 这类已存在的 CSS 选择器规则。所谓“动态修改选择器”,实际是绕道操作:比如用 document.styleSheets 遍历规则再调用 insertRule/deleteRule,但该方式存在严重限制——insertRule 只能在同源的内联 <style> 或已加载的 <link> 样式表中生效,且跨域样式表、某些 CSP 策略下会静默失败。
className 和 classList 是可控、可预测的样式切换入口
切换 class 名本质是触发浏览器的样式重计算(recalculate),而非重排(reflow),性能开销小;同时所有样式定义仍保留在 CSS 文件中,便于维护、压缩、缓存和 SSR 支持。
-
element.className = "active"会完全覆盖原有 class,适合单状态强控制场景 -
element.classList.add("loading")和element.classList.toggle("disabled")更安全,不干扰其他类名 - 多个条件组合时,推荐用
classnames库生成字符串,避免手拼出"btn btn-primary " + (loading ? "btn-loading" : "") + " " + (disabled ? "btn-disabled" : "")这类易错逻辑
用 style 属性或 setAttribute("style", ...) 容易覆盖伪类和响应式断点
内联样式优先级最高,一旦写入 element.style.backgroundColor = "red",就会压制 :hover、@media (max-width: 768px) 等所有外部定义的交互与适配样式。常见现象包括:
- 按钮悬停无变色
- 移动端视口缩放后布局错乱
- 暗色模式媒体查询失效
而 class 切换天然继承 CSS 层叠逻辑,.btn.dark:hover 依然有效。
立即学习“前端免费学习笔记(深入)”;
主题切换等复杂场景依赖 class 层级结构
现代主题系统(如 dark/light)普遍采用 document.documentElement.setAttribute("data-theme", "dark") 配合 CSS 自定义属性(:root[data-theme="dark"] { --bg: #1a1a1a; })。这种方案必须以 class 或 data 属性为锚点,靠选择器作用域来批量控制样式。若强行用 JS 去逐个改 DOM 元素的 style.color,不仅代码量爆炸,还会丢失 CSS 变量的响应式联动能力。
真正难的不是“怎么切”,而是“切在哪一层”——class 是样式系统的契约接口,不是临时补丁。漏掉这点,后期维护成本会指数上升。


















