css选择器不生效的根本原因是class操作节点与选择器主体不匹配:若规则为html.dark或:root.dark,必须操作document.documentelement;若为body.dark,则操作document.body。

直接操作 class 属性是前端最常用、也最容易出错的基础动作——它不难,但错一点,CSS 就不生效、JS 就查不到、主题就切不动。
为什么 document.body.classList.toggle('dark') 有时完全没反应
因为你的 CSS 规则可能写的是 html.dark 或 :root.dark,而你却在 body 上加 class。浏览器只认选择器匹配的节点:规则绑 html,就必须操作 document.documentElement;规则绑 body,才轮到 document.body。翻控制台看元素上到底有没有 class,再对照 CSS 文件第一行的选择器前缀,比猜快十倍。
- 检查现有 CSS 主题规则:搜
html.dark、body.dark、:root.dark,看哪个真实存在 - 统一锚点:建议全项目锁定
document.documentElement,它覆盖伪元素、CSS 变量、第三方组件更稳 - 别信“默认就是 body”——Bootstrap 4 的暗色模式文档写的是
body.dark,但 Bootstrap 5+ 已转向html.dark
classList.add() 和 className = 'xxx' 的区别不只是写法问题
className = 'active' 是暴力赋值,会清空所有已有 class;classList.add('active') 是原子追加,不影响其他类。一个按钮原本有 btn btn-primary u-mt-2,用 className 赋值后只剩 active,样式全崩。
- 永远优先用
classList系列 API:add()、remove()、toggle()、contains() -
toggle()适合二元切换,但别裸用——它不感知 localStorage 或服务端初始状态,容易和用户手动改 storage 冲突 - 需要状态确定性时,先
contains('dark')判断,再显式add()/remove(),同步更新localStorage
class 名里带数字或下划线,为什么 CSS 选不到、JS 查不到
HTML 规范允许 class 值含下划线(如 user_profile),但某些 SSR 框架或旧版 IE 会截断或转义失败;数字开头(如 1col)则直接让 CSS 选择器失效——.1col 不是合法选择器,浏览器解析时会跳过整条规则。
- 必须用 kebab-case(小写+连字符):
main-nav、form-group、modal-backdrop - 数字可出现在中间或结尾:
cols-3、step-2✅,但不能开头:3col❌ - JS 中用
document.querySelector('.user-profile'),注意点号后必须严格匹配 class 字符串,大小写敏感
多个 class 同时用,为什么有的样式不生效
不是 class 写多了就叠加生效,而是 CSS 特异性(specificity)和层叠顺序在起作用。.btn.primary 和 .btn--large 没冲突,但若两者都定义了 padding,谁权重高谁赢;如果还混入 style="padding: 0",内联样式优先级最高,直接干掉 class 定义。
- 避免靠堆 class 提高权重:
.btn.btn.btn和.btn权重完全一样(都是 0-1-0) - 工具类(如
u-p-4)一旦引入,就要接管全部间距逻辑,别让它和.card { padding: 1rem }共存 - 调试时右键「检查元素」→ 看「Computed」面板,找哪条 padding 被 strike-through 了,点开来源就能定位冲突规则
class 不是样式快照,它是语义锚点;改 class 时,你真正改的是 CSSOM 中的选择器匹配关系和 JS 对 DOM 的引用路径——稍不留意,就变成“代码写了,页面没变,控制台也没报错”的隐形故障。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











