【動畫進階】神奇的卡片 Hover 效果與 Blur 的特性探究
本文,我們將一起探討探討,如下所示的一個卡片 Hover 動畫,應(yīng)該如何實現(xiàn):

這個效果的幾個難點:
- 鼠標(biāo)移動的過程中,展示當(dāng)前卡片邊緣的 border 以及發(fā)光效果;
效果只出現(xiàn)在鼠標(biāo)附近?這一塊的實現(xiàn)方法就有很多種了,可以計算鼠標(biāo)附近的范圍,在范圍內(nèi)去實現(xiàn)的效果,但是這樣成本太高了。
轉(zhuǎn)換一下思維,其實也可以利用遮罩的思想。在一開始就已經(jīng)實現(xiàn)好了整體效果,也就是漸變色的整個邊框以及整體的內(nèi)發(fā)光效果,通過遮罩的思想,讓整個遮罩層跟隨鼠標(biāo)進行移動。
- 整體的效果需要適配鼠標(biāo)的移動,跟隨鼠標(biāo)移動,進行效果的切換;
基于上述動圖中,到目前為止,純 CSS 在鼠標(biāo)移動效果跟隨上,是沒法解決的,這里需要引入一定量的 Javascript 代碼。
基于上述難點(1)(2),下面我們就一起看看如何一步一步實現(xiàn)這個效果。
搭建整個靜態(tài)效果
首先,我們需要搭建整個靜態(tài)效果。也就是在沒任何 hover 的狀態(tài)下的效果,如下所示:

由于,每張圖背后的虛化圖效果,應(yīng)該是基于圖片不同而千圖千面,因此,不可能能夠用一張背景圖 Cover 所有情況。
并且,圖片背后的虛化圖的效果,需要與實際圖片的顏色保持大致一致。
基于上述兩點,我們很容易想到使用 filter: blur() 模糊來處理此類情況。
代碼也比較簡單:
<div></div>
:root {
--pic: url("https://oss.aiyuzhou8.com/2023/05/08-.jpg");
}
div {
position: relative;
margin: auto;
width: 350px;
height: 500px;
border-radius: 30px;
overflow: hidden;
&::before,
&::after {
content: "";
position: absolute;
background: var(--pic);
background-size: cover;
background-position: center;
border-radius: 30px;
}
&::before {
inset: 0;
filter: blur(20px);
}
&::after {
inset: 50px;
}
}
這里,我們用元素的一層偽元素實現(xiàn)原圖,另外一層偽元素實現(xiàn)虛化后的圖片:

這種好處是,背后的虛化圖層,可以適配任意的不同圖片:

實現(xiàn)漸變色邊框
接下來,我們需要實現(xiàn)漸變色的邊框效果。
這個需要借助 conic-gradient 實現(xiàn)。
我們需要借助另外一個 div 實現(xiàn)我們的效果:
<div></div>
div {
width: 350px;
height: 500px;
border-radius: 30px;
background: conic-gradient(#03a9f4, #e91e63, #9c27b0, #ff5722, #03a9f4);
}
這樣,我們就得到了一個這樣的圖形:

把它疊加到我們上述的效果之上,讓整個圖形,稍微比上述虛化背景大一點點即可,如此一來,效果就變成了這樣:

仔細看,圖片帶上了漸變色的邊框。
等等,再仔細看!除了漸變色邊框之外,當(dāng)前的效果,居然還自帶了內(nèi)發(fā)光(內(nèi)陰影)效果,真是歪打正著,這不正是我們需要實現(xiàn)的嗎:

探究 filter: blur() 的透明效果
這是為何呢?原因在于,設(shè)置了 filter: blur() 的元素,會從邊緣處向中心處,帶有透明衰減的效果。
我們簡單來做個實驗:
<div></div>
<div></div>
div {
position: relative;
width: 200px;
height: 300px;
border-radius: 10px;
border: 1px solid #000;
background: conic-gradient(#03a9f4, #e91e63, #9c27b0, #ff5722, #03a9f4);
&::before {
content: "";
position: absolute;
inset: 10px;
border-radius: 10px;
background: #fff;
border: 1px solid #000;
}
}
我們設(shè)置了兩個一模一樣的 div,其中,元素本身設(shè)置了一個角向漸變背景。
接著,利用其偽元素,在元素中間相距邊界 10px 的地方,設(shè)置一個背景為白色的元素。效果如下:

此時此刻,兩個元素沒有任何不一樣。但是接下來,我們給第二個元素的偽元素,添加上一個 filter: blur() 高斯模糊效果:
div:nth-child(2) {
&::before {
filter: blur(20px);
}
}
此時,再看看效果:

在白色元素的邊緣處,向內(nèi)的方向,其實是有逐漸減弱的透明效果。
當(dāng)然,由于高斯模糊還會產(chǎn)生向外擴散的效果,因此上述 DEMO 示意圖看起來不是很清晰,我們可以通過多套一層容器,通過 overflow: hidden 阻止高斯模糊的向外擴散。
我們再調(diào)整一下布局:
<div class="g-father">
<div class="g-child"></div>
</div>
<div class="g-father">
<div class="g-child"></div>
</div>
.g-father {
position: relative;
width: 200px;
height: 300px;
border-radius: 10px;
border: 1px solid #000;
background: conic-gradient(#03a9f4, #e91e63, #9c27b0, #ff5722, #03a9f4);
.g-child {
position: absolute;
inset: 10px;
border-radius: 10px;
border: 1px solid #000;
overflow: hidden;
&::before {
content: "";
position: absolute;
inset: 0;
background: #fff;
border-radius: 10px;
}
}
}
.g-father:nth-child(2) {
.g-child::before {
filter: blur(20px);
}
}
此時,我們再看整個效果,設(shè)置了 filter: blur() 的元素,會從邊緣處向中心處,帶有透明衰減的效果就非常明顯了:

完整的 DEMO,你可以戳這里:CodePen Demo -- filter: blur 透明效果示意
鼠標(biāo)移動事件監(jiān)聽配合 mask,實現(xiàn)整體效果
好,到這里,我們已經(jīng)成功得到了這么一個效果:

基于上述效果,我們最后要做的,就是最終實現(xiàn)這么個效果:

這里,我們會利用鼠標(biāo)移動事件監(jiān)聽配合 mask 來實現(xiàn)。
由于我們上述的效果是分層實現(xiàn)的,其中邊框和內(nèi)發(fā)光層,其實是這么個背景效果:

我們要做的就是:
- 利用
radial-gradient()實現(xiàn)一個徑向漸變 mask 遮罩; - 監(jiān)聽鼠標(biāo)移動事件,移動 mask 遮罩的中心點;
- 可以通過多設(shè)置一層,實現(xiàn) Hover 時背景角向漸變元素才出現(xiàn),鼠標(biāo)離開元素區(qū)域,背景角向漸變元素消失;
大致代碼如下:
<div id="g-container">
<div id="g-img"></div>
</div>
:root {
--x: 0;
--y: 0;
}
#g-container {
position: relative;
width: 350px;
height: 500px;
border-radius: 30px;
}
#g-img {
position: absolute;
inset: 0px;
border-radius: 30px;
background: conic-gradient(#03a9f4, #e91e63, #9c27b0, #ff5722, #03a9f4);
mask: radial-gradient(
circle at var(--x) var(--y),
#000,
#000,
transparent,
transparent,
transparent
);
}
const container = document.getElementById("g-container");
const img = document.getElementById("g-img");
container.addEventListener("mousemove", (event) => {
img.style.visibility = 'visible';
const target = event.target;
const rect = target.getBoundingClientRect();
var offsetX = event.clientX - rect.left;
var offsetY = event.clientY - rect.top;
var percentX = (Math.min(Math.max(offsetX / rect.width, 0), 1) * 100).toFixed(2);
var percentY = (Math.min(Math.max(offsetY / rect.height, 0), 1) * 100).toFixed(2);;
console.log('X: ' + percentX + '%');
console.log('Y: ' + percentY + '%');
container.setAttribute('style', `--x: ${percentX}%;--y: ${percentY}%;`);
});
container.addEventListener("mouseout", (event) => {
img.style.visibility = 'hidden';
});
在圖形上方移動鼠標(biāo),我們可以得到這么一個效果:

好,將上述的前面兩個圖層也合并進來,這樣,我們就最終完美的實現(xiàn)了我們想要的效果:

完整的代碼散落在上方,就不重復(fù)貼影響閱讀體驗了,感興趣的同學(xué),可以戳這里獲取完整 DEMO 效果及源碼:
CodePen Demo -- CSS 3D Rotate With Mouse Move DEMO
最后
好了,本文到此結(jié)束,希望本文對你有所幫助 ??
想 Get 到最有意思的 CSS 資訊,千萬不要錯過我的公眾號 -- iCSS前端趣聞 ??
更多精彩 CSS 技術(shù)文章匯總在我的 Github -- iCSS ,持續(xù)更新,歡迎點個 star 訂閱收藏。
如果還有什么疑問或者建議,可以多多交流,原創(chuàng)文章,文筆有限,才疏學(xué)淺,文中若有不正之處,萬望告知。

浙公網(wǎng)安備 33010602011771號