圖片
說難不難,說簡單也不簡單,這是一個無限循環的輪播效果,并且個數是固定的,你會如何實現呢?
原效果是通過vue的transition組件實現的,感覺有些笨重,思考了一番,發現純 CSS也能實現這樣的效果,而且性能更好,實現也更簡潔,一起來看看吧!
首先來分析一下思路??粗且粋€連貫的輪播效果,其實單獨看每一個子項,都是完全相同的運動軌跡。
圖片
然后是這個動畫,其實就是6個關鍵幀,逐一去位移和縮放,如下:
圖片
然后給每個子項不同的“負延遲”,是不是就剛好錯開,形成一個完整的輪播效果了呢?
無論CSS怎么實現,動畫原理就這些了,下面來看幾個實現方式
首先簡單布局一下,先用一個元素實現動畫;
<div class="item"></div>
加點修飾;
html,body{ font-family: -apple-system, "BlinkMacSystemFont", sans-serif; margin: 0; height: 100%; display: flex; justify-content: center; flex-direction: column; align-items: center; background: aliceblue; counter-reset: num;}.item{ position: absolute; display: grid; place-content: center; width: 100px; height: 100px; border-radius: 8px; background-color: #3E65FF; color: #fff; font-size: 30px; counter-increment: num;}
這里的數字是用CSS計數器生成的,效果如下:
圖片
根據前面的關鍵幀,很容易用代碼實現,就是。
.item{ animation: slide 12s infinite;}@keyframes slide { 0%,100% { transform: translate(0%, 0%) scale(1); } 16.67% { transform: translate(120%, -30%) scale(0.9); } 33.33% { transform: translate(100%, -70%) scale(0.8); } 50% { transform: translate(0, -90%) scale(0.7); } 66.67% { transform: translate(-100%, -70%) scale(0.8); } 83.33% { transform: translate(-120%, -30%) scale(0.9); }}
這里的16.67%關鍵幀是將100%進行6等分得到的,如下所示:
圖片
效果如下:
圖片
雖然有動畫了,但是效果有點奇怪,每次改變位置的時候好像沒有停頓,顯得過渡有些緩慢,只是有減速和加速的過程,這是默認的ease-in-out的淡入淡出緩沖效果。
那么,如何拉開一定的間隔呢?也就是希望每次運動的快一點,然后停留一會。其實也很簡單,在之前的每個關鍵點前再添加一個相同的關鍵幀,比如在16.67%的前面一點6.67%,由于是相同的,所以這段時間內是沒有動畫的,也就相當于停留了一會。
圖片
用代碼實現就是:
@keyframes slide { 0%,90%,100% { transform: translate(0%, 0%) scale(1); } 6.67%, 16.67% { transform: translate(120%, -30%) scale(0.9); } 23.33%, 33.33% { transform: translate(100%, -70%) scale(0.8); } 40%, 50% { transform: translate(0, -90%) scale(0.7); } 56.67%, 66.67% { transform: translate(-100%, -70%) scale(0.8); } 73.33%, 83.33% { transform: translate(-120%, -30%) scale(0.9); }}
這樣是不是就好多了?
圖片
實現了一個,多個子元素也就好辦了。
<div class="item" style="--i: 0"></div><div class="item" style="--i: 1"></div><div class="item" style="--i: 2"></div><div class="item" style="--i: 3"></div><div class="item" style="--i: 4"></div><div class="item" style="--i: 5"></div>
我們給每個子元素加個CSS變量,然后給每個動畫加個“負延遲”,讓這個動畫提前運行到指定位置;
.item{ animation: slide 12s calc(-2s * var(--i)) infinite;}
效果如下:
基本就實現這個這個輪播動畫,不過層級還有點問題。
所以還需要再關鍵幀里加入層級變化;
@keyframes slide { 0%,90%,100% { z-index: 4; transform: translate(0%, 0%) scale(1); } 6.67%, 16.67% { z-index: 3; transform: translate(120%, -30%) scale(0.9); } 23.33%, 33.33% { z-index: 2; transform: translate(100%, -70%) scale(0.8); } 40%, 50% { z-index: 1; transform: translate(0, -90%) scale(0.7); } 56.67%, 66.67% { z-index: 2; transform: translate(-100%, -70%) scale(0.8); } 73.33%, 83.33% { z-index: 3; transform: translate(-120%, -30%) scale(0.9); }}
這樣就完美了。
這種實現兼容性最好,只用到了 CSS 動畫,兼容市面所有瀏覽器,可以放心使用
其實目前來說,用上面這種方式就足夠了,沒有任何問題。
不過,上面對于中間停頓的處理方式可能有些繁瑣,下面再介紹另一種思路,可能更符合常規。
先思考一下,如果是用 JS要如何實現?是不是可以直接每隔2秒改變位移和縮放,然后通過transition實現過渡效果?
首先,我們還是需要像之前一樣,定義一些關鍵幀,不過不是直接改變位移和縮放,而是改變一些 CSS變量。
@keyframes slide { 0%,100% { --translate: 0,0; --scale: 1; --z: 4; } 16.67% { --translate: 120%,-30%; --scale: 0.9; --z: 3; } 33.33% { --translate: 100%,-70%; --scale: 0.8; --z: 2; } 50% { --translate: 0%,-90%; --scale: 0.7; --z: 1; } 66.67% { --translate: -100%,-70%; --scale: 0.8; --z: 2; } 83.33% { --translate: -120%,-30%; --scale: 0.9; --z: 3; }}
然后每個子項就需要用transfrom來應用這些變量了;
.item{ transform: translate(var(--translate)) scale(var(--scale)); transition: .5s transform; animation: slide 12s calc(-2s * var(--i)) infinite;}
我們來看看效果:
好像并沒有過渡動畫?這是因為animation覆蓋了transition,所以需要分離開來,我們嵌套一層父級。
<div class="item-wrap" style="--i: 0"> <div class="item"></div></div><div class="item-wrap" style="--i: 1"> <div class="item"></div></div><div class="item-wrap" style="--i: 2"> <div class="item"></div></div><div class="item-wrap" style="--i: 3"> <div class="item"></div></div><div class="item-wrap" style="--i: 4"> <div class="item"></div></div><div class="item-wrap" style="--i: 5"> <div class="item"></div></div>
然后將動畫寫在父級上;
.item-wrap{ animation: slide 12s calc(-2s * var(--i)) infinite; display: contents;}
這樣就不影響了,效果如下:
不過還是有點怪怪的。這是因為animation的默認效果也是ease-in-out,所以有這種漸入漸出的效果。我們需要瞬間變化,不需要過渡效果,因為過渡效果可以由transition完成。
這里我們可以用steps來實現,steps(1)表示直接切換,中間沒有任何過渡。
.item-wrap{ animation: slide 12s calc(-2s * var(--i)) steps(1) infinite;}
這樣效果就和前面基本一致了。
你也可以訪問以下鏈接來查看實際效果:
雖然里面沒有提到CSS @property,但實際上是依賴這個特性的,因此兼容性稍差,需要Safari 16.4+,Firefox目前還不支持。
拋開兼容性,其實還有一種方式可以實現,而且更容易理解,也更符合JS的思路。
我們要做的動畫很簡單,只需要改變一個 CSS變量就行,如下:
@property --index { syntax: "<number>"; initial-value: 0; inherits: false;}@keyframes slide { 0% { --index: 0; } 100% { --index: 6; }}
通過@property可以讓--index變量從0→6一次變化。
關于這個技巧,之前在多篇文章中都有提到。
你可能不需要 JS!CSS實現一個計時器。
如何讓CSS計數器支持小數的動態變化?
還在使用定時器嗎?CSS 也能實現電子時鐘。
動畫合成小技巧!CSS 實現動感的倒計時效果。
自定義計數器小技巧!CSS 實現長按點贊累積動畫。
實現如下:
.item-wrap{ display: contents; animation: slide 12s calc(-2s * var(--i)) steps(6) infinite;}
這樣就實現了一個--index不斷變化的動畫。
當然僅僅只是這樣還不夠,我們需要根據這個變量來匹配具體的樣式,這就要用到CSS樣式查詢了,具體實現如下:
@container style(--index: 0) { .item { transform: translate(0, 0) scale(1); z-index: 4; }}@container style(--index: 1) { .item { transform: translate(120%, -30%) scale(0.9); z-index: 3; }}@container style(--index: 2) { .item { transform: translate(100%, -70%) scale(0.8); z-index: 2; }}@container style(--index: 3) { .item { transform: translate(0, -90%) scale(0.7); z-index: 1; }}@container style(--index: 4) { .item { transform: translate(-100%, -70%) scale(0.8); z-index: 2; }}@container style(--index: 5) { .item { transform: translate(-120%, -30%) scale(0.9); z-index: 3; }}
這段應該很好理解,比如@container style(--index: 5) 表示,當查詢到--index為5的時候,下面的樣式就生效了,非常像通過 JS 來改變類名一樣,這種方式也能實現類似的效果。
你也可以訪問以下鏈接來查看實際效果:
由于要用到樣式查詢,所以兼容性更差一點,需要Chrome 111+,酌情使用。
以上就是本文的全部內容了,共介紹了3種不同的實現思路,兼容性從高到低,大家可以自行選擇。
對了,還有一點,有時候我們需要鼠標hover時暫停動畫,這個就體現出CSS的優勢了,直接用:hover實現,類似這樣
.wrap:hover .item{ animation-play-state: paused;}
下面總結一下實現要點:
本文鏈接:http://www.www897cc.com/showinfo-26-98557-0.htmlCSS 實現3d輪播圖的一些思路,你學會了嗎?
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: 六個常見的 Go 接口設計錯誤