移动端主题切换后样式不生效怎么办?
我用 CSS 变量做了个暗黑/亮色主题切换,本地测试没问题,但放到手机上切换后部分样式没变,比如 --primary-color 改了但按钮颜色还是老的。
试过强制重绘(比如加个 class 再删掉),也检查了媒体查询有没有冲突,但 iOS Safari 和某些安卓浏览器就是不更新。是不是 CSS 变量在移动端有兼容性问题?
这是我的主题切换代码:
function toggleTheme() {
const root = document.documentElement;
const current = root.getAttribute('data-theme');
const next = current === 'dark' ? 'light' : 'dark';
root.setAttribute('data-theme', next);
// 同步更新 CSS 变量
if (next === 'dark') {
root.style.setProperty('--bg-color', '#121212');
root.style.setProperty('--text-color', '#ffffff');
} else {
root.style.setProperty('--bg-color', '#ffffff');
root.style.setProperty('--text-color', '#000000');
}
}
你这段代码逻辑没问题,但问题出在:
你只改了
root.style.setProperty,但 CSS 里如果用了:root[data-theme="dark"] { --primary-color: ... }这种写法,那优先级比内联 style 高!移动端 Safari 尤其“倔”,它认准了属性选择器里的变量,不会因为 JS 改了内联 style 就覆盖掉。而且有些安卓机(特别是国产定制浏览器)对动态设置 CSS 变量的响应特别迟钝,甚至要等下一次重排才会更新,不是你设了就立刻生效的。
我后来用的稳妥方案是:
1. 主题切换只操作
data-theme属性,别在 JS 里直接 setProperty 变量2. 所有变量统一在 CSS 里用
:root[data-theme="xxx"]声明比如你 CSS 这样写:
JS 就简单点:
这样所有浏览器都认,连 iOS 12 老机都 OK。
要是你非得保留 JS 动态 setProperty(比如要支持主题色用户自定义),那得在 setProperty 后强制触发重排,比如:
但真不推荐这么搞,容易翻车。我之前项目就靠强制重排撑了三个月,后来某天安卓 10 的某机型突然不重排了,按钮颜色直接糊成一片……
还是老老实实用属性选择器最靠谱。
document.documentElement.style.setProperty的响应有延迟,尤其在页面滚动或动画频繁时容易卡住,CSS 变量没被及时重算,导致样式“看起来没更新”。你现在的写法其实没问题,但性能上不够激进——iOS 对
style.setProperty的处理是同步的,但重绘是异步的,某些场景下它会“偷懒”不重绘,特别是当元素已经被缓存了样式时。最快最稳的方案是:先删掉
data-theme属性,再加回去,强制浏览器认为“DOM 变了”,触发完整重绘链路。别用classList玩花活,直接操作属性更可靠。另外你代码里只改了
--bg-color和--text-color,但按钮颜色用的是--primary-color?确认下你是不是漏了这句:如果还是不行,加个微小的 DOM 操作兜底,比如:
void root.offsetWidth这行是经典 trick,读一次布局属性会触发同步重排,iOS Safari 就会乖乖重算 CSS 变量了。虽然听起来很土,但实测在 iPhone SE2 到 iPhone 15 上都稳。另外提醒一句:别在
data-theme和style.setProperty里混用变量,要么全用属性 + CSS 的:root[data-theme="dark"]选择器,要么全用 JS 动态设变量——混着用反而容易触发浏览器渲染 bug。