CSS变量在移动端Safari中动画不跑,根本原因是iOS Safari 15.6之前完全不解析@keyframes内var(),整条规则被静默丢弃;伪元素中变量晚一帧计算,calc()嵌套var()则常降级为0或忽略。

CSS 变量在移动端适配时不稳定,根本原因不是写法有误,而是不同系统、内核、WebView 版本对 --x 和 var(--x) 的解析能力差异极大——有些版本压根不识别,有些只支持静态定义,有些则在动画、伪元素、calc() 中静默失效。
为什么 @keyframes 里用 var(--x) 动画直接不跑
iOS Safari 15.6 之前完全不解析 var() 在 @keyframes 内部的使用。浏览器遇到 transform: translateX(var(--offset)) 这类声明,会直接丢弃整条 @keyframes 规则,不报错、不 fallback,结果就是加了动画类,元素纹丝不动。
- 必须把变量值提前内联为具体数值:
transform: translateX(42px),不能依赖 JS 注入后让 CSS 动态读取 - 若需 JS 控制动画参数,改用
element.animate()API(Safari 12.1+ 稳定支持) -
@-webkit-keyframes同样不认var(),双写无用
为什么伪元素(::before/::after)中 var(--x) 常失效
伪元素不自动继承父级的 CSS 变量作用域;更关键的是,Safari 对伪元素中 var() 的计算时机比 Chrome 晚一帧,首次渲染时可能取不到值,表现为背景色/尺寸短暂为空或回退到初始值。
- 不要只写
.box::before { background: var(--bg); },先加兜底:background: #f0f0f0; - 若变量由 JS 设置,设置后需触发一次强制重排,例如:
getComputedStyle(el).opacity; - 避免在伪元素里用
var()驱动transition或animation,Safari 会拒绝启动
为什么 calc(var(--gap) * 2) 在老 Safari 中算出 0
iOS 15.x 及更早 Safari 中,calc() 嵌套 var() 属于未完成支持的语法,常被当作无效表达式,降级为 calc(0 * 2) 或直接忽略整条声明——这不是你写错了单位,是解析器根本没走到计算那步。
立即学习“前端免费学习笔记(深入)”;
- 降级方案:用 JS 计算好值再写进
style属性,或用data-属性 + 属性选择器模拟 - 真需要响应式计算,优先用
clamp()+ 媒体查询组合(Safari 14.5+ 支持良好) - 别在关键布局中依赖它——老 Safari 会把它当无效值,退化成
auto,导致页面塌陷
为什么 JS 设置了 --vh,但高度还是不对
移动端地址栏收起、软键盘弹出、横竖屏切换都会改 window.innerHeight,但 CSS 变量不会自动更新。只在 DOMContentLoaded 里设一次 --vh,后续所有布局就基于那个过期值。
- 必须监听
resize(iOS 对orientationchange支持不稳定,resize更可靠);某些 iOS 版本地址栏收起时不触发resize,需额外监听scroll并节流 - JS 赋值必须带
px单位:document.documentElement.style.setProperty('--vh', `${window.innerHeight * 0.01}px`) - CSS fallback 必须双层:
height: 100dvh; height: calc(100 * var(--vh, 1px)); height: 100vh;——1vh不能作 fallback,会被忽略
真正容易被忽略的是:变量值本身没问题,但 Safari 对“变量何时可被读取”的判断极保守——它不等 JS 设置完就走 CSS 解析流程,也不重试。所以靠 JS 动态注入变量再指望 CSS 立即响应,在 Safari 里大概率失败。


















