# 用 SVG 遮罩製作有特殊外框的輪播 ## 前言 今天跟國中同學聚餐,提到一個他不知道該怎麼做的功能 他希望輪播的外框是特殊圖案,而非常見的方形,裡面的圖片可以橫向線性移動並且換圖 例如以下的樣子 ![](https://i.imgur.com/8gktHDV.png) ## 實作成果 這邊先貼上做完的成果,後面一步步解析怎麼做出來 https://codepen.io/not0000/pen/bGjvyoN ![](https://i.imgur.com/PlVSE8l.png) ## 可行性分析 我想到的做法是使用 SVG 圖形製作外框,然後用 css 覆蓋套到現有的輪播套件上 css 應該是使用 posision absolute 改變 xy 軸,並且用 z-index 指定上下層 但我只有用過 div 等 html 元素,不確定 svg 混進來是否適用,所以要先實驗看看 --- ## 準備實驗素材 我準備了一張底下要用的 jpg 和一個 星型向量遮罩,想先測試在無動畫的狀態,能否做出特殊形狀的外框遮罩 ![](https://i.imgur.com/qndNnzv.png) --- ## 第一次實驗 但當我把 svg 疊上去後發現 svg 裡面的路徑應該要挖掉,沒挖掉變成中間其實是白色 ![](https://i.imgur.com/bSsKgT7.jpg) --- ## 修正素材 回到 Illustrator ,這次為求慎重,故意放一個綠色背景確保真的有挖空,再放回 html 一次 ![](https://i.imgur.com/Od7imK1.png) --- ## 實驗成功 這次真的挖成功了,確定 svg 可以幫圖片製作特殊遮罩, ![](https://i.imgur.com/zrJpUDS.jpg) --- ## 調整大小 稍微用 css 把兩者尺寸改成相同,初步實驗樣本完成,接下來要合併輪播動畫 基本上做到這一步,已經確定沒有什麼技術問題了 ![](https://i.imgur.com/vnGP36T.png) --- ## 加入輪播動畫 我習慣用的是 [Swiper](https://swiperjs.com/) 因為只是要做實驗功能可行性的範本,為求方便,直接在 Swiper 官網找[可以引用 cdn 的檔案](https://swiperjs.com/get-started) ```html= <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@8/swiper-bundle.min.css" /> <script src="https://cdn.jsdelivr.net/npm/swiper@8/swiper-bundle.min.js"></script> ``` 而且為了要讓動畫有兩張可以切換的圖片,再找一個 戴珍珠耳環的少女圖片做準備 ![](https://i.imgur.com/gonJWtl.jpg) 把 swiper 需要的 html css js 都貼上來,可以看到輪播的框框出現了 ![](https://i.imgur.com/F5geeCk.png) ## 微調 swiper swiper 雖然上來了也確定可以動,但有幾個問題 1. 範本的 js 是垂直捲動的 1. 沒有自動撥放 1. 還沒有跟 svg 遮罩整合 要把這三個地方改掉 ![](https://i.imgur.com/BwdPNTf.png) ## 範本的 js 是垂直捲動的 這是最容易的,稍微看一下 js 的英文,有一段 direction: 'vertical' ,刪掉即可 至於參數到底有哪些,可以看官網 [api 文件](https://swiperjs.com/swiper-api#param-direction)的這一段 ![](https://i.imgur.com/4kgoACE.png) ## 自動撥放 這個也還算容易,用 auto 這個關鍵字去找 api 很快就找到了,改完的範本如下 ``` const swiper = new Swiper('.swiper', { loop: true, autoplay: { delay: 3000, //每三秒鐘輪播一張圖 }, ``` ## 更換 html 理想情況下,是一個遮罩對應多張圖,但我這邊先嘗試用了偷懶的方法,我打算把遮罩跟圖片作為一組直接放一起,這樣原本的 html 可以不太需要動,每張圖個字一個遮罩,於是把 ```html= <div class="swiper-slide">Slide 1</div> ``` 這一段直接換成我原本寫好的 html ```html= <div class="swiper-slide"> <div class="inner-image"><img src="" alt="蒙娜麗莎"></div> <div class="cover"> <svg>遮罩</svg> </div> </div> ``` 結果跑起來變成整個遮罩一起輪播,這不是想要的結果 ![](https://i.imgur.com/jTMECQh.png) 於是乖乖把 svg 抽出來,重新調整 posision 的 css ## 把 svg 遮罩往外放一點 整個 swiper 的圖片是在 swiper-wrapper 這一塊,抽出來後發現他是使用 position: relative; ,跟我原本的 absolute 不同,於是我也改用 position: relative; 並且加上 top: -300px; 以符合 swiper 的高度,配上 z-index:1; 控制到比較上面一層,這樣終於做出可以在遮罩內滑動的效果了 ``` .cover{ position: relative; z-index:1; top:-300px; } ``` ![](https://i.imgur.com/yyNsqMB.png) --- ## 不太滿意的地方 因為加了遮罩,所以滑動時,如果是點在"遮罩"上,會造成無法滑動(畢竟沒有點到圖片,就無法觸發 js 的事件),但還需要研究怎麼控制就是了 想到的方法是在 swiper 上面疊一層 div ,然後偵測 div 滑動的事件,再去結合 swiper 的滑動圖片 --- ## 不要自己硬幹,與其他開發者互動的結果 後來把不太滿意的地方拿去F2E社團問,馬上就有答案了 https://www.facebook.com/groups/f2e.tw/posts/5766357716734879 > Dian Wu:在 svg 的style 上加上 pointer-events:none 試試 一開始我先嘗試放在 svg 上,但沒有成功,後來轉念一想改放在其他地方看看,於是拉到上一層的 cover (用來包覆svg以及設定z-index:-1的地方),這次就順利完成了 ###### tags: `程式設計`