iOS暗黑模式切换不触发CSS变量重算,必须用prefers-color-scheme媒体查询配合:root级变量定义和color-scheme: light dark声明,否则原生控件错乱;变量须全在:root定义,不能嵌套或放于.dark类中。

直接说结论:iOS暗黑模式切换本身不触发CSS变量重算,prefers-color-scheme媒体查询是唯一可靠入口,但必须配合:root级变量定义 + color-scheme: light dark声明,否则原生控件(如<input>、滚动条)会错乱或失色。
为什么iOS上prefers-color-scheme有时不生效
iOS Safari(尤其是iOS 15–16)对@media (prefers-color-scheme: dark)的响应有延迟或静默失败,常见于页面已加载后系统手动切模式。根本原因不是媒体查询失效,而是变量未在:root中正确定义或被低优先级规则覆盖。
- 变量必须全部写在
:root里,不能放在.dark类或body中——否则继承链断裂,var(--bg)fallback 到初始值甚至透明 - 不要用嵌套写法:
@media (prefers-color-scheme: dark) { :root { --bg: #000; } }在旧版Safari中可能被忽略;应拆成两个独立:root块 - 必须加
color-scheme: light dark到:root或html,否则iOS不会自动适配表单控件、<select></select>下拉箭头、滚动条轨道等原生元素
color-scheme不是可选项,是iOS暗黑模式的通行证
color-scheme本身不改颜色,但它告诉WebKit:“我支持双模式,请把系统级暗色样式注入原生控件”。漏掉这行,哪怕CSS变量全对,<input type="date">依然白底黑字、滚动条还是亮色。
- 写法必须是
:root { color-scheme: light dark; },不能只写dark,否则亮色模式下原生控件可能异常 - 它不影响自定义样式,只作用于浏览器默认渲染的UI部件
- 不支持
!important,也不接受变量(var(--scheme)无效)
iOS上localStorage同步比桌面端更关键
iOS Safari在后台标签页或冷启动时,matchMedia('(prefers-color-scheme: dark)')可能返回matches: false,即使系统设为暗色——这是WebKit已知行为。用户手动切换一次后,媒体查询才“醒来”。
立即学习“前端免费学习笔记(深入)”;
- 初始化时必须三步并行:
localStorage.getItem('theme')→ 无则 fallback 到matchMedia→ 立即设置document.documentElement.setAttribute('data-theme', ...) - 不能等
DOMContentLoaded再操作class,否则首屏闪白/闪黑;<script></script>应放在内,直接操作document.documentElement - 监听系统变化要用
matchMedia().addEventListener('change', ...),iOS 16+才支持,iOS 15需降级为轮询(每500ms查一次matches)
最易被忽略的一点:iOS上transition必须写在具体使用变量的元素上,比如body { background-color: var(--bg); transition: background-color 0.3s; }。在:root里写transition: --bg 0.3s完全无效——变量本身不可动画,这点和所有浏览器一致,但在iOS上因重绘节奏不同,更容易看出“啪”一下切换的割裂感。


















