上一篇文章中,我們製作了一個非常酷炫的小型滑塊(或者如果您更喜歡的話,可以稱之為“旋轉木馬”),它以圓形方向旋轉。這次,我們將製作一個可以翻閱寶麗來圖片堆棧的滑塊。
很酷吧?先別看代碼,因為有很多東西需要解釋。加入我吧?
此滑塊的大部分HTML和CSS與我們上次製作的圓形滑塊類似。事實上,我們使用的是完全相同的標記:
<code><div> <img alt="" src=""><img alt="" src=""><img alt="" src=""><img alt="" src=""> </div></code>
這是基本的CSS,它將我們的父級.gallery
容器設置為網格,所有圖像都在彼此之上堆疊:
<code>.gallery { display: grid; width: 220px; /* 控制大小 */ } .gallery > img { grid-area: 1 / 1; width: 100%; aspect-ratio: 1; object-fit: cover; border: 10px solid #f2f2f2; box-shadow: 0 0 4px #0007; }</code>
到目前為止,沒有什麼複雜的。即使對於寶麗來風格的圖像,我使用的也只是邊框和陰影。您可能能夠做得更好,因此請隨意嘗試這些裝飾樣式!我們將把大部分精力放在動畫上,這是最棘手的部分。
此滑塊的邏輯依賴於圖像的堆疊順序——是的,我們將使用z-index
。所有圖像都以相同的z-index
值(2)開始,這將使堆棧中的最後一張圖像位於頂部。
我們取最後一張圖像,將其向右滑動,直到顯示堆棧中的下一張圖像。然後我們降低圖像的z-index
值,然後將其滑回卡組。由於它的z-index
值低於其餘圖像,因此它成為堆棧中的最後一張圖像。
這是一個簡化的演示,它展示了這個技巧。將鼠標懸停在圖像上以激活動畫:
現在,想像一下相同的技巧應用於所有圖像。如果我們使用:nth-child()
偽選擇器來區分圖像,那麼這就是模式:
這就是我們的無限滑塊!
如果您還記得上一篇文章,我只定義了一個動畫並使用延遲來控制每張圖像。我們在這裡也將做同樣的事情。讓我們首先嘗試可視化動畫的時間線。我們將從三張圖像開始,然後將其推廣到任意數量 (N) 的圖像。
我們的動畫分為三個部分:“向右滑動”、“向左滑動”和“不動”。我們可以很容易地識別每張圖像之間的延遲。如果我們認為第一張圖像從 0s 開始,並且持續時間等於 6s,那麼第二張圖像將從 -2s 開始,第三張圖像將從 -4s 開始。
<code><div> <img alt="" src=""><img alt="" src=""><img alt="" src=""><img alt="" src=""> </div></code>
我們還可以看到,“不動”部分佔據了整個動畫的三分之二 (2*100%/3),而“向右滑動”和“向左滑動”部分一起佔據了三分之一——因此,每個部分都等於總動畫的 100%/6。
我們可以這樣編寫動畫關鍵幀:
<code>.gallery { display: grid; width: 220px; /* 控制大小 */ } .gallery > img { grid-area: 1 / 1; width: 100%; aspect-ratio: 1; object-fit: cover; border: 10px solid #f2f2f2; box-shadow: 0 0 4px #0007; }</code>
120% 是一個任意值。我需要一個大於 100% 的值。圖像需要向右滑動,遠離其餘圖像。為此,它需要移動至少其大小的 100%。這就是我選擇 120% 的原因——以獲得一些額外的空間。
現在我們需要考慮z-index
。別忘了,我們需要在圖像滑出堆棧之後和滑回堆棧底部之前更新圖像的z-index
值。
<code>.gallery > img:nth-child(2) { animation-delay: -2s; } /* -1 * 6s / 3 */ .gallery > img:nth-child(3) { animation-delay: -4s; } /* -2 * 6s / 3 */</code>
我們不是在時間線上的 16.67% (100%/6) 點定義一個狀態,而是在幾乎相同的點 (16.66% 和 16.67%) 定義兩個狀態,其中z-index
值在我們將圖像滑回卡組之前降低。
這就是我們將所有這些結合在一起時發生的情況:
嗯,滑動部分似乎工作正常,但是堆疊順序全部混亂了!動畫開始得很好,因為頂部的圖像正在移動到後面……但是後續的圖像並沒有跟上。如果您注意到,序列中的第二張圖像在下一張圖像閃爍到其頂部之前返回到堆棧頂部。
我們需要仔細跟踪z-index
的變化。最初,所有圖像的z-index
都是:2。這意味著堆疊順序應該是……
<code>@keyframes slide { 0% { transform: translateX(0%); } 16.67% { transform: translateX(120%); } 33.34% { transform: translateX(0%); } 100% { transform: translateX(0%); } }</code>
我們滑動第三張圖像並將其z-index
更新為:
<code>@keyframes slide { 0% { transform: translateX(0%); z-index: 2; } 16.66% { transform: translateX(120%); z-index: 2; } 16.67% { transform: translateX(120%); z-index: 1; } /* 我们在这里更新 z-order */ 33.34% { transform: translateX(0%); z-index: 1; } 100% { transform: translateX(0% ); z-index: 1; } }</code>
我們對第二張圖像也這樣做:
<code>我们的眼睛 ? --> 第三张 (2) | 第二张 (2) | 第一张 (2)</code>
……以及第一張圖像:
<code>我们的眼睛 ? --> 第二张 (2) | 第一张 (2) | 第三张 (1)</code>
我們這樣做,一切似乎都很好。但實際上並非如此!當第一張圖像移動到後面時,第三張圖像將開始另一個迭代,這意味著它返回到z-index
:2:
<code>我们的眼睛 ? --> 第一张 (2) | 第三张 (1) | 第二张 (1)</code>
因此,實際上我們根本沒有所有圖像的z-index
:2!當圖像沒有移動(即動畫的“不動”部分)時,z-index
為 1。如果我們滑動第三張圖像並將其z-index
值從 2 更新為 1,它將保留在頂部!當所有圖像具有相同的z-index
時,源順序中的最後一個圖像——在這種情況下是我們的第三張圖像——位於堆棧頂部。滑動第三張圖像會導致以下結果:
<code>我们的眼睛 ? --> 第三张 (1) | 第二张 (1) | 第一张 (1)</code>
第三張圖像仍然位於頂部,之後,當它的動畫以z-index
:2 重新啟動時,我們將第二張圖像移動到頂部:
<code><div> <img alt="" src=""><img alt="" src=""><img alt="" src=""><img alt="" src=""> </div></code>
一旦我們滑動它,我們得到:
<code>.gallery { display: grid; width: 220px; /* 控制大小 */ } .gallery > img { grid-area: 1 / 1; width: 100%; aspect-ratio: 1; object-fit: cover; border: 10px solid #f2f2f2; box-shadow: 0 0 4px #0007; }</code>
然後第一張圖像將跳到頂部:
<code>.gallery > img:nth-child(2) { animation-delay: -2s; } /* -1 * 6s / 3 */ .gallery > img:nth-child(3) { animation-delay: -4s; } /* -2 * 6s / 3 */</code>
我知道,這很令人困惑。但是我們的邏輯並不完全錯誤。我們只需要稍微糾正一下動畫即可使一切按我們想要的方式工作。訣竅在於正確重置z-index
。
讓我們考慮第三張圖像位於頂部的這種情況:
<code>@keyframes slide { 0% { transform: translateX(0%); } 16.67% { transform: translateX(120%); } 33.34% { transform: translateX(0%); } 100% { transform: translateX(0%); } }</code>
我們看到滑動第三張圖像並更改其z-index
會使其保持在頂部。我們需要做的是更新第二張圖像的z-index
。因此,在我們滑動第三張圖像遠離卡組之前,我們將第二張圖像的z-index
更新為 2。
換句話說,我們在動畫結束之前重置第二張圖像的z-index
。
綠色加號表示將z-index
增加到 2,紅色減號與z-index
:1 相關。第二張圖像以z-index
:2 開始,然後當它從卡組中滑出時,我們將它更新為 1。但在第一張圖像從卡組中滑出之前,我們將第二張圖像的z-index
更改回 2。這將確保兩張圖像具有相同的z-index
,但是,第三張圖像將仍然位於頂部,因為它在DOM中出現較晚。但在第三張圖像滑動並更新其z-index
之後,它會移動到底部。
這是動畫的三分之二,因此讓我們相應地更新關鍵幀:
<code>@keyframes slide { 0% { transform: translateX(0%); z-index: 2; } 16.66% { transform: translateX(120%); z-index: 2; } 16.67% { transform: translateX(120%); z-index: 1; } /* 我们在这里更新 z-order */ 33.34% { transform: translateX(0%); z-index: 1; } 100% { transform: translateX(0% ); z-index: 1; } }</code>
好了一點,但仍然不夠好。還有一個問題……
別擔心,我們不會再次更改關鍵幀,因為這個問題只在涉及最後一張圖像時才會發生。我們可以為最後一張圖像製作一個“特殊”的關鍵幀動畫來修復問題。
當第一張圖像位於頂部時,我們有以下情況:
<code>我们的眼睛 ? --> 第三张 (2) | 第二张 (2) | 第一张 (2)</code>
考慮到我們之前所做的調整,在第一張圖像滑動之前,第三張圖像將跳到頂部。這只會發生在這種情況下,因為在第一張圖像之後移動的下一張圖像是 DOM 中順序較高的最後一張圖像。其餘圖像很好,因為我們有 N,然後是 N - 1,然後我們從 3 到 2,從 2 到 1……但然後我們從 1 到 N。
為了避免這種情況,我們將對最後一張圖像使用以下關鍵幀:
<code>我们的眼睛 ? --> 第二张 (2) | 第一张 (2) | 第三张 (1)</code>
我們在動畫進行到 5/6 時(而不是三分之二)重置z-index
值,此時第一張圖像已移出堆棧。所以我們看不到任何跳躍!
成功!我們的無限滑塊現在完美無缺了!這是我們最終代碼的全部內容:
<code>我们的眼睛 ? --> 第一张 (2) | 第三张 (1) | 第二张 (1)</code>
現在我們的動畫適用於三張圖像,讓我們使其適用於任意數量 (N) 的圖像。但首先,我們可以通過將動畫拆分來稍微優化我們的工作,以避免冗餘:
<code><div> <img alt="" src=""><img alt="" src=""><img alt="" src=""><img alt="" src=""> </div></code>
現在代碼更易於閱讀和維護了!我們為滑動部分製作一個動畫,為z-index
更新製作另一個動畫。請注意,我們在z-index
動畫上使用steps(1)
。這是因為我希望突然更改z-index
值,與滑動動畫不同,在滑動動畫中我們希望平滑移動。
現在代碼更易於閱讀和維護,我們可以更好地了解如何支持任意數量的圖像。我們需要做的是更新動畫延遲和關鍵幀的百分比。延遲很容易,因為我們可以使用我們在上一篇文章中製作的完全相同的循環來支持圓形滑塊中的多個圖像:
<code>.gallery { display: grid; width: 220px; /* 控制大小 */ } .gallery > img { grid-area: 1 / 1; width: 100%; aspect-ratio: 1; object-fit: cover; border: 10px solid #f2f2f2; box-shadow: 0 0 4px #0007; }</code>
這意味著我們正在從普通的CSS轉向Sass。接下來,我們需要想像一下時間線如何隨著 N 張圖像而變化。別忘了動畫分為三個階段:
在“向右滑動”和“向左滑動”之後,圖像應該保持不動,直到其餘圖像完成序列。因此,“不動”部分需要花費與 (N - 1) 相同的時間作為“向右滑動”和“向左滑動”。在一個迭代中,N 張圖像將滑動。因此,“向右滑動”和“向左滑動”都佔據總動畫時間線的 100%/N。 “向右滑動”和“向左滑動”都佔據總動畫時間線的 100%/N。圖像在 (100%/N)/2 時從堆棧中滑出,並在 100%/N 時滑回。
我們可以更改這個:
<code>.gallery > img:nth-child(2) { animation-delay: -2s; } /* -1 * 6s / 3 */ .gallery > img:nth-child(3) { animation-delay: -4s; } /* -2 * 6s / 3 */</code>
……到這個:
<code>@keyframes slide { 0% { transform: translateX(0%); } 16.67% { transform: translateX(120%); } 33.34% { transform: translateX(0%); } 100% { transform: translateX(0%); } }</code>
如果我們將 N 替換為 3,當堆棧中有 3 張圖像時,我們將得到 16.67% 和 33.33%。堆疊順序的邏輯相同,我們將有:
<code>@keyframes slide { 0% { transform: translateX(0%); z-index: 2; } 16.66% { transform: translateX(120%); z-index: 2; } 16.67% { transform: translateX(120%); z-index: 1; } /* 我们在这里更新 z-order */ 33.34% { transform: translateX(0%); z-index: 1; } 100% { transform: translateX(0% ); z-index: 1; } }</code>
我們仍然需要更新 66.33% 的點。這應該是圖像在動畫結束之前重置其z-index
的地方。與此同時,下一張圖像開始滑動。由於滑動部分需要 100%/N,因此重置應該發生在 100% - 100%/N:
<code>我们的眼睛 ? --> 第三张 (2) | 第二张 (2) | 第一张 (2)</code>
但是為了使我們的z-order-last
動畫工作,它應該在序列中稍後發生。還記得我們對最後一張圖像所做的修復嗎?重置z-index
值需要在第一張圖像移出堆棧時發生,而不是在它開始滑動時發生。我們可以在關鍵幀中使用相同的推理:
<code>我们的眼睛 ? --> 第二张 (2) | 第一张 (2) | 第三张 (1)</code>
我們完成了!以下是使用五張圖像時得到的結果:
我們可以添加一點旋轉來使事情變得更漂亮:
我所做的只是將rotate(var(--r))
附加到transform
屬性。在循環中,--r
使用隨機角度定義:
<code>我们的眼睛 ? --> 第一张 (2) | 第三张 (1) | 第二张 (1)</code>
旋轉會產生小的故障,因為我們有時可以看到一些圖像跳到堆棧的後面,但這並不重要。
所有這些z-index
工作都是一個巨大的平衡行為,對吧?如果您在此練習之前不確定堆疊順序的工作方式,那麼您現在可能對它有了更好的了解!如果您發現某些解釋難以理解,我強烈建議您再次閱讀本文並使用鉛筆和紙張繪製內容。嘗試使用不同數量的圖像來說明動畫的每個步驟,以更好地理解這個技巧。
上次,我們使用了一些幾何技巧來創建一個圓形滑塊,該滑塊在完成一個完整序列後旋轉回第一張圖像。這次,我們使用z-index
完成了類似的技巧。在這兩種情況下,我們都沒有復制任何圖像來模擬連續動畫,也沒有使用 JavaScript 來幫助進行計算。
下次,我們將製作 3D 滑塊。敬請期待!
以上是CSS無限滑塊翻過寶麗來圖像的詳細內容。更多資訊請關注PHP中文網其他相關文章!