[分享會]只用CSS實現輪播圖

陟上晴明發表於2023-02-19

早些時候有看到過一個 純CSS輪播圖 的文章,當時有研究過實現,大概是利用了 hash (錨標記) 和 scroll-snap 來實現的,但是具體實現已經回憶不起來了。

正好現在分享群組裡邊暫時沒有主題了,就想著可以當成一個常駐的補位小環節,大家一起瀏覽 CodePen 之類的社群找一個大家都感興趣的 Demo 來研究。
在分享前還是需要自己重新研究一遍的,不然在講述的時候出錯可太 “甜蜜的” 尷尬了。

首先呢,先實現一個簡易的的可控輪播示例

在樣例的實現中我將會使用到一下技術棧,希望你可以稍微瞭解一下

  1. Pug (HTML前處理器)
  2. Stylus (CSS前處理器)

P.S. 以下筆記內容將逐步實現目標文章示例,會復原目標文章內的元素樣式,稍微有點改動但變化不大,因為自己想的樣式太醜了。

?CodePen Demo

? 講解:

可以點開上方示例中的選項卡檢視實現程式碼,

  1. html 中書寫了 5 個 <div 並且宣告瞭對應的 ID
  2. 並且在後續新增了 <a> 標籤來改變URL當中的 hash 值來控制卡片的切換;
  3. css 利用 scroll-behavior:smooth 這個屬性,來達到切換卡片的平滑滾動效果。

但是缺少了切換前進後退按鈕,接下來我們就來實現這個功能:

?CodePen Demo2

? 講解:

其實很憨,直接為每一個卡片新增了前進後退按鈕的 <a> 標籤而已。
稍微有點麻煩的就是 如何讓這兩個按鈕隨著卡片的切換而改變,而不被後一個卡片的按鈕所覆蓋,因為這兩個按鈕是不會隨著卡片切換所移動的,這裡就需要腦洞大開了!

正常思路來說,肯定是會嘗試修改 前進後退按鈕 的父級的定位方式。
確實,會需要修改成 position:relative,但是這個其實是為了每次切換卡片後變更對應的錨連結的。

原示例是從輪播元件的最外層容器建立了 ::before::after 兩個偽類,給他們設定的切換按鈕的樣式,並且設定為點選穿透,然後把輪播卡片內的 前進後退按鈕透明 底色。
這樣所展示的 “按鈕” 就不會隨卡片所以移動了,而實際的切換按鈕會隨著卡片所移動,只是不會被瀏覽者發現。

功能基本實現了,然後我們復原一下原示例的樣式。

?CodePen Demo3

對照一下原示例,除了自動播放外還差了些什麼呢?emmmm.....自動播放

? 尾關BOSS ? 自動輪播

最後來看一下她是如何實現自動播放的,這裡的實現方式如果他不講我直接就蒙圈了,但是確實很贊!?

  1. First I slowly offset the scroll snap points to the right, making the scroll area follow along due to being snapped to them.
    首先我緩慢地將滾動捕捉點向右偏移,使滾動區域由於捕捉它們而跟隨。
  2. After having scrolled the width of a whole slide, I deactivate the snapping. The scroll area is now untied from the scroll snap points.
    在滾動整個幻燈片寬度後,我停用了捕捉。 滾動區域現在與滾動捕捉點解除繫結。
  3. Now I let the scroll snap points jump back to their initial positions without them “snap-dragging” the scroll area back with them
    現在我讓滾動捕捉點跳回到它們的初始位置,而不用它們 “捕捉拖動” 滾動區域
  4. Then I re-engage the snapping which now lets the scroll area snap to a different snap point ?
    然後我重新啟用捕捉,讓滾動區域捕捉到不同的捕捉點

看起來有點不易懂,但是其實並不複雜的。

其實就是利用了 scroll-snap 會使滾動容器的捕捉點變更為你設定的元素對齊位置(scroll-snap-align),然後透過修改 left 屬性值使滾動容器向右滾動實現向後滾動的效果,然後透過修改當前元素的對齊位置為 none, 讓滾動容器捕捉到下一個元素的對齊位置,以此來達到自動輪播的效果,那麼讓我們來實現一下吧!

?CodePen Demo 4

但是我還沒有增加懸停停止自動輪播和一些其他的最佳化,有興趣的可以自己實現一下,用到的CSS屬性:

完整復現一下原示例吧!

?CodePen Demo 5

尾聲

其實一開始我是不知道他如何實現的視差滾動的,結果在研究自動輪播的時候,突然就通了,所以就加上來了

透過 transform:translate3d() 給中間的元素,增加了 Z軸 屬性,使其脫離了平面 “懸浮” 在輪播卡片上,然後在最外層容器的 “輪播器” 設定了 perspective 指定了容器平面與 視窗Z軸 距離。

但是有點問題,只有在自動播放動畫執行時才會體現出來,手動控制切換是感覺不出來的,因為手動滾動時無法應用 scroll-snap

⚡ 相容性

什麼?你問我相容性?友盡了啊!

別想了,scroll-snap 屬性都是 CR 階段,也就是候選,具體正式上線還有2個階段要走,
並且scroll-behavior (平滑滾動)屬性 Safari 是不支援的,

"scroll-behavior" | Can I use
"scroll-snap" | Can I use

所以移動端的相容有很大問題,畢竟還有一個毒瘤 —— 微信內建瀏覽器,也是不支援這些屬性的,
我在製作的過程中都沒有考慮過移動端的適配,直接放棄了,PC端還是可以玩玩的。

自動輪播實現不了,那麼視差滾動也就沒辦法實現了,

鬧這麼大一圈,其實就是個圖個樂子,不過嘗一下鮮,學習到別人的腦洞就好了。


檔案連結

scroll-behavior - CSS | MDN
perspective - CSS | MDN
scroll-snap-type - CSS | MDN
scroll-snap-align - CSS | MDN
hover - CSS | MDN
:focus-within - CSS | MDN
prefers-reduced-motion - CSS | MDN

CSS-Only Carousel | CSS-Tricks
You can get pretty far in making a slider with just HTML and CSS | CSS-Tricks
大俠,請留步,要不過來瞭解下CSS Scroll Snap? « 張鑫旭-鑫空間-鑫生活

本文參與了SegmentFault 思否寫作挑戰賽,歡迎正在閱讀的你也加入。

相關文章