闪屏本质是主题CSS加载滞后导致的样式重绘——浏览器先渲染默认样式,再等新CSS下载、解析、应用,中间出现视觉断层。解决核心思路是:让目标主题的CSS资源在切换前就就绪,切换时只改class不等资源。

预加载所有主题CSS文件
把深色、浅色等主题的CSS都提前通过引入,用rel="preload"或rel="stylesheet"(配合media="print"或disabled属性)避免阻塞渲染,同时确保资源已缓存。
- 推荐写法:
- 或统一加载但初始禁用:
,切换时移除disabled并切换body class - 避免用@import或动态fetch+insertRule,它们无法被预加载且执行延迟高
切换时仅操作DOM class,不触发布局重排
确保主题CSS中所有选择器都基于一个顶层class(如.theme-dark),且不依赖属性选择器或JS内联样式。切换时只给html>或加/删class,浏览器直接复用已解析的规则。
- ✅ 正确示例:
document.documentElement.classList.toggle('theme-dark') - ❌ 错误做法:用JS逐个修改元素style.color等,触发强制同步布局
- 注意:CSS变量(:root { --bg: #fff; })也适用此方式,只需在对应class下重定义变量值
利用CSS媒体查询兜底系统偏好
用户首次访问时,用@media (prefers-color-scheme: dark)自动匹配系统主题,并配合JS同步设置初始class,避免白屏/黑屏等待。
- 在CSS中写:
@media (prefers-color-scheme: dark) { :root { --theme: 'dark'; } } - JS读取:
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';,立即设class - 这样用户打开页面瞬间就是目标主题,无过渡空白
可选:添加轻量级淡入过渡(非必需)
如果仍想视觉柔和,不用依赖CSS加载,而是用opacity过渡——初始body设opacity: 0,主题class就绪后10ms内渐显,全程不闪。
立即学习“前端免费学习笔记(深入)”;
- CSS中定义:
body { opacity: 0; transition: opacity 0.15s ease; } body.ready { opacity: 1; } - JS在DOM ready + 主题CSS加载完成后加ready类(可用document.fonts.load或link.sheet.cssRules检测)
- 注意:过渡时间别超过200ms,否则影响感知响应速度










