在页面加载过程中,进度条的存在可以很好的缓解用户的等待焦虑。
但是你可能不知道,90%以上的进度条只是模拟的,是假的进度条。没办法,大部分情况下都无法真实的算出资源的加载情况。既然无法避免,那我们就需要尽可能真实地模拟加载情况,给人一种页面很轻快的感觉。
在这里,我们可以仅使用 CSS 来模拟一个比较真实的进度条加载,一起看看吧!
一、进度条加载和CSS缓冲动画
进度条的实现很简单,我们仅需要一个容器就行了,例如:
<divclass="progress"></div>
这里有两层结构,我们可以用一层伪元素来表示当前进度。
.progress{position: relative;width:300px;height:10px;margin:25px0;border-radius:10px;overflow: hidden;background-color:#E4CCFF;}.progress::before{position: absolute;content:'';width:0%;height:100%;background:#9747FF;}
这样我们就绘制了两层,可以通过改变::before的宽度来改变当前进度,要实现进度从0% -> 100%非常简单,只需要一个关键帧就行了。
.progress::before{animation: progress10s forwards;}@keyframes progress{to{width:100%}}
效果如下:
这是默认的缓冲效果,也就是ease。
这是一种先快后慢的运动效果,其实也基本符合我们的需求,至少比匀速要好很多,例如下面是ease和linear的对比,虽然总时长相同,但很明显ease给人的感觉更快。
为了便于区分是否完成,我们在最后一个进度将进度条变为绿色。
@keyframes progress{99%{background-color:#9747FF;}100%{background-color:#14AE5C;width:100%;}}
效果如下:
不过,仅仅是ease还不够,我们可以将起始速度调整的更快,这个可以通过cubic-bezier实现,比如这样一个曲线。
前半段速度足够快,后半段足够慢,几乎处于停止状态,下面来对比一下这3者的效果
是不是感觉这个进度条更快了呢?
二、使用 linear 实现更精细的进度控制
前面的cubic-bezier虽然能实现先快后面的效果,但整体还是比较单调,毕竟没什么细节。
实际的加载过程可能会受到网络环境的影响,速度时快时慢,甚至会在中途停止一小会,这种有什么办法模拟呢?当然也是有的,这需要借助全新的linear()函数。
简单来说,就是我们可以通过linear设置足够多的细节,来尽可能真实地模拟加载情况。
下面是我在Chrome控制台上随便加了十几个关键点,有些点前后纵向距离比较接近,就表示这段时间内运动的距离很短,也就是速度很慢,可以模拟出卡顿的感觉,你也可以根据自己或者设计的感觉加入更多的关键点。
下面来看一下这个缓冲效果和前面的对比。
是不是看着更像那么一回事了,有种网络不稳定的感觉?
不过,这个linear的兼容性还有点差,实际中可以做一下兼容,不支持的仍然可以用前面的cubic-ezier方式,类似于这样,毕竟是渐进增强而已。
.progress{--ease:cubic-bezier(.08,.81,.29,.99);}@supports(animation-timing-function:linear(0,1)){.progress{--ease:linear(00%,0.254.14%,0.5313.29%,0.6125.03%,0.7534.8%,0.8843.99%,0.9358.77%,0.9868.88%,0.9979.22%,188.79%,1100%);}}
三、主动完成进度条
大多数情况下,进度条只是一个过渡状态,不会真正等到进度条走完,我们可能在监听到某个关键资源加载成功或者某个功能初始化成功的实现就直接让进度条走完(1s内),这该如何处理呢?
直接替换肯定不行,那样就不够平滑了,动画也不够连贯。
这里有个非常巧妙的方式,也非常简单。
给进度条额外增加一个相同的动画,就是时间不一样,之前的是10s,新加的时长比较短,只有1s,默认情况下,只有前面的动画是执行的,后面的动画是暂停的,这里用一个单独的CSS变量来指定暂停状态,实现如下:
.progress::before{/*两个相同的动画,播放时长不同*/animation: progress10svar(--ease) forwards, progress1svar(--ease) forwards;animation-play-state:var(--running, running, paused);}
然后在某个时刻,资源加载完成的时候,改变一下播放状态,让前面的暂停,后面的开始播放,后面的动画时长只有1s
,所以很快就能完成,这里用点击事件来模拟加载完成。
btn.onclick=function(){document.body.style.setProperty('--running','paused, running')}
这样在点击之后,可以在1s内平滑地完成整个进度,效果如下:
还可以改变以下后面动画的缓冲效果,也就是在“立刻完成”之后,全部都用默认的ease,而不是和前面保持一致
.progress::before{position: absolute;content:'';width:0%;height:100%;background:#9747FF;animation: progressvar(--dur,10s)var(--ease) forwards, progress1s forwards;}
这样会不会更好一点呢?(“立即完成”后不应该有网络波动的感觉🤔)
以上完整代码可以查看以下demo
- CSS progress(codepen.io)[1]
四、总结一下
这样一个非常实用的进度条模拟小技巧,你学到了吗?下面总结一下
- 进度条可以用户的等待焦虑
- 大多数情况下无法真实的算出资源的加载情况,所以需要尽可能真实的模拟进度加载情况
CSS
动画默认的ease
是先快后面,给人一种加载快的感觉- 还可以通过
cubic-bezier
让初始速度更快 - 通过
linear
可以给进度添加更多细节,以便于模拟更复杂的加载情况 - 实际页面上进度条只是一个过渡状态,不会真正等到进度条走完,需要主动触发完成进度条
- 直接改成进度条状态不够平滑,动画也不够连贯
- 可以通过多动画,设置不同的动画时长,在真正需要完成的时候改变动画暂停状态,来实现主动完成进度加载
[1]CSS progress(codepen.io): https://codepen.io/xboxyan/pen/emOmazz