最稳纯CSS实现是用linear-gradient配合background-position动画模拟进度条拉满,通过position: relative容器与伪元素absolute覆盖,以background-position数值映射实现无缝左移,配合CSS变量--ui-loading-progress供JS接管,时长设2.5s匹配真实加载节奏,移动端加will-change优化帧率。

用 linear-gradient 模拟进度条拉满动画最稳
纯 CSS 实现“页面加载时进度条从 0% 拉到 100%”,本质不是监听真实加载,而是用一个可控的动画模拟视觉反馈。直接上 linear-gradient 配合 background-position 动画,比 JS 控制更轻、无阻塞、兼容性好(Chrome 26+ / Firefox 16+ / Safari 6.1+)。
常见错误是试图用 width 动画 + overflow: hidden,结果在 flex 容器或 transform 父级里错位、缩放失真;或者滥用 @keyframes 改变 background-size,导致边缘模糊或重绘抖动。
- 进度条容器必须设
position: relative,内部伪元素用position: absolute覆盖 - 动画用
background-position: 0% 0%, 100% 0%→background-position: -200% 0%, 0% 0%实现无缝左移拉满效果 - 别给伪元素加
border-radius再套动画——圆角会参与重绘,iOS Safari 上容易卡顿
:root 里定义加载状态变量,方便后期接入 JS 控制
虽然纯 CSS 能跑通基础动画,但真实项目里往往需要“加载完成就停住”或“出错时变红”。这时候不能删掉动画,而是在 :root 里预留 CSS 变量,让 JS 只需改一个值就能接管。
比如定义 --loading-progress: 0,再用 transition: background-position 0.3s ease-out 配合 JS 设置 document.documentElement.style.setProperty('--loading-progress', '100'),就能平滑终止动画。
立即学习“前端免费学习笔记(深入)”;
- 变量名别用
--progress这种太泛的,容易和第三方库冲突,推荐--ui-loading-progress - 不要在
@keyframes里直接引用变量(CSS 不支持),得靠background-position的数值映射来间接响应 - 如果用了 CSS-in-JS 库(如 Emotion),注意它可能把 :root 变量注入时机晚于动画触发,首次加载会闪一下
动画时间要匹配真实资源加载节奏,别硬写 1s
很多人设 animation-duration: 1s,结果首屏图片还没解码完,进度条已经跑到头了,用户觉得“假”。真正合理的做法是让动画总时长略长于预期最大加载耗时,再配合 JS 提前终止。
实测:Webpack 打包后首屏 JS/CSS 在 3G 网络下平均 1.8s 加载完,所以动画设 2.5s 更可信;若用 font-display: swap 加载字体,还要额外预留 0.3s。
- 别用
ease-in-out——开头太慢,用户没感知;推荐cubic-bezier(0.34, 1.1, 0.5, 1),前段加速明显,后段收得稳 - 移动端记得加
will-change: background-position,否则 iOS Safari 动画帧率可能掉到 30fps - 如果页面有 WebP 图片 fallback 到 JPEG,加载时间波动大,建议动画时长设成 3s,并允许 JS 在
load事件后 100ms 强制置 100%
兼容旧浏览器时,background-clip 替代方案更可靠
IE11 和部分安卓 4.x 浏览器不支持 background-position 动画的平滑插值,会一帧跳到终点。这时换用 background-clip: text + color 动画更稳妥,虽然只适用于文字型进度提示,但至少不崩。
原理是把进度条文字变成“镂空”,用渐变色背景透出来,再动 color 值控制显示范围——这个属性在老浏览器里动画支持度反而更好。
- 必须加
-webkit-background-clip: text和-webkit-text-fill-color: transparent双写 - 别用
rgba()渐变做背景,IE11 会渲染成纯黑;改用十六进制色值或hsl() - 这种方案无法做细条形进度,适合“Loading… 30%”这类带数字的提示,别硬套到顶部细横条上
img 的 load?还是等关键 API 返回?这个边界点一旦定错,再顺滑的动画也显得虚假。










