歡迎關注我的公眾號:前端偵探
今天來用 CSS 實現一個帶圓角的環形 loading 動畫,效果是這樣的
先不考慮動畫,其實就是這樣一個圖形
那麼,如何來繪製呢?下面花兩分鐘一起看看吧
一、CSS實現思路
首先,看到這環形逐漸消失的效果,也就是透明度漸變的效果,肯定要聯想到錐形漸變
conic-gradient() - CSS:層疊樣式表 | MDN (mozilla.org)
透過錐形漸變,可以很輕鬆的實現這樣一個效果,透明到純色的漸變
loading{
background: conic-gradient(transparent 10%, royalblue 90%)
}
效果如下
然後,整體是一個環形,可以透過徑向漸變配合mask
遮罩實現
loading{
/*...*/
-webkit-mask: radial-gradient( closest-side circle, transparent 50%, red 51% 99%, transparent 100%);
}
原理是這樣的
還有一個圓角,可以直接用徑向漸變實現
loading{
background: radial-gradient( closest-side circle, royalblue 99%, transparent 100%) center top/25% 25% no-repeat,
conic-gradient(transparent 10%, royalblue 90%);;
}
其實就是兩個相同顏色的漸變疊加到一起形成的,如下
所以完整程式碼就是
loading{
width: 200px;
height: 200px;
background:
radial-gradient( closest-side circle, royalblue 99%, transparent 100%) center top/25% 25% no-repeat,
conic-gradient(transparent 10%, royalblue 90%);
-webkit-mask: radial-gradient( closest-side circle, transparent 50%, red 51% 99%, transparent 100%);
}
二、更好地自定義顏色
上面的實現雖然很好的滿足了需求,但是,還是有些CSS設計問題。
比如,我如果需要改變 loading 的顏色,需要改變兩個地方
很明顯,這樣的實現不太符合 DRY(Don't Repeat Yourself)原則。
有一個比較簡單思路可以用 CSS 變數來傳遞
loading{
--color: royalblue;
background:
radial-gradient( closest-side circle, var(--color) 99%, transparent 100%) center top/25% 25% no-repeat,
conic-gradient(transparent 10%, var(--color) 90%);
-webkit-mask: radial-gradient( closest-side circle, transparent 50%, red 51% 99%, transparent 100%);
}
這樣每次都只需要改變一個變數就行了。
loading.red{
--color: red;
}
除了這種方式以外,其實還有一點需要考慮,為啥背景不能幹淨一點、純粹一點呢?換個說法,現在的背景實現對於不瞭解的同學來講,可能會很費勁,能否將這些細節隱藏起來,更直觀地去自定義顏色呢?比如像這種方式
loading.red{
background: red;
}
如果要實現這樣的效果,就需要將繪製部分全部在mask
遮罩中完成,背景只是展示而已。
那麼,如何透過mask
遮罩實現這樣的圖形呢?
三、更直觀地去自定義顏色
mask
遮罩其實也和 CSS 背景差不多,只是多了一些圖形合成操作,其實就是布林運算,也就是mask-composite
。
mask-composite - CSS: Cascading Style Sheets | MDN (mozilla.org)
/* Keyword values */
mask-composite: add; /* 疊加(預設) */
mask-composite: subtract; /* 減去,排除掉上層的區域 */
mask-composite: intersect; /* 相交,只顯示重合的地方 */
mask-composite: exclude; /* 排除,只顯示不重合的地方 */
相信在很多圖形設計軟體中都見到類似的操作(下面是 photoshop)
這個屬性的值(標準和非標準)非常多,-webkit-mask-composite 與標準下的值有所不同,屬性值非常多,如下(chorme 、safari 支援)
-webkit-mask-composite: clear; /*清除,不顯示任何遮罩*/
-webkit-mask-composite: copy; /*只顯示上方遮罩,不顯示下方遮罩*/
-webkit-mask-composite: source-over; /*疊加,兩者都顯示*/
-webkit-mask-composite: source-in; /*只顯示重合的地方*/
-webkit-mask-composite: source-out; /*只顯示上方遮罩,重合的地方不顯示*/
-webkit-mask-composite: source-atop;
-webkit-mask-composite: destination-over; /*疊加,兩者都顯示*/
-webkit-mask-composite: destination-in; /*只顯示重合的地方*/
-webkit-mask-composite: destination-out;/*只顯示下方遮罩,重合的地方不顯示*/
-webkit-mask-composite: destination-atop;
-webkit-mask-composite: xor; /*只顯示不重合的地方*/
之前在這篇文章中有詳細介紹 mask-composite
的用法,有興趣的可以回顧一下
CSS mask 實現滑鼠跟隨鏤空效果
回到這裡,思考一下?,怎麼來繪製這樣一個圖形?
形狀是一樣的,只是和前面的步驟稍微有些差異
首先還是繪製環形漸變,可以先繪製錐形漸變和環形漸變,如下
loading{
background: royalblue;
-webkit-mask:
radial-gradient( closest-side circle, transparent 49%, red 50% 99%, transparent 100%),
conic-gradient(transparent 10%, royalblue 90%);
}
但是這樣兩個漸變會疊加在一起
其實我們需要是隻顯示兩者重疊的部分,也就是交叉區域,這個特性在mask-composite
中對應的就是destination-in
或者source-in
loading{
...
-webkit-mask-composite: source-in;
}
效果如下
然後是那個圓角,和上面繪製一樣
loading{
...
-webkit-mask:
radial-gradient( closest-side circle, royalblue 99%, transparent 100%) center top/25% 25% no-repeat,
radial-gradient( closest-side circle, transparent 49%, red 50% 99%, transparent 100%),
conic-gradient(transparent 10%, royalblue 90%)
;
-webkit-mask-composite: source-in;
}
如果直接這樣疊加,會變成這樣
其實這是因為source-in
導致的,三個圖形,最後只顯示了三者重疊的區域。但是我們現在需要的是最上面的圓角直接疊加就行了,不需要裁剪,可以用到source-over
loading{
-webkit-mask-composite: source-over, source-in;
}
效果如下
下面是完整程式碼
loading{
width: 200px;
height: 200px;
background: royalblue;
-webkit-mask:
radial-gradient( closest-side circle, royalblue 99%, transparent 100%) center top/25% 25% no-repeat,
radial-gradient( closest-side circle, transparent 49%, red 50% 99%, transparent 100%),
conic-gradient(transparent 10%, royalblue 90%);
-webkit-mask-composite: source-over, source-in;
}
如果要換顏色,直接更換背景就可以了,還可以是漸變
loading{
background: conic-gradient(red, orange, red)
}
自定義顏色起來是不是更加直觀?
四、動畫和安利
動畫很簡單,就是一個無限旋轉的線性動畫,這個沒什麼好說的
loading{
animation: rotate 1s linear infinite;
}
@keyframes rotate{
to{
transform: rotate(360deg);
}
}
這樣就實現了文章開頭效果
關於線上 demo,這裡安利一下我開發的xy-ui元件庫(目前正在重構中...),裡面 loading
元件就用到了這個實現
https://xy-ui.codelabo.cn
很多有趣的 CSS 小技巧都可以在這個元件庫中找到,歡迎 star & fork ??????
五、總結和說明
以上就是本文的全部內容了,稍顯囉嗦,不過也是為了提供更多的思路,下面總結一下實現重點
- 整個實現其實用到了錐形漸變和徑向漸變
- 正常思路是背景繪製出透明錐形漸變,然後透過 mask 遮罩裁剪出環形
- 不過這種思路改顏色稍微麻煩一點,可以透過 CSS 變數傳遞,簡化程式碼
- 顏色在背景中不夠直觀,可以考慮將實現細節放到 mask 中
- mask遮罩合成可以實現圖形的合成與裁剪,可以更靈活的布林運算
- 推薦一下我的元件庫 xy-ui,可以學到更多有趣的 CSS 小技巧
最後,如果覺得還不錯,對你有幫助的話,歡迎點贊、收藏、轉發❤❤❤,同時也歡迎喜歡 CSS 的各位關注我,加我微信XboxYan
,一起交流,共同進步。
歡迎關注我的公眾號:前端偵探