:hover不监听CSS变量变更,因浏览器仅缓存一次样式计算结果;需通过offsetHeight触发回流强制重算,Safari等需配合@media (hover: hover) and (pointer: fine)兜底。

伪类:hover不监听CSS变量变更
因为浏览器在匹配 :hover 时,只做一次样式计算并缓存结果,不会订阅 --color-primary 这类自定义属性的变化。你调用 document.documentElement.style.setProperty('--color-primary', '#ff6b6b') 后,正常态颜色立刻更新,但已渲染的 .btn:hover 规则仍用着旧变量快照——不是没生效,是压根没重跑伪类匹配逻辑。
强制重绘才能让:hover拿到新变量值
最简可行方案是触发回流,让浏览器重新评估所有选择器:
- 给按钮加稳定 class,比如
btn-action,hover 样式写成.btn-action:hover - JS 更新变量后立即执行:
btn.classList.remove('btn-action'); btn.offsetHeight; btn.classList.add('btn-action'); -
offsetHeight是关键:它强制同步回流,迫使样式系统丢弃缓存、重新计算:hover下的变量值 - 别用
display: none切换 class,用户正悬停时会闪一下,且可能丢失状态
移动端或旧版 Safari 需额外兜底
部分 Safari 版本对 :hover + CSS 变量 组合支持极弱,即使强制重绘也可能不生效。此时建议:
- 把依赖变量的 hover 样式包进
@media (hover: hover) and (pointer: fine),排除触控设备 - 为按钮同时提供
:active样式作为移动端 fallback,确保点击反馈不丢 - 避免在关键路径(如主操作按钮)上纯靠变量驱动 hover,可预设几套主题 class 直接切换
真正难的不是怎么改变量,而是怎么让浏览器“意识到”该重算 —— 它藏在那一行 offsetHeight 里,也藏在你忘了给媒体查询加 pointer: fine 的那个括号里。
立即学习“前端免费学习笔记(深入)”;


















