
今天來用 css 實現一個帶圓角的環形 loading 動畫,效果是這樣的

先不考慮動畫,其實就是這樣一個圖形

那么,如何來繪制呢?下面花兩分鐘一起看看吧。
一、CSS實現思路
首先,看到這環形逐漸消失的效果,也就是透明度漸變的效果,肯定要聯想到錐形漸變。
conic-gradient() - CSS:層疊樣式表 | MDN (mozilla.org)[1]
通過錐形漸變,可以很輕松的實現這樣一個效果,透明到純色的漸變。
loading{
background: conic-gradient(transparent 10%, royalblue 90%)
}
效果如下:

然后,整體是一個環形,可以通過徑向漸變配合mask遮罩實現。
radial-gradient() - CSS:層疊樣式表 | MDN (mozilla.org)[2]
mask - CSS: Cascading Style Sheets | MDN (mozilla.org)[3]
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)[4]
/* Keyword values */
mask-composite: add; /* 疊加(默認) */
mask-composite: subtract; /* 減去,排除掉上層的區域 */
mask-composite: intersect; /* 相交,只顯示重合的地方 */
mask-composite: exclude; /* 排除,只顯示不重合的地方 */
相信在很多圖形設計軟件中都見到類似的操作(下面是 Photoshop)。

這個屬性的值(標準和非標準)非常多,-webkit-mask-composite[5] 與標準下的值有所不同,屬性值非常多,如下(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 實現鼠標跟隨鏤空效果[6]
回到這里,思考一下






