因为box-shadow不支持动画位移,需用position: absolute且z-index: 1的::after伪元素模拟动态光刷;ios需will-change或改用真实子元素+filter解决渲染降级。

为什么直接给 .progress-fill 加 box-shadow 不出光晕?
因为发光光晕需要“移动感”,静态阴影只是停在原地发亮,没有扫描、掠过或呼吸的动态节奏。浏览器渲染时,box-shadow 本身不支持动画位移(left/top 对它无效),所以必须借助能动的载体——::after 伪元素,把它当成一个独立的“光刷”,靠 left + animation 拉着它横向扫过进度条内部。
::after 光晕层必须设 position: absolute 和 z-index
否则它会脱离文档流错位,或被父容器背景盖住,导致光晕不可见。常见错误包括:
- 忘记给父容器(如
.progress-fill)设position: relative,导致::after相对于 body 定位,飘到页面任意角落 - 没写
z-index: 1,而进度条背景用了background-image或深色渐变,把光晕压在底下 - 用
width: 100%但没配合transform-origin: left,动画起始点偏移,第一帧就漏光
光晕动画的关键参数:时长、方向、重复与 easing
要模拟“扫描式”光效,不是匀速来回,而是单向快速掠过再重置。推荐这样写:
@keyframes sweep {
0% { left: -100%; opacity: 0.6; }
50% { left: 100%; opacity: 0.9; }
100% { left: 200%; opacity: 0.3; }
}
.progress-fill::after {
content: "";
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: radial-gradient(circle at 30% 50%, rgba(255,255,255,0.8), transparent 70%);
animation: sweep 2.4s ease-out infinite;
}
注意点:
- 动画总时长建议在 2–3 秒之间:太短像闪屏,太长失去“动态”感
- 用
ease-out而非linear,让光晕入画轻快、出画放缓,更接近真实光学扫掠 - 起始
left: -100%确保每次循环都从左侧外进入,避免衔接跳帧 - 别用
infinite却不设animation-delay—— 多个进度条同时动会显得机械同步,加随机延迟更自然
移动端 iOS Safari 上光晕“断连”或“变暗”的修复
部分 iOS 版本(尤其是 iOS 16+)会对 ::after 的 opacity 和 radial-gradient 做渲染降级,尤其当父元素有 transform: scaleX() 时。解决方法很具体:
- 把光晕层从
::after换成真实子元素(如<span class="glow"></span>),绕过伪元素限制 - 改用
filter: blur(2px)配合纯白background-color,比radial-gradient更稳定 - 强制开启硬件加速:
will-change: transform;加在.progress-fill上,唤醒 GPU 渲染通道 - 避免在
@keyframes中同时修改left和opacity—— 分拆成两个动画,或只动left,用background的 alpha 通道控制明暗
真正难的不是写出光晕,而是让它在 Chrome、Safari、WebView 里看起来一致——多数人卡在 iOS 上那一帧“突然变灰”的瞬间,其实就差一个 will-change 或一次 radial-gradient 的 fallback 替换。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











