
今天,分享一個實(shí)際業(yè)務(wù)中能夠用得上的動畫技巧。
巧用逐幀動畫,配合補(bǔ)間動畫實(shí)現(xiàn)一個無限循環(huán)的輪播效果,像是這樣:

看到上述示意圖,有同學(xué)不禁會發(fā)問,這不是個非常簡單的位移動畫么?
我們來簡單分析分析,從表面上看,確實(shí)好像只有元素的 transform: translate() 在位移,但是注意,這里有兩個難點(diǎn):
到這里,你可以暫停思考一下,如果有 20 個元素,需要進(jìn)行類似的無限輪播播報,使用 CSS 實(shí)現(xiàn),你會怎么去做呢?
首先,我需要利用到逐幀動畫效果,也被稱為步驟緩動函數(shù),利用的是 animation-timing-function 中,的 steps,語法如下:
{ /* Keyword values */ animation-timing-function: step-start; animation-timing-function: step-end; /* Function values */ animation-timing-function: steps(6, start) animation-timing-function: steps(4, end);}如果你對 steps 的語法還不是特別了解,強(qiáng)烈建議你先看看我的這篇文章 -- 深入淺出 CSS 動畫[1],它對理解本文起著至關(guān)重要的作用。
好的,還是文章以開頭的例子,假設(shè)我們存在這樣 HTML 結(jié)構(gòu):
<div class="g-container"> <ul> <li>Lorem ipsum 1111111</li> <li>Lorem ipsum 2222222</li> <li>Lorem ipsum 3333333</li> <li>Lorem ipsum 4444444</li> <li>Lorem ipsum 5555555</li> <li>Lorem ipsum 6666666</li> </ul></div>首先,我們實(shí)現(xiàn)這樣一個簡單的布局:

在這里,要實(shí)現(xiàn)輪播效果,并且是任意個數(shù),我們可以借助 animation-timing-function: steps():
:root { // 輪播的個數(shù) --s: 6; // 單個 li 容器的高度 --h: 36; // 單次動畫的時長 --speed: 1.5s;}.g-container { width: 300px; height: calc(var(--h) * 1px);}ul { display: flex; flex-direction: column; animation: move calc(var(--speed) * var(--s)) steps(var(--s)) infinite;}ul li { width: 100%;}@keyframes move { 0% { transform: translate(0, 0); } 100% { transform: translate(0, calc(var(--s) * var(--h) * -1px)); }}別看到上述有幾個 CSS 變量就慌了,其實(shí)很好理解:
上述的效果,實(shí)際如下:

如果給容器添加上 overflow: hidden,就是這樣的效果:

這樣,我們就得到了整體的結(jié)構(gòu),至少,整個效果是循環(huán)的。
但是由于只是逐幀動畫,所以只能看到切換,但是每一幀之間,沒有過渡動畫效果。所以,接下來,我們還得引入補(bǔ)間動畫。
我們需要利用補(bǔ)間動畫,實(shí)現(xiàn)動態(tài)的切換效果。
這一步,其實(shí)也非常簡單,我們要做的,就是將一組數(shù)據(jù),利用 transform,從狀態(tài) A 位移到 狀態(tài) B。
單獨(dú)拿出一個來演示的話,大致的代碼如下:
<div class="g-container"> <ul style="--s: 6"> <li>Lorem ipsum 1111111</li> <li>Lorem ipsum 2222222</li> <li>Lorem ipsum 3333333</li> <li>Lorem ipsum 4444444</li> <li>Lorem ipsum 5555555</li> <li>Lorem ipsum 6666666</li> </ul></div>:root { --h: 36; --speed: 1.2s;}ul li { height: 36px; animation: liMove calc(var(--speed)) infinite;}@keyframes liMove { 0% { transform: translate(0, 0); } 80%, 100% { transform: translate(0, -36px); }}非常簡單的一個動畫:

bgg1
基于上述效果,我們?nèi)绻岩婚_始提到的 逐幀動畫 和這里這個 補(bǔ)間動畫 結(jié)合一下,ul 的整體移動,和 li 的 單個移動疊在在一起:
:root { // 輪播的個數(shù) --s: 6; // 單個 li 容器的高度 --h: 36; // 單次動畫的時長 --speed: 1.5s;}.g-container { width: 300px; height: calc(var(--h) * 1px);}ul { display: flex; flex-direction: column; animation: move calc(var(--speed) * var(--s)) steps(var(--s)) infinite;}ul li { width: 100%; animation: liMove calc(var(--speed)) infinite;}@keyframes move { 0% { transform: translate(0, 0); } 100% { transform: translate(0, calc(var(--s) * var(--h) * -1px)); }}@keyframes liMove { 0% { transform: translate(0, 0); } 80%, 100% { transform: translate(0, calc(var(--h) * -1px)); }}就能得到這樣一個效果:

Wow,神奇的化學(xué)反應(yīng)產(chǎn)生了!基于 逐幀動畫 和 補(bǔ)間動畫 的結(jié)合,我們幾乎實(shí)現(xiàn)了一個輪播效果。
當(dāng)然,有一點(diǎn)瑕疵,可以看到,最后一組數(shù)據(jù),是從第六組數(shù)據(jù) transform 移動向了一組空數(shù)據(jù):

實(shí)際開發(fā)過輪播的同學(xué)肯定知道,這里,其實(shí)也很好處理,我們只需要在末尾,補(bǔ)一組頭部的第一個數(shù)據(jù)即可:
改造下我們的 HTML:
<div class="g-container"> <ul> <li>Lorem ipsum 1111111</li> <li>Lorem ipsum 2222222</li> <li>Lorem ipsum 3333333</li> <li>Lorem ipsum 4444444</li> <li>Lorem ipsum 5555555</li> <li>Lorem ipsum 6666666</li> <!--末尾補(bǔ)一個首條數(shù)據(jù)--> <li>Lorem ipsum 1111111</li> </ul></div>這樣,我們再看看效果:

Beautiful!如果你還有所疑惑,我們給容器加上 overflow: hidden,實(shí)際效果如下,通過額外添加的最后一組數(shù)據(jù),我們的整個動畫剛好完美的銜接上,一個完美的輪播效果:

完整的代碼,你可以戳這里:CodePen Demo -- Vertical Infinity Loop[2]
當(dāng)然,實(shí)現(xiàn)了豎直方向的輪播,橫向的效果也是一樣的。
并且,我們可以通過在 HTML 結(jié)構(gòu)中,通過 style 內(nèi)填寫 CSS 變量值,傳入實(shí)際的 li 個數(shù),以達(dá)到根據(jù)不同 li 個數(shù)適配不同動畫:
<div class="g-container"> <ul style="--s: 6"> <li>Lorem ipsum 1111111</li> <li>Lorem ipsum 2222222</li> <li>Lorem ipsum 3333333</li> <li>Lorem ipsum 4444444</li> <li>Lorem ipsum 5555555</li> <li>Lorem ipsum 6666666</li> <!--末尾補(bǔ)一個首尾數(shù)據(jù)--> <li>Lorem ipsum 1111111</li> </ul></div>整個動畫的 CSS 代碼基本是一致的,我們只需要改變兩個動畫的 transform 值,從豎直位移,改成水平位移即可:
:root { --w: 300; --speed: 1.5s;}.g-container { width: calc(--w * 1px); overflow: hidden;}ul { display: flex; flex-wrap: nowrap; animation: move calc(var(--speed) * var(--s)) steps(var(--s)) infinite;}ul li { flex-shrink: 0; width: 100%; height: 100%; animation: liMove calc(var(--speed)) infinite;}@keyframes move { 0% { transform: translate(0, 0); } 100% { transform: translate(calc(var(--s) * var(--w) * -1px), 0); }}@keyframes liMove { 0% { transform: translate(0, 0); } 80%, 100% { transform: translate(calc(var(--w) * -1px), 0); }}這樣,我們就輕松的轉(zhuǎn)化為了橫向的效果:

完整的代碼,你可以戳這里:CodePen Demo -- Horizontal Infinity Loop[3]
OK,上面的只是文字版的輪播,那如果是圖片呢?
沒問題,方法都是一樣的?;谏鲜龅拇a,我們可以輕松地將它修改一下后得到圖片版的輪播效果。
代碼都是一樣的,就不再列出來,直接看看效果:


完整的代碼,你可以戳這里:CodePen Demo -- Horizontal Image Infinity Loop[4]
掌握了這個技巧之后,你可以將它運(yùn)用在非常多只需要簡化版的輪播效果之上。
再簡單總結(jié)一下,非常有意思的技巧:
OK,本文到此結(jié)束,希望本文對你有所幫助 :)
[1]深入淺出 CSS 動畫: https://github.com/chokcoco/iCSS/issues/141
[2]CodePen Demo -- Vertical Infinity Loop: https://codepen.io/Chokcoco/pen/RwQVByx
[3]CodePen Demo -- Horizontal Infinity Loop: https://codepen.io/Chokcoco/pen/JjpNBXY
[4]CodePen Demo -- Horizontal Image Infinity Loop: https://codepen.io/Chokcoco/pen/GRQvqgq
[5]Github -- iCSS: https://github.com/chokcoco/iCSS
本文鏈接:http://m.www897cc.com/showinfo-26-78144-0.html動畫進(jìn)階 | CSS 也能實(shí)現(xiàn)完美的文字輪播與圖片輪播效果
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com