#引言
在前端開發中, CSS 不再僅僅用於佈局和樣式修飾, 越來越多的高級視覺效果也可以通過純 CSS 實現, 其中就包括令人驚豔的 蒙版 效果。mask-image 作為 CSS 中用於控制元素可見區域的強大屬性, 能夠幫助開發者實現類似 Photoshop 中的遮罩操作, 無需藉助複雜的圖像處理。無論是實現漸隱文字、柔和的圖像遮罩, 還是動態的 手電筒 追光效果, mask-image 都提供了靈活而優雅的解決方案。本文將深入介紹 mask-image 的基本用法、支持的各種類型(如漸變、SVG)、配套屬性 (如 mask-mode), 並結合多個實戰示例, 帶你全面掌握 CSS 蒙版的使用技巧。
#一、基本語法
mask-image 是 CSS 中用來定義蒙版效果的一個屬性。它可以根據一個圖像或漸變、控制 元素 的可見區域, 實現類似 Photoshop 中的蒙版功能。
如下代碼所示, background-image 所支持的 值 在 mask-image 都可以適用, 並且類似 background 系列屬性, mask-* 中也都有對應的屬性, 用於設置蒙版圖參數
html
<divclassName="wrapper" />
<style>
.wrapper {
width: 500px;
height: 500px;
// 設置背景圖
background-image: url('./bg.png');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
// 設置蒙版
mask-image: url('./mask_alpha.png');
mask-size: 100%;
mask-repeat: no-repeat;
mask-position: center;
}
</style>
如下圖是上面代碼效果, 默認情況下 遮罩圖像的 Alpha(透明度) 的值將會作用於 元素:
- 透明度為
100%的區域, 則會完全展示對應元素內容 - 透明度為
0%的區域, 則會完全隱藏對應元素內容
#二、 使用漸變
同 background-image 我們這邊也是可以使用漸變的:
html
<divclassName="wrapper" />
<style>
.wrapper {
width: 500px;
height: 500px;
// 設置背景圖
background-image: url('./bg.png');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
// 設置漸變蒙版
mask-image: linear-gradient(to bottom, rgb(25500 / 0%) 0%, rgb(25500 / 100%) 100%);
}
</style>
如上代碼, mask-image 設置為一個漸變效果, 整個漸變只是在透明度上發生變化, 而最終效果如下:
#三、 使用 SVG
注意不同於 background-image, mask-image 還可以設置為某個 svg 上的 <mask/>。如下代碼所示我們在 svg 中定義了一個 <mask/> 並在 mask-image 中通過 url('#mask') 方式進行了引用。
html
<divclassName="wrapper" />
<svgviewBox="-10 -10 300 300">
<maskid="mask">
<ellipse
cx="50%"
cy="50%"
rx="25%"
ry="25%"
fill="white"
/>
</mask>
</svg>
<style>
.wrapper {
width: 500px;
height: 500px;
// 設置背景圖
background-image: url('./bg.png');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
// 設置漸變蒙版
mask-image: url('#mask');
}
</style>
而最終的效果如下:
#四、可應用於任意元素
我們先將上文用到的蒙版圖片轉為 base64 數據
下面我們在掘金上進行嘗試, 在控制枱直接在 body 上設置蒙版:
上面例子是為了説明蒙版可作用於任何元素, 可直接將任意元素部分 蒙 住
#五、 mask-mode: 設置蒙版規則
上文我們提到, 默認情況下 遮罩圖像的 Alpha(透明度) 的值將會作用於 元素:
- 透明度為
100%的區域, 則會完全展示對應元素內容 - 透明度為
0%的區域, 則會完全隱藏對應元素內容
之所以如此是因為 mask-mode 默認值為 match-source 即模版作用規則由源決定, 這裏就兩種情況:
- 如果
mask-image引用的是SVG中的<mask>, 則使用其mask-type屬性值(如果存在)。如果未明確設置, 則此值默認為Alpha模式。 - 如果蒙版圖片的源是
<image>或<gradient>, 則使用蒙版圖像的Alpha值。
那麼除了 Alpha 模式之外還有其他的模式嗎? 有的, 那就是 luminance(亮度), 即根據模版圖片不同的亮度來控制元素的顯隱:
- 蒙版圖片中黑色區域, 其對應位置元素完全透明(不可見)
- 蒙版圖片中白色區域, 其對應位置元素完全不透明(可見)
- 蒙版圖片中灰色區域, 其對應位置元素半透明
- 蒙版圖片中越白部分, 其對應位置元素透明度越高, 反之越黑則透明度越低
而這裏我們可通過 mask-mode: <alpha | luminance | match-source>, 來設置模版作用模式, 如下代碼所示
html
<divclassName="wrapper" />
<style>
.wrapper {
width: 500px;
height: 300px;
background-image: url("./bg.png");
background-size: cover;
background-position: center;
background-repeat: no-repeat;
// 設置蒙版模式為亮度模式
mask-mode: luminance;
// 蒙版圖片為漸變, 即白 => 黑
mask-image: linear-gradient(to bottom, #fff, #000);
mask-size: 100%;
mask-repeat: no-repeat;
mask-position: center;
}
</style>
最終效果如下, 蒙版白色部分元素完全可見, 黑色部分元素不可見, 中間灰色過渡對應的就是元素可見度的過渡
#六、 DEMO: 漸變隱藏
我們要實現這麼一個效果:
- 我們有個容器, 容器高度是自適應
- 同時容器最大高度默認為
200px超出部分需要隱藏 - 但是如果直接隱藏容器底部過渡就特別生硬
- 如下代碼所示:
html
<divclassName="container">
<p>
我經常遇到兩種候選人。一種是一聽算法題, 就兩手一攤, 表情痛苦, 説“哥, 我天天寫業務, 真沒準備這個”。另一種呢, 正好相反, 題目一出, 眼睛一亮, 不出三十秒, 就把 LeetCode 上背得滾瓜爛熟的最優解, 一字不差地敲了出來, 然後一臉期待地看着我。
説實話, 這兩種, 都不是我最想看到的。
</p>
<p>
這就引出了一個很多候選人都想問, 但不敢問的問題:“你們這些面試官, 到底怎麼想的?你們明知道我們前端平時工作中, 99%的時間都用不上這些, 為什麼非要折磨我們?”
今天, 我就想站在桌子對面, 跟大夥掏心窩子地聊聊, 我們問算法題, 到底圖個啥。
</p>
</div>
<style>
.container {
width: 400px;
color: #999;
max-height: 200px;
overflow: hidden;
}
</style>
最後效果如下, 容器底部文字硬生生的被切斷了
而更好的效果應該是有個完美的過渡效果, 這裏我們就可以使用蒙版來處理: 如下代碼所示, 蒙版是一個漸變, 從下到上, 漸變透明度從 0 ~ 100 一個過渡
diff
<style>
.container {
width: 400px;
color: #999;
max-height: 200px;
overflow: hidden;
+ mask-image: linear-gradient(to top, rgb(0 0 0 / 0%), rgb(0 0 0 / 100%) 40px);
}
</style>
而最終效果如下: 整個過渡還是很絲滑的
然而有些站點為了實現上述過渡效果, 簡單粗暴的在容器底部覆蓋了一層漸變背景圖! 而如此實在不夠優雅, 如果頁面背景複雜的話就完全沒有效果!
但是用我們的方式肯定就能應付上面這情況了。
下面看另一個例子, 有代碼如下:
html
<divclassName="container">
我經常遇到兩種候選人。一種是一聽算法題, 就兩手一攤, 表情痛苦, 説“哥, 我天天寫業務, 真沒準備這個”。另一種呢,
正好相反, 題目一出, 眼睛一亮, 不出三十秒不出三十秒, 就把 LeetCode 上背得滾瓜爛熟的最優解, 一字不差地敲了出來,
然後一臉期待地看着我。
</div>
<style>
.container {
width: 400px;
color: #999;
max-height: 200px;
overflow: hidden;
}
</style>
效果如下, 但是我們希望在第二行行末, 有個漸隱的效果:
下面我們直接改代碼:
html
<divclassName="container">
我經常遇到兩種候選人。一種是一聽算法題, 就兩手一攤, 表情痛苦, 説“哥, 我天天寫業務, 真沒準備這個”。另一種呢,
正好相反, 題目一出, 眼睛一亮, 不出三十秒不出三十秒, 就把 LeetCode 上背得滾瓜爛熟的最優解, 一字不差地敲了出來,
然後一臉期待地看着我。
</div>
<style>
.container {
width: 600px;
color: #999;
line-height: 1.6em;
max-height: 3.2em;
overflow: hidden;
mask-mode: luminance;
mask-image: radial-gradient(ellipse 1000px300px at 100%40px, #000, #fff10%, #fff10%);;
}
</style>
最終效果:
而這裏實際上使用了橢圓漸變來實現蒙版, 我們可以把蒙版改為背景, 來看下蒙版圖片的樣子:
diff
.container {
width: 600px;
color: #999;
line-height: 1.6em;
max-height: 3.2em;
overflow: hidden;
+ background-image: radial-gradient(ellipse 1000px 300px at 100% 40px, #000, red 10%, red 10%);;
}
如下圖所示:
#七、 DEMO: 手電筒
你也許看到過下圖類似的一個效果, 這看起來也許很唬人, 但是實際上了解了蒙版的概念後, 實現這麼一個效果還是很簡單的:
如下代碼所示:
- 我們只需要通過
onMouseMove和onMouseLeave來記錄鼠標移動位置 - 並將鼠標位置存儲下來, 轉為
CSS變量--client-x以及--client-y - 最後使用動態的
CSS變量來渲染蒙版即可
js
constMaskImagePage: FC = () => {
const [client, setClient] = useState(HIDE_CLIENT);
const handleMouseMove = useCallback((e) => {
setClient({
x: e.clientX,
y: e.clientY,
});
}, []);
const handleMouseLeave = useCallback(() => {
setClient(HIDE_CLIENT);
}, []);
return (
<div
className="page"
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
style={{
'--client-x': `${client.x}px`,
'--client-y': `${client.y}px`,
}}
/>
);
};
css
.page {
width: 100vw;
height: 100vh;
background-image: url("./page_bg.png"); // 隨便一個背景圖, 這個不重要
background-size: 100%100%;
mask-mode: luminance;
mask-image: radial-gradient(circle at var(--client-x) var(--client-y), #fff, #000100px);
}
#八、DEMO: 驚豔的過渡轉場
在 奇妙的 CSS MASK 一文中, 有這麼一個效果:
而這裏就使用到蒙版, 蒙版圖片如下所示, 其實就是好多幀蒙版拼接出來的一個長圖:
而關鍵代碼如下, 其實就是通過控制 mask-position 控制蒙版圖片的位置, 從而實現過渡的轉場效果:
css
.container {
mask-image: url(https://i.imgur.com/AYJuRke.png);
mask-size: 3000%100%;
}
@keyframes maskMove {
from {
mask-position: 00;
}
to {
mask-position: 100%0;
}
}
完整 DEMO 查看: mask 製作轉場動畫
#九、參考文檔
- CSDN - mask-image
- css-tricks mask-image
- 奇妙的 CSS MASK