最近,在 Steam 玩一款老遊戲(生化危機 4 重置版),其中,每當遊戲轉場的過程中,都有這麼一個有趣的 Loading 動畫:
整個效果有點類似於日食效果,中間一圈黑色,向外散發著太陽般的光芒。
本文,我們將嘗試使用 CSS,還原這個效果。
整個效果做出來,類似於如下兩個動畫效果這樣:
其實,整個效果,去掉中間黑色的遮罩,是這個樣子的:
所以,我們的目標就變成了,如何使用 CSS,實現上述這個圖形效果。
到這裡,思考一圈 CSS 中的各種屬性,和這個圖形能掛上鉤的,幾乎就只有角向漸變 conic-gradient
了。
我們可以利用多重角向漸變,試著畫一個類似的圖形 -- 從單個顏色到透明,再多次迴圈鋪滿 360° 的整個圖形:
<div></div>
body {
background: #000;
}
div {
width: 200vw;
height: 200vh;
background:
repeating-conic-gradient(
rgba(0, 136, 204, 0.77),
rgba(150, 157, 100, 0.72) 2%,
rgba(230, 247, 200, 0.82) 3%,
transparent 4%,
transparent 5%
);
}
我們隨機設定了 conic-gradient()
中的顏色 A 到顏色 B 到顏色 C到透明的變化,可以得到這麼一張圖形:
注意,對於上面的顏色沒有任何要求,隨機設定都可以。
我們可以讓這個圖形旋轉起來,簡單加上一個旋轉動畫:
div {
animation: rotate 2s ease-in-out infinite;
}
@keyframes rotate {
to {
transform: rotate(1turn);
}
}
效果如下:
我們仔細觀察一下,我們要的最終效果,其實要求邊緣是毛刺狀,而不是連續的影象:
這一步要怎麼實現呢?其實也非常簡單,我們只需要在原影象上,疊加一層從影象主色到黑色的徑向漸變即可。
我們可以藉助偽元素實現這個疊加遮罩:
div::before {
content: "";
position: absolute;
inset: 0;
background: radial-gradient(rgba(150, 157, 100, 0.32), rgba(0, 0, 0, 1) 45vmin, rgba(0, 0, 0, 1));
}
這裡我們實現了這麼一個漸變:
radial-gradient(rgba(150, 157, 100, 0.32), rgba(0, 0, 0, 1) 45vmin, rgba(0, 0, 0, 1))
:其核心就是實現了從某一個實體顏色(選取一個上面角向漸變圖形用到的主要顏色)到黑色的一個徑向漸變效果這樣,我們就將邊緣改造的不那麼突兀了!
效果如下:
基於上述的原理及技巧,我們重新構思一下整個動畫,上面只有一層角向背景的背景在運動。
那麼,如果我們設定多層背景,並且,設定他們正向、反向一起運動呢?
我們來實現一個 4 層角向漸變背景的動畫效果,並且使用最終我們想要的黃色為主題色,:
<div class="g-container">
<div class="g-circle g-circle1"></div>
<div class="g-circle g-circle2"></div>
<div class="g-circle g-circle3"></div>
<div class="g-circle g-circle4"></div>
</div>
完整的 CSS 程式碼如下:
body{
width: 100%;
height: 100%;
background: #000;
}
.g-container {
position: absolute;
width: 80vmax;
height: 80vmax;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
.g-circle {
position: absolute;
inset: 0;
border-radius: 50%;
}
.g-circle1 {
background:
repeating-conic-gradient(
from 0deg at 50% 50%,
transparent 0%,
rgba(255, 230, 8, 0.69) 1%,
transparent 6%
);
animation: 13s linear rotate infinite reverse;
}
.g-circle2 {
background:
repeating-conic-gradient(
from 19deg at 50% 50%,
transparent 0%,
rgba(250, 240, 20, 0.78) 1.2%,
rgba(250, 240, 20, 0.78),
transparent 4.8%,
transparent 7.6%
);
animation: 9s linear -2s rotate infinite;
}
.g-circle3 {
background:
repeating-conic-gradient(
from 37deg at 50% 50%,
transparent 0%,
rgba(250, 240, 20, 0.78) 4%,
transparent 7.9%,
transparent 12%
);
animation: 17s linear rotate infinite reverse;
}
.g-circle4 {
background:
repeating-conic-gradient(
from 103deg at 50% 50%,
transparent 0%,
rgba(250, 240, 20, 0.5) 5%,
rgba(250, 240, 20, 0.27) 7%,
transparent 12%
);
animation: 7s linear rotate infinite;
}
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(359deg);
}
}
上面的程式碼,做了幾件核心事情:
repeating-conic-gradient()
這樣,我們能得到這麼一個效果:
此時,我們再在上述圖形的基礎上,疊加上一層遮罩 mask,將圖案的邊緣黑化:
<div class="g-container">
<div class="g-circle g-circle1"></div>
<div class="g-circle g-circle2"></div>
<div class="g-circle g-circle3"></div>
<div class="g-circle g-circle4"></div>
+ <div class="g-circle g-mask"></div>
</div>
.g-container .g-mask {
position: absolute;
inset: -200px;
background:
radial-gradient(
rgba(250, 240, 20, 0.2) 0,
rgba(0, 0, 0, .8) calc(40vmax - 15vmax),
#000 calc(40vmax - 5vmax),
#000 100%
);
}
這裡是一個比原容器稍微大的新容器(注意 inset: 200px
),再設定從中心想外的徑向漸變,最外層顏色為黑色。
這樣,我們就能得到我們想要的效果了:
到這裡,完整的程式碼,你可以戳這裡:CodePen Demo -- Conic-gradient Pic
當然,上述其實只是一種實現該圖形動畫的方式。
我們還可以藉助混合模式,得到類似的效果。
這一次,我們將藉助 SASS 的隨機函數,隨機生成不同的角向漸變背景,大致的程式碼如下:
<div></div>
@function randomNum($max, $min: 0, $u: 1) {
@return ($min + random($max)) * $u;
}
@function randomConicGradient() {
$n: 16 + random(16);
$list: ();
@for $i from 0 to $n {
$list: $list, rgba(hsl(100, randomNum(250, 5, 10%), randomNum(1, 1, 1%)), randomNum(100, 0, .01));
}
@return conic-gradient($list, nth($list, 1));
}
body {
overflow: hidden;
}
div {
width: 100vw;
height: 100vh;
margin: 0;
background:
radial-gradient(hsl(9, randomNum(100, 75, 1%), randomNum(100, 75%, 1%)), black);
&:before, &:after {
position: absolute;
top: 50%; left: 50%;
margin: -100vmax;
width: 200vmax;
height: 200vmax;
opacity: .5;
animation: rotate randomNum(100, 25, .1s) ease-in-out infinite;
content: '';
}
&:before { background: randomConicGradient(); }
&:after {
background: randomConicGradient();
animation-duration: randomNum(100, 25, .1s);
animation-direction: reverse;
}
}
@keyframes rotate {
to {
transform: rotate(1turn);
}
}
上述的程式碼核心做了 3 件事:
這樣,我們可以得到這麼一種隨機效果:
這裡可能大家光看程式碼還是會有些費勁,我給大家再拆解一下,上面的圖形,大致是由下述方式疊加而來(由於顏色都是隨機生成的,所以更多的看每個結構實現了什麼樣的圖形):
嘿,有點意思,不過別急,此時,我們再給兩個偽元素,新增上一個混合模式 mix-blend-mode: overlay
:
div {
// ...
&:before, &:after {
mix-blend-mode: overlay;
}
}
這樣,整個效果就變成了:
由於,顏色是隨機的,重新整理頁面或者簡單改變一些顏色引數,得到的效果就會很不一樣,也有可能是這樣的:
或者這樣的:
藉助混合模式,我們實現了更為酷炫的效果,上述的 DEMO,完整的程式碼在這裡:CodePen Demo -- Animation conic-gradient
好,到這裡,我們再回歸最開始我們希望實現的效果:
有了上面的鋪墊,再看這個效果就沒那麼複雜了,本質就是在我們上述實現的圖形中間,鏤空一個黑色區域。
首先,我們藉助上述鋪墊的內容,實現這麼一個圖形:
接著,我們在內部,通過 mask,進行一個徑向漸變的鏤空即可,加上這麼一句簡單的程式碼:
div {
mask: radial-gradient(transparent, transparent 55%, #000 56%, #000);
}
需要結合實現 background 的引數進行偵錯。
這樣,我們就成功的實現一個類似的 Loading 圖形:
完整的程式碼,你可以戳這裡:CodePen Demo -- Animation conic-gradient & Mask
我們再看一個由 CodePen 上由 Yoav Kadosh 實現的另外一個原理類似的有意思的效果:
經由本文介紹的技巧,我們還可以演化出許多有意思的效果,讀者朋友可以自行探索!
當然,我們不難看出,CSS 還是非常有意思的。
好了,本文到此結束,希望對你有幫助