CSS 如何模擬“真實”的進度條?
在頁面加載過程中,進度條的存在可以很好的緩解用戶的等待焦慮。
但是你可能不知道,90%以上的進度條只是模擬的,是假的進度條。沒辦法,大部分情況下都無法真實的算出資源的加載情況。既然無法避免,那我們就需要盡可能真實地模擬加載情況,給人一種頁面很輕快的感覺。
在這里,我們可以僅使用 CSS 來模擬一個比較真實的進度條加載,一起看看吧!
一、進度條加載和CSS緩沖動畫
進度條的實現(xiàn)很簡單,我們僅需要一個容器就行了,例如:
<divclass="progress"></div>
這里有兩層結(jié)構(gòu),我們可以用一層偽元素來表示當前進度。
.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的寬度來改變當前進度,要實現(xiàn)進度從0% -> 100%非常簡單,只需要一個關(guān)鍵幀就行了。
.progress::before{animation: progress10s forwards;}@keyframes progress{to{width:100%}}
效果如下:
這是默認的緩沖效果,也就是ease。
這是一種先快后慢的運動效果,其實也基本符合我們的需求,至少比勻速要好很多,例如下面是ease和linear的對比,雖然總時長相同,但很明顯ease給人的感覺更快。
為了便于區(qū)分是否完成,我們在最后一個進度將進度條變?yōu)榫G色。
@keyframes progress{99%{background-color:#9747FF;}100%{background-color:#14AE5C;width:100%;}}
效果如下:
不過,僅僅是ease還不夠,我們可以將起始速度調(diào)整的更快,這個可以通過cubic-bezier實現(xiàn),比如這樣一個曲線。
前半段速度足夠快,后半段足夠慢,幾乎處于停止狀態(tài),下面來對比一下這3者的效果
是不是感覺這個進度條更快了呢?
二、使用 linear 實現(xiàn)更精細的進度控制
前面的cubic-bezier雖然能實現(xiàn)先快后面的效果,但整體還是比較單調(diào),畢竟沒什么細節(jié)。
實際的加載過程可能會受到網(wǎng)絡(luò)環(huán)境的影響,速度時快時慢,甚至?xí)谥型就V挂恍?,這種有什么辦法模擬呢?當然也是有的,這需要借助全新的linear()函數(shù)。
簡單來說,就是我們可以通過linear設(shè)置足夠多的細節(jié),來盡可能真實地模擬加載情況。
下面是我在Chrome控制臺上隨便加了十幾個關(guān)鍵點,有些點前后縱向距離比較接近,就表示這段時間內(nèi)運動的距離很短,也就是速度很慢,可以模擬出卡頓的感覺,你也可以根據(jù)自己或者設(shè)計的感覺加入更多的關(guān)鍵點。
下面來看一下這個緩沖效果和前面的對比。
是不是看著更像那么一回事了,有種網(wǎng)絡(luò)不穩(wěn)定的感覺?
不過,這個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%);}}
三、主動完成進度條
大多數(shù)情況下,進度條只是一個過渡狀態(tài),不會真正等到進度條走完,我們可能在監(jiān)聽到某個關(guān)鍵資源加載成功或者某個功能初始化成功的實現(xiàn)就直接讓進度條走完(1s內(nèi)),這該如何處理呢?
直接替換肯定不行,那樣就不夠平滑了,動畫也不夠連貫。
這里有個非常巧妙的方式,也非常簡單。
給進度條額外增加一個相同的動畫,就是時間不一樣,之前的是10s,新加的時長比較短,只有1s,默認情況下,只有前面的動畫是執(zhí)行的,后面的動畫是暫停的,這里用一個單獨的CSS變量來指定暫停狀態(tài),實現(xiàn)如下:
.progress::before{/*兩個相同的動畫,播放時長不同*/animation: progress10svar(--ease) forwards, progress1svar(--ease) forwards;animation-play-state:var(--running, running, paused);}
然后在某個時刻,資源加載完成的時候,改變一下播放狀態(tài),讓前面的暫停,后面的開始播放,后面的動畫時長只有1s
,所以很快就能完成,這里用點擊事件來模擬加載完成。
btn.onclick=function(){document.body.style.setProperty('--running','paused, running')}
這樣在點擊之后,可以在1s內(nèi)平滑地完成整個進度,效果如下:
還可以改變以下后面動畫的緩沖效果,也就是在“立刻完成”之后,全部都用默認的ease,而不是和前面保持一致
.progress::before{position: absolute;content:'';width:0%;height:100%;background:#9747FF;animation: progressvar(--dur,10s)var(--ease) forwards, progress1s forwards;}
這樣會不會更好一點呢?(“立即完成”后不應(yīng)該有網(wǎng)絡(luò)波動的感覺??)
以上完整代碼可以查看以下demo
- CSS progress(codepen.io)[1]
四、總結(jié)一下
這樣一個非常實用的進度條模擬小技巧,你學(xué)到了嗎?下面總結(jié)一下
- 進度條可以用戶的等待焦慮
- 大多數(shù)情況下無法真實的算出資源的加載情況,所以需要盡可能真實的模擬進度加載情況
CSS
動畫默認的ease
是先快后面,給人一種加載快的感覺- 還可以通過
cubic-bezier
讓初始速度更快 - 通過
linear
可以給進度添加更多細節(jié),以便于模擬更復(fù)雜的加載情況 - 實際頁面上進度條只是一個過渡狀態(tài),不會真正等到進度條走完,需要主動觸發(fā)完成進度條
- 直接改成進度條狀態(tài)不夠平滑,動畫也不夠連貫
- 可以通過多動畫,設(shè)置不同的動畫時長,在真正需要完成的時候改變動畫暫停狀態(tài),來實現(xiàn)主動完成進度加載
[1]CSS progress(codepen.io): https://codepen.io/xboxyan/pen/emOmazz