您現在的位置是:首頁 > 網頁遊戲首頁網頁遊戲
CSS mask 實現滑鼠跟隨鏤空效果
- 2021-12-22
zbrush怎麼讓物體居中
前言
偶然在某思看到這樣一個問題,如何使一個div的部分割槽域變透明而其他部分模糊掉?,最後實現效果是這樣的
進一步,還能實現任意形狀的鏤空效果
滑鼠經過的地方清晰可見,其他地方則是模糊的。
可能一開始無從下手,不要急,可以先從簡單的、類似的效果開始,一步一步嘗試,一起看看吧。
一、普通半透明的效果
比如平時開發中碰到更多的可能是一個半透明的效果,有點類似於探照燈(滑鼠外面的地方是半透明遮罩,看起來會暗一點)。如下:
那先從這種效果開始吧,假設有這樣一個佈局:
那麼如何繪製一個鏤空的圓呢?先介紹一種方法
其實很簡單,只需要一個足夠大的投影就可以了,原理如下
這裡可以用偽元素::before來繪製,結構更加精簡。用程式碼實現就是
。wrap::before{ content:‘’; position: absolute; width: 100px; height: 100px; border-radius: 50%; left: 50%; top: 50%; transform: translate(-50%,-50%); /*預設居中*/ box-shadow: 0 0 0 999vw rgba(0, 0, 0, 。5); /*足夠大的投影*/}複製程式碼
可以得到這樣的效果
二、藉助 CSS 變數傳遞滑鼠位置
按照以往的經驗,可能會在 js 中直接修改元素的 style 屬性,類似這樣
img。addEventListener(‘mousemove’, (ev) => { img。style。left = ‘。。。’; img。style。top = ‘。。。’;})複製程式碼
但是這樣互動與業務邏輯混雜在一起,不利於後期維護。其實,我們只需要滑鼠的座標,在 CSS 中也能完全實現跟隨的效果。
這裡藉助 CSS 變數,那一切就好辦了!假設滑鼠的座標是 [——x,——y](範圍是[0, 1]),那麼遮罩的座標就可以使用 calc計算了
。wrap::before{ left: calc(var(——x) * 100%); top: calc(var(——y) * 100%);}複製程式碼
然後滑鼠座標的獲取可以使用 JS 來計算,也比較容易,如下
img。addEventListener(‘mousemove’, (ev) => { img。style。setProperty(‘——x’, ev。offsetX / ev。target。offsetWidth); img。style。setProperty(‘——y’, ev。offsetY / ev。target。offsetHeight);})複製程式碼
這樣,半透明效果的鏤空效果就完成了
完整程式碼可以訪問: backdrop-shadow (codepen。io)
三、漸變也能實現半透明的效果
除了上述陰影擴充套件的方式,
CSS 徑向漸變
也能實現這樣的效果
繪製一個從透明到半透明的漸變,如下
。wrap::before{ content: ‘’; position: absolute; width: 100%; height: 100%; left: 0; top: 0; background: radial-gradient( circle at center, transparent 50px, rgba(0,0,0,。5) 51px);}複製程式碼
可以得到這樣的效果
然後,把滑鼠座標對映上去就可以了。從這裡就可以看出 CSS 變數的好處,無需修改 JS,只需要在CSS中
修改漸變中心點
的位置就可以實現了
。wrap::before{ background: radial-gradient( circle at calc(var(——x) * 100% ) calc(var(——y) * 100% ), transparent 50px, rgba(0,0,0,。5) 51px);}複製程式碼
四、背景模糊的效果嘗試
CSS 中有一個專門針對背景(元素後面區域)的屬性:backdrop-filter。使用方式和 filter完全一致!
backdrop-filter: blur(10px);複製程式碼
下面是 MDN 中的一個示意效果
backdrop-filter是讓當前
元素所在區域後面的內容
模糊,要想看到效果,需要元素本身半透明或者完全透明;而filter是讓當前
元素自身
模糊。有興趣的可以檢視這篇文章: CSS backdrop-filter簡介與蘋果iOS毛玻璃效果 « 張鑫旭-鑫空間-鑫生活 (zhangxinxu。com)
需要注意的是,這種
模糊與背景的半透明度沒有任何關係
,哪怕元素本身是透明的,仍然會有效果。例如下面是去除背景後的效果 ,整塊都是模糊的
如果直接運用到上面的例子會怎麼樣呢?
1。 陰影實現
在上面第一個例子中新增 backdrop-filter
。wrap::before{ content:‘’; position: absolute; width: 100px; height: 100px; border-radius: 50%; left: 50%; top: 50%; transform: translate(-50%,-50%); /*預設居中*/ box-shadow: 0 0 0 999vw rgba(0, 0, 0, 。5); /*足夠大的投影*/ backdrop-filter: blur(5px)}複製程式碼
得到效果如下
可以看到圓形區域是模糊的,正好和希望的效果相反。其實也好理解,只有圓形區域才是真實的結構,外面都是陰影,所以最後作用的範圍也只有圓形部分
2。 漸變實現
現在在第二個例子中新增 backdrop-filter
。wrap::before{ content: ‘’; position: absolute; width: 100%; height: 100%; left: 0; top: 0; background: radial-gradient( circle at calc(var(——x) * 100% ) calc(var(——y) * 100% ), transparent 50px, rgba(0,0,0,。5) 51px); backdrop-filter: blur(5px)}複製程式碼
效果如下
已經全部都模糊了,只是圓形區域外暗一些。由於::before的尺寸佔據整個容器,所以整個背後都變模糊了,圓形外部比較暗是因為半透明漸變的影響。
總之還是不能滿足我們的需求,需要尋求新的解決方式。
五、CSS MASK 實現鏤空
與其說是讓圓形區域不模糊,還不如說是把那塊區域給鏤空了。就好比之前是一整塊磨砂玻璃,然後透過
CSS MASK
打了一個圓孔,這樣透過圓孔看到後面肯定是清晰的。
可以對第二個例子稍作修改,透過徑向漸變繪製一個透明圓,剩餘部分都是純色的遮罩層,示意如下
用程式碼實現就是
。wrap::before{ content: ‘’; position: absolute; width: 100%; height: 100%; left: 0; top: 0; -webkit-mask: radial-gradient( circle at calc(var(——x, 。5) * 100% ) calc(var(——y, 。5) * 100% ), transparent 50px, #000 51px); background: rgba(0,0,0,。3); backdrop-filter: blur(5px)}複製程式碼
這樣就實現了文章開頭的效果
完整程式碼可以檢視:backdrop-mask (codepen。io)
六、CSS MASK COMPOSITE 實現更豐富的鏤空效果
除了使用徑向漸變繪製遮罩層以外,還可以透過
CSS MASK COMPOSITE(遮罩合成)
的方式來實現。標準關鍵值如下(firefox支援):
/* 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: exclude)打一個孔就行了,實現如下
。wrap::before{ content: ‘’; position: absolute; width: 100%; height: 100%; left: 0; top: 0; -webkit-mask: url(“data:image/svg+xml,%3Csvg width=‘50’ height=‘50’ viewBox=‘0 0 50 50’ fill=‘none’ xmlns=‘http://www。w3。org/2000/svg’%3E%3Ccircle cx=‘25’ cy=‘25’ r=‘25’ fill=‘%23C4C4C4’/%3E%3C/svg%3E”), linear-gradient(red, red); -webkit-mask-size: 50px, 100%; -webkit-mask-repeat: no-repeat; -webkit-mask-position: calc(var(——x, 。5) * 100% + var(——x, 。5) * 100px - 50px ) calc(var(——y, 。5) * 100% + var(——y, 。5) * 100px - 50px ), 0; -webkit-mask-composite: xor; /*只顯示不重合的地方, chorem 、safari 支援*/ mask-composite: exclude; /* 排除,只顯示不重合的地方, firefox 支援 */ background: rgba(0,0,0,。3); backdrop-filter: blur(5px)}複製程式碼
需要注意-webkit-mask-position中的計算,這樣也能很好的實現這個效果
完整程式碼可以檢視:backdrop-mask-composite (codepen。io)
你可能已經發現,上述例子中的圓是透過 svg 繪製的,還用到了遮罩合成,看著好像更加繁瑣了。其實呢,這是一種更加萬能的解決方式,可以帶來無限的可能性。比如我需要一個星星⭐️的鏤空效果,很簡單,先透過一個繪製軟體畫一個
然後把這段 svg 程式碼轉義一下,這裡推薦使用張鑫旭老師的SVG線上壓縮合並工具
替換到剛才的例子中就可以了
。wrap::before{ content: ‘’; position: absolute; width: 100%; height: 100%; left: 0; top: 0; -webkit-mask: url(“data:image/svg+xml,%3Csvg width=‘96’ height=‘91’ viewBox=‘0 0 96 91’ fill=‘none’ xmlns=‘http://www。w3。org/2000/svg’%3E%3Cpath d=‘M48 0l11。226 34。55h36。327l-29。39 21。352L77。39 90。45 48 69。098 18。61 90。451 29。837 55。9。447 34。55h36。327L48 0z’ fill=‘%23C4C4C4’/%3E%3C/svg%3E”), linear-gradient(red, red); -webkit-mask-size: 50px, 100%; -webkit-mask-repeat: no-repeat; -webkit-mask-position: calc(var(——x, 。5) * 100% + var(——x, 。5) * 100px - 50px ) calc(var(——y, 。5) * 100% + var(——y, 。5) * 100px - 50px ), 0; -webkit-mask-composite: xor; /*只顯示不重合的地方, chorem 、safari 支援*/ mask-composite: exclude; /* 排除,只顯示不重合的地方, firefox 支援 */ background: rgba(0,0,0,。3); backdrop-filter: blur(5px)}複製程式碼
星星鏤空實現效果如下
完整程式碼可以檢視:backdrop-star (codepen。io)
再比如一個心形❤,實現效果如下
完整程式碼可以檢視:backdrop-heart (codepen。io)
只有想不到,沒有做不到
七、總結和說明
以上實現了一個滑鼠跟隨鏤空的效果,從簡單到複雜,從單一到通用,雖然藉助了一點點 JS ,但是僅僅是“工具人”的角色,互動邏輯全部都由 CSS 完成,下面總結一下:
足夠大的陰影是一個實現圓形鏤空效果的小技巧
CSS 漸變也能輕易的繪製出圓形鏤空背景
藉助 CSS 變數可以很方便的利用滑鼠位置實現想要的效果
backdrop-filter 可以想象成磨砂玻璃的功能
CSS Mask 可以給磨砂玻璃打孔,實現鏤空的效果
藉助遮罩合成特性和SVG,可以實現任意形狀的鏤空效果
CSS MASK 還是非常強大的,有必要還是多掌握一下。最後,如果覺得還不錯,對你有幫助的話,歡迎點贊、收藏、轉發❤❤❤