transition 必须作用于原生可动画属性(如 background-color),不能用于自定义属性;需在默认状态而非 .dark 类中声明;class 必须在 DOM 解析前同步挂载,否则首屏闪白。

直接加 transition 不行,必须写对位置、选对属性、填对值——否则切换就是闪一下,不是渐变。
为什么 transition: --bg-color 0.3s 完全无效
CSS 规范不支持对自定义属性做插值动画。浏览器看到这行就直接忽略,既不报错也不执行。所谓“变量过渡”是误解,--bg-color 只是占位符,真正参与渲染和动画的是它被替换后的具体值(比如 #ffffff → #121212)。
-
transition必须作用于原生可动画属性:background-color、color、border-color、opacity等 - 两端值都得是明确的、可插值的颜色,避免用
transparent或inherit,否则可能中途跳变 - 不能只在
.dark类里写transition,必须放在默认状态规则中(比如body或:root下的通用选择器)
transition 必须写在默认状态,而不是 .dark 类里
很多人把 transition 只塞进 .dark { transition: ... },结果第一次点击切换时还是闪——因为浏览器从“无过渡”跳到“有过渡”,第一帧没缓动逻辑。
- 正确写法示例:
body { background-color: #ffffff; color: #333; transition: background-color 0.35s ease-in-out, color 0.35s ease-in-out; } -
.dark类只负责提供目标值:background-color: #121212; color: #e0e0e0; - 所有参与过渡的属性,在默认态和
.dark态都必须写死具体值,不能留空或用initial
用 CSS 变量时,transition 得落到具体元素上
如果你用 :root 声明 --bg-color,再在 body { background-color: var(--bg-color); } 中引用,那 transition 就不能只写在 :root,而要写在 body 或其他实际使用该变量的元素上。
立即学习“前端免费学习笔记(深入)”;
- 变量更新是原子性的,浏览器不会为变量变化触发重绘;只有当引用变量的属性值改变时,才可能触发动画
- 所以
body要同时满足:有transition声明 + 默认态和.dark态下background-color都是可插值颜色 - 推荐时长范围:300–450ms;
ease-in-out比ease更柔和,适合主题切换
首屏不闪的关键:class 必须在 DOM 解析前就挂上
哪怕 CSS 和 JS 写得再准,如果 document.documentElement.classList.add('dark') 是等 DOMContentLoaded 后才执行,iOS Safari 和 Android WebView 就大概率闪一下白屏。
- 必须在
<head>里内联轻量 JS,用matchMedia('(prefers-color-scheme: dark)')同步检测 - 立即读取
localStorage.getItem('theme'),并同步设置document.documentElement.classList - 切换按钮的 JS 只负责
classList.toggle('dark')和存localStorage,别掺和样式计算
最易被忽略的不是“怎么写 transition”,而是“谁来触发重绘”和“什么时候挂 class”。漏掉初始化时机或过渡声明位置,再漂亮的颜色值也出不来渐变。


















