這里給大家分享我在網(wǎng)上總結(jié)出來(lái)的一些知識(shí),希望對(duì)大家有所幫助
今日,群友提問(wèn),如何實(shí)現(xiàn)這么一個(gè) Loading 效果:
這個(gè)確實(shí)有點(diǎn)意思,但是這是 CSS 能夠完成的?
沒(méi)錯(cuò),這個(gè)效果中的核心氣泡效果,其實(shí)借助 CSS 中的濾鏡,能夠比較輕松的實(shí)現(xiàn),就是所需的元素可能多點(diǎn)。參考我們之前的:
- 使用純 CSS 實(shí)現(xiàn)超酷炫的粘性氣泡效果
- 巧用 CSS 實(shí)現(xiàn)酷炫的充電動(dòng)畫
圓弧的實(shí)現(xiàn)
首先,我們可能需要實(shí)現(xiàn)這樣一段圓?。?/p>
這里需要用到的技術(shù)是:
角向漸變?conic-gradient()
?+?mask
?以及兩個(gè)偽元素。圖片示意如下:
?核心代碼如下圖:
HTML:
<div class="g-container"> <div class="g-circle"></div> </div>
CSS:
:root { --headColor: hsl(130, 75%, 75%); --endColor: hsl(60, 75%, 40%); } .g-container { position: relative; background: #000; } .g-circle { position: relative; width: 300px; height: 300px; border-radius: 50%; background: conic-gradient( var(--headColor) 0, var(--headColor) 10%, hsl(120, 75%, 70%), hsl(110, 75%, 65%), hsl(100, 75%, 60%), hsl(90, 75%, 55%), hsl(80, 75%, 50%), hsl(70, 75%, 45%), var(--endColor) 30%, var(--endColor) 35%, transparent 35% ); mask: radial-gradient(transparent, transparent 119px, #000 120px, #000 120px, #000 100%); &::before, &::after { content: ""; position: absolute; inset: 0; width: 30px; height: 30px; background: var(--headColor); top: 0; left: 135px; border-radius: 50%; } &::after { background: var(--endColor); left: unset; top: 214px; right: 26px; } }
這樣,我們就得到了這樣一個(gè)圖形:
氣泡的實(shí)現(xiàn)
接下來(lái),我們來(lái)實(shí)現(xiàn)尾部氣泡向外擴(kuò)散的效果。
由于這里涉及了多個(gè)氣泡的不同運(yùn)動(dòng)動(dòng)畫,多個(gè)標(biāo)簽元素肯定是少不了了。
因此,接下來(lái)我們要做的事情:
- 我們需要多一組元素,將其絕對(duì)定位到上述圓環(huán)的頭部或者尾部
- 給每個(gè)子元素隨機(jī)設(shè)置多個(gè)大小不一的圓,顏色保持一致
- 給每個(gè)子元素隨機(jī)設(shè)置不同方向的,向外擴(kuò)散的位移動(dòng)畫
- 給每個(gè)子元素隨機(jī)設(shè)置負(fù)的
animation-delay
,造成動(dòng)畫上的先后順序,并以此形成整個(gè)無(wú)限循環(huán)的氣泡擴(kuò)散動(dòng)畫
這里,由于有許多小氣泡的動(dòng)畫,這個(gè)數(shù)量,我設(shè)置成了 100。那肯定是不能一個(gè)一個(gè)手寫它們的動(dòng)畫代碼,需要借助 SASS/LESS 等預(yù)處理器的循環(huán)、隨機(jī)等函數(shù)。
核心代碼如下:
HTML:
<div class="g-container"> <div class="g-circle"></div> <ul class="g-bubbles"> <li class="g-bubble"></li> // ... 共 100 個(gè) bubble 元素 <li class="g-bubble"></li> </ul> </div>
CSS:
// 上面圓環(huán)的代碼,保持一致,下面只補(bǔ)充氣泡動(dòng)畫的代碼 .g-bubbles { position: absolute; width: 30px; height: 30px; border-radius: 50px; top: 100px; left: 235px; background: var(--headColor); } .g-bubble { position: absolute; border-radius: 50%; background-color: inherit; } @for $i from 1 through 100 { .g-bubble:nth-child(#{$i}) { --rotate: calc(#{random(360)} * 1deg); --dis: calc(#{random(100)} * 1px); --width: calc(3px + #{random(25)} * 1px); top: 50%; left: 50%; transform: translate(-50%, -50%); width: var(--width); height: var(--width); animation: move #{(random(1500) + 1500) / 1000}s ease-in-out -#{random(3000) / 1000}s infinite; } } @keyframes move { 0% { transform: translate(-50%, -50%) rotate(0deg); } 75% { opacity: .9; } 100% { transform: rotateZ(var(--rotate)) translate(-50%, var(--dis)); opacity: .4; } }
核心在于 @for $i from 1 through 100 { }
這段 SASS 代碼內(nèi)部,我們實(shí)現(xiàn)了上面說(shuō)的 (2)(3)(4) 的功能點(diǎn)!
這樣,我們就得到了這樣一個(gè)效果,在尾部有大量氣泡動(dòng)畫,不斷向外擴(kuò)散的效果:
借助濾鏡實(shí)現(xiàn)粘性氣泡效果
OK,到這里整個(gè)效果基本就做完了。當(dāng)然,也是剩下最后最重要的一步,需要讓多個(gè)氣泡之間產(chǎn)生一種粘性融合的效果。
這個(gè)技巧在此前非常多篇文章中,也頻繁提及過(guò),就是利用 filter: contrast()
濾鏡與 filter: blur()
濾鏡。
如果你還不了解這個(gè)技巧,可以戳我的這篇文章看看:你所不知道的 CSS 濾鏡技巧與細(xì)節(jié)
簡(jiǎn)述下該技巧:
單獨(dú)將兩個(gè)濾鏡拿出來(lái),它們的作用分別是:
-
filter: blur()
: 給圖像設(shè)置高斯模糊效果。 -
filter: contrast()
: 調(diào)整圖像的對(duì)比度。
但是,當(dāng)他們“合體”的時(shí)候,產(chǎn)生了奇妙的融合現(xiàn)象。
仔細(xì)看兩圓相交的過(guò)程,在邊與邊接觸的時(shí)候,會(huì)產(chǎn)生一種邊界融合的效果,通過(guò)對(duì)比度濾鏡把高斯模糊的模糊邊緣給干掉,利用高斯模糊實(shí)現(xiàn)融合效果。
基于此,我們?cè)俸?jiǎn)單改造下我們的 CSS 代碼,所需要加的代碼量非常少:
- 加上濾鏡 blur() 和 contrast() ,形成融合粘性效果
- 加上整個(gè)圓環(huán)的旋轉(zhuǎn)即可效果
- 加上濾鏡 hue-rotate(),實(shí)現(xiàn)色彩的變換動(dòng)畫
.g-container { // ... 保持一致 background: #000; filter: blur(3px) contrast(5); animation: rotate 4s infinite linear; } @keyframes rotate { 100% { transform: rotate(360deg); filter: blur(3px) contrast(5) hue-rotate(360deg); } }
就這樣,我們就大致還原了題圖的效果:
完整的代碼,你可以戳這里:CodePen Demo -- Pure CSS Loading Animation
修復(fù)違和感
當(dāng)然,上面的效果,乍一看還行,仔細(xì)看,違和感很重。
原因在于,擴(kuò)散出來(lái)的小球也跟著半圓環(huán)一起進(jìn)行了旋轉(zhuǎn)動(dòng)畫,看上去就有點(diǎn)奇怪。
正確的做法應(yīng)該是,圓環(huán)尾部的氣泡應(yīng)該是原地發(fā)散消失的。
那么,怎么能夠做到氣泡效果,一直發(fā)生在圓環(huán)的尾部,同時(shí)消失的時(shí)候又不跟著整個(gè)圓環(huán)一起進(jìn)行旋轉(zhuǎn)呢?我們想要的最終效果,應(yīng)該是這樣:
這里,我們可以拆解一下。想象,如果去掉圓環(huán)的旋轉(zhuǎn),其實(shí)我們只需要實(shí)現(xiàn)這樣一個(gè)效果即可:
整個(gè)動(dòng)畫的核心就轉(zhuǎn)變成了如何實(shí)現(xiàn)這么一個(gè)效果??此茝?fù)雜,其實(shí)也很好做。
首先,我們重新改造一下上述的 .g-bubbles
。
- 生成 N 個(gè)一樣大小的小球元素,定位在整個(gè)容器的中間
<div class="g-container"> <div class="g-circle"></div> <ul class="g-bubbles"> <li class="g-bubble"></li> // ... 共 200 個(gè) bubble 元素 <li class="g-bubble"></li> </ul> </div>
CSS:
.g-bubbles { position: absolute; width: 30px; height: 30px; transform: translate(-50%, -50%); left: 50%; top: 50%; border-radius: 50px; } .g-bubble { position: absolute; inset: 0; border-radius: 50%; background: hsl(60, 75%, 40%); }
得到這么一個(gè)效果,所有圓形小點(diǎn),都暫時(shí)匯聚在容器的中心:
這里需要簡(jiǎn)單解釋一下:
其次,我們借助 SASS,按照元素的順序,把它們順序排列到圓環(huán)軌跡之上:
$count: 200; @for $i from 1 through $count { .g-bubble:nth-child(#{$i}) { --rotate: calc(#{360 / $count} * #{$i} * 1deg); transform: rotateZ(var(--rotate)) translate(135px, 0); opacity: 1; } }
由于我們?cè)O(shè)置了 div 小球的個(gè)數(shù)為 200 個(gè),這樣,我們就得到了一圈由 200 個(gè)圓形小球形成的圓環(huán):
接下來(lái)這一步非常重要,我們?cè)O(shè)定一個(gè)動(dòng)畫:
- 讓每個(gè)小球在動(dòng)畫的
75% ~ 100%
階段做透明度從 1 到 0 的變換,而0% ~ 75%
的階段保持透明度為 0 - 讓 200 個(gè) div 依次進(jìn)行這個(gè)動(dòng)畫效果(利用負(fù)的 animation-delay,從 -0 到 -4000ms),整體上就能形成逐漸消失的效果
@for $i from 1 through $count { .g-bubble:nth-child(#{$i}) { --rotate: calc(#{360 / $count} * #{$i} * 1deg); --delayTime: calc(4000 * #{$i / $count} * -1ms); transform: rotateZ(var(--rotate)) translate(135px, 0); opacity: 1; animation: showAndHide 4000ms linear var(--delayTime) infinite; } } @keyframes showAndHide { 0% { opacity: 0; } 75% { opacity: 0; } 75.1% { opacity: 1; } 100% { opacity: 0; } }
這樣,我們就得到了一個(gè)圓形小球氣泡圍繞圓環(huán)漸次消失的效果:
配合上整個(gè)圓環(huán),效果就會(huì)是這樣:
很接近了,但是沒(méi)有隨機(jī)的感覺(jué),氣泡也沒(méi)有散開(kāi)的動(dòng)畫。解決的方案:
- 所以我們需要讓氣泡在執(zhí)行透明度變化的同時(shí),進(jìn)行一個(gè)隨機(jī)的發(fā)散位移
- 小圓形氣泡的大小也可以帶上一點(diǎn)隨機(jī),同時(shí),在動(dòng)畫過(guò)程逐漸縮小
當(dāng)然,整個(gè)動(dòng)畫的基礎(chǔ),還是在容器設(shè)置了 濾鏡 blur() 和 contrast() 的加持之下的,這樣,我們給氣泡再補(bǔ)上隨機(jī)動(dòng)畫散開(kāi)及縮放的動(dòng)畫:
@for $i from 1 through $count { .g-bubble:nth-child(#{$i}) { --rotate: calc(#{360 / $count} * #{$i} * 1deg); --delayTime: calc(4000 * #{$i / $count} * -1ms); --scale: #{0.4 + random(10) / 10}; --x: #{-100 + random(200)}px; --y: #{-100 + random(200)}px; transform: rotateZ(var(--rotate)) translate(135px, 0); opacity: 1; animation: showAndHide 4000ms linear var(--delayTime) infinite; } } @keyframes showAndHide { 0% { transform: rotateZ(var(--rotate)) translate(135px, 0); opacity: 0; } 75% { opacity: 0; } 75.1% { transform: rotateZ(var(--rotate)) translate(135px, 0) scale(var(--scale)); opacity: 1; } 100% { transform: rotateZ(var(--rotate)) translate(calc(135px + var(--x)), var(--y)) scale(.2); opacity: 0; } }
只看一圈的氣泡圓形,我們能得到了這樣的效果:
配合上圓環(huán)的效果:
配合上父容器的 filter: hue-rotate()
動(dòng)畫,就能實(shí)現(xiàn)顏色的動(dòng)態(tài)變換,得到我們最終想要的效果:
這樣,沒(méi)有了第一版本的違和感,整個(gè)效果也顯得比較自然。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-427141.html
整體代碼:
HTML:
<div class="g-container"> <div class="g-circle"></div> <ul class="g-bubbles"> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> <li class="g-bubble"></li> </ul> </div>
CSS:
body, html { width: 100%; height: 100%; display: grid; place-content: center; background: #000; overflow: hidden; } $count: 200; :root { --headColor: hsl(130, 75%, 75%); --endColor: hsl(60, 75%, 40%); } .g-container { position: relative; width: 300px; height: 300px; padding: 100px; filter: blur(3px) contrast(3); background: #000; animation: hueRotate 8s infinite linear; } .g-circle { position: relative; width: 300px; height: 300px; border-radius: 50%; background: conic-gradient( var(--headColor) 0, var(--headColor) 2%, hsl(120, 75%, 70%), hsl(110, 75%, 65%), hsl(100, 75%, 60%), hsl(90, 75%, 55%), hsl(80, 75%, 50%), hsl(70, 75%, 45%), var(--endColor) 16%, var(--endColor) 18%, transparent 18% ); mask: radial-gradient(transparent, transparent 119px, #000 120px, #000); -webkit-mask: radial-gradient(transparent, transparent 119px, #000 120px, #000); animation: rotate 4s infinite -700ms linear; &::before, &::after { content: ""; position: absolute; inset: 0; width: 32px; height: 32px; background: var(--headColor); top: 0; left: 135px; border-radius: 50%; } &::after { background: var(--endColor); left: unset; top: 80px; right: 10px; } } .g-bubbles { position: absolute; width: 30px; height: 30px; transform: translate(-50%, -50%); left: 50%; top: 50%; border-radius: 50px; } .g-bubble { position: absolute; border-radius: 50%; background: var(--endColor); } @for $i from 1 through $count { .g-bubble:nth-child(#{$i}) { --rotate: calc(#{360 / $count} * #{$i} * 1deg); --delayTime: calc(4000 * #{$i / $count} * -1ms); --width: 30px; --scale: #{0.4 + random(10) / 10}; --x: #{-100 + random(200)}px; --y: #{-100 + random(200)}px; width: var(--width); height: var(--width); transform: rotateZ(var(--rotate)) translate(135px, 0); opacity: 1; animation: showAndHide 4000ms linear var(--delayTime) infinite; } } @keyframes showAndHide { 0% { transform: rotateZ(var(--rotate)) translate(135px, 0); opacity: 0; } 75% { opacity: 0; } 75.1% { transform: rotateZ(var(--rotate)) translate(135px, 0) scale(var(--scale)); opacity: 1; } 100% { transform: rotateZ(var(--rotate)) translate(calc(135px + var(--x)), var(--y)) scale(.2); opacity: 0; } } @keyframes rotate { 100% { transform: rotate(-360deg); } } @keyframes hueRotate { 100% { filter: blur(3px) contrast(3) hue-rotate(360deg); } }
本文轉(zhuǎn)載于:
https://juejin.cn/post/7221320687430942781
如果對(duì)您有所幫助,歡迎您點(diǎn)個(gè)關(guān)注,我會(huì)定時(shí)更新技術(shù)文檔,大家一起討論學(xué)習(xí),一起進(jìn)步。
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-427141.html
到了這里,關(guān)于記錄-有意思的氣泡 Loading 效果的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!