CSS 遮罩簡介
CSS 遮罩允許你透過為一個元素應用一個或多個遮罩影像,從而選擇性地顯示或隱藏該元素的部分內容。這些遮罩影像可以是漸變、影像或 SVG 源。與 CSS 裁剪不同——後者基於單一路徑的形狀來完全顯示或隱藏元素的區域——遮罩可以基於遮罩影像的 Alpha 透明度以及(可選的)亮度,實現更細微的透明度和混合效果。
本指南介紹了遮罩的概念、各種遮罩影像型別,以及遮罩的亮度和 Alpha 透明度如何影響元素被遮罩(可見)的部分,以及被裁剪(或隱藏)的部分。
CSS 中的遮罩是什麼?
在 CSS 中,遮罩可用於定義元素的可見區域和隱藏區域。由一個或多個 mask-image 源定義的遮罩層,決定了元素哪些區域應該可見以及其不透明度。
備註: 可以使用 mask 簡寫屬性設定多個 CSS 遮罩屬性值。
對於 alpha 遮罩,被遮罩元素的不透明度與應用的遮罩的不透明度相匹配。在 CSS 中,遮罩與化裝舞會面具的作用相反,後者是在面具不透明的地方隱藏臉部。而在 CSS 中,元素中其遮罩完全不透明的區域將是完全不透明且可見的。在遮罩完全透明的地方,元素將完全隱藏。被部分不透明遮罩區域遮罩的元素區域將是部分不透明的,與其遮罩的不透明度相匹配。
對於 Alpha 遮罩,遮罩的顏色無關緊要,只有遮罩的不透明度才重要。而對於亮度遮罩,在確定被遮罩元素的不透明度時,會考慮遮罩顏色的亮度。顏色越亮、越不透明,元素就越不透明。顏色越暗、越透明,遮罩的不透明度就越低。
遮罩可以使用 CSS 漸變、柵格影像(如 PNG)和 SVG <mask> 元素來定義。在本指南中,我們將在討論不透明度和透明度、亮度以及遮罩與 CSS 裁剪時,介紹各種遮罩影像型別。
每個遮罩層都包含一個 mask-image,該影像相對於一個原點框進行定位。遮罩影像可以被調整大小、重複和裁剪。在聲明瞭多個遮罩影像的情況下,可以設定遮罩層的合成或組合方式。這些內容將在遮罩屬性指南中討論。
備註: 所有示例都將使用以下影像作為應用遮罩的基礎元素。
不透明度與透明度
對於 Alpha 遮罩,元素的可見區域由應用於其上的遮罩的 Alpha 透明度定義。在遮罩完全不透明的地方,元素將是可見的。在遮罩完全透明的每個畫素點,元素也將完全隱藏。被遮罩的部分不透明區域遮罩的元素區域將是部分不透明的,與其所應用的遮罩的不透明度相匹配。
使用漸變
為了說明這一點,我們來看一個使用 conic-gradient() 作為 mask-image 的示例。CSS 漸變,包括錐形漸變,可用於在可見和隱藏區域之間建立平滑過渡。
在這種情況下,遮罩的右上角是完全不透明的,左上象限是完全透明的,下半部分則在不透明和透明之間平滑過渡。
.applied-mask {
mask-image: conic-gradient(black 90deg, transparent 270deg);
}
.mask-source {
background: conic-gradient(black 90deg, transparent 270deg);
}
請注意,應用了遮罩的元素的右上角是完全可見的,左上角被隱藏,下半部分則從可見平滑過渡到透明,這反映了所應用的遮罩影像的可見性。
對於 Alpha 遮罩,遮罩的顏色不重要,只有透明度才重要。在這個示例中,我們有一個條紋漸變,包含完全不透明的紅色、半透明的紅色和完全透明的條紋。
.applied-mask {
mask-image: repeating-linear-gradient(
to bottom right,
red 0 20px,
#ff000055 20px 40px,
transparent 40px 60px
);
}
.mask-source {
background: repeating-linear-gradient(
to bottom right,
red 0 20px,
#ff000055 20px 40px,
transparent 40px 60px
);
}
請注意,完全不透明的遮罩區域會顯示完全不透明的元素畫素,半透明的遮罩區域會建立半透明的區域,而完全透明的遮罩區域會完全隱藏相關區域。
使用匯入的影像
前兩個示例使用漸變作為遮罩和背景影像。遮罩影像不一定是 CSS 影像,也可以是外部影像或 SVG。
在這種情況下,我們使用一個外部 PNG 影像。該影像包含一個帶有透明背景的彩色心形。
.applied-mask {
mask-image: url("https://mdn.github.io/shared-assets/images/examples/colorful-heart.png");
mask-size: 220px 220px;
}
.mask-source {
background: url("https://mdn.github.io/shared-assets/images/examples/colorful-heart.png");
background-size: 220px 220px;
}
請注意透明的遮罩區域如何裁剪元素;元素中唯一可見的部分是遮罩不透明的區域。遮罩本身的顏色無關緊要。
Alpha 透明度與亮度
mask-mode 屬性的預設值——match-source——會根據具體值將模式設定為 alpha 或 luminance。對於除 SVG <mask> 元素外的所有遮罩源,match-source 值會解析為 alpha。如果遮罩源是 <mask> 元素,match-source 會解析為該 <mask> 的 mask-type 屬性值(如果已設定)。否則,它會解析為在 <mask> 元素上設定的 SVG mask-type 屬性的值。如果該屬性也未明確設定,match-source 將解析為 luminance。
如果 mask-mode 解析為 luminance,或者我們明確將其設定為 luminance,遮罩的顏色將影響遮罩的不透明度。在前面的演示中,沒有設定 mask-mode,因此其值預設為 match-source。由於彩色心形影像是透明的 PNG,match-source 解析為 alpha。透過明確設定此屬性,我們可以控制模式。在此演示中,我們將 mask-mode 更改為 luminance。
.applied-mask {
mask-mode: luminance;
}
當對與前一個示例相同的遮罩應用 mask-mode: luminance 時,元素中遮罩顏色最亮的區域更不透明,而較暗的區域則不那麼不透明。
亮度遮罩的不透明度由 RGB 顏色的 R、G、B 和 A 值透過以下公式確定:
((0.2125 * R) + (0.7154 * G) + (0.0721 * B)) * A
例如,最新的 <named-color> 是 rebeccapurple,即 #663399。雖然人們可能認為其亮度可能等同於 hsl() 顏色函式的 L 值,但並非如此簡單。值 #663399 等同於 rgb(40% 20% 60% / 1) 和 hsl(270 50% 40% / 1),但其亮度值為 27.134%,而不是 40%。
((0.2125 * 0.4) + (0.7154 * 0.2) + (0.0721 * 0.6)) * 1 = 0.27134
白色的亮度值為 100%。
((0.2125 * 1) + (0.7154 * 1) + (0.0721 * 1)) * 1 = 1
黑色的亮度為 0%。
((0.2125 * 0) + (0.7154 * 0) + (0.0721 * 0)) * 1 = 0
我們將透過在一個包含 rebeccapurple、white 和 black 的線性漸變中,新增不透明度為 27.234% 的白色(rgb(100% 100% 100%),其亮度為 100%)來演示這一點,然後用這個漸變來遮罩我們的影像。這個白色會解析為相同的不透明度值。
((0.2125 * 1) + (0.7154 * 1) + (0.0721 * 1)) * 0.27134 = 0.27134
.applied-mask {
mask-image: repeating-linear-gradient(
to bottom left,
rebeccapurple 0 20px,
rgb(100% 100% 100% / 0.27134) 20px 40px,
black 40px 45px,
white 45px 50px
);
mask-mode: luminance;
}
.mask-source {
background: repeating-linear-gradient(
to bottom left,
rebeccapurple 0 20px,
rgb(100% 100% 100% / 0.27134) 20px 40px,
black 40px 45px,
white 45px 50px
);
}
white 遮罩的區域是完全不透明的。black 遮罩的區域是完全透明的。rebeccapurple 遮罩的區域和不透明度為 27.1234% 的白色遮罩的區域,其不透明度均為 27.1234%。
如果將 mask-mode 切換為 alpha,漸變的顏色將不再重要。除了被半透明白色覆蓋的區域外,整個元素都將是不透明的。
mask-mode 屬性使得可以使用沒有 Alpha 透明度的柵格影像(如 JPEG)作為遮罩影像。JPEG 由不透明畫素組成。如果使用 JPEG 作為遮罩並採用其預設的 alpha 遮罩模式,將會隱藏整個元素。另一方面,mask-mode 的 luminance 值會在遮罩為黑色(沒有亮度)的地方裁剪元素,在遮罩為不透明白色(100% 亮度)的地方完全不透明,其他區域則根據遮罩區域的亮度呈現半透明狀態。
在這個示例中,我們有一個白色月亮懸掛在黑色夜空中的影像。
.applied-mask {
mask-image: url("https://mdn.github.io/shared-assets/images/examples/moon.jpg");
mask-mode: luminance;
mask-size: 220px;
}
.mask-source {
background: url("https://mdn.github.io/shared-assets/images/examples/moon.jpg");
background-size: 220px;
}
在天空是黑色的地方,元素被裁剪且不可見。在月亮最亮的地方,影像最為可見。
在這種情況下,如果將 mask-mode 切換為 alpha,整個元素將變得可見,因為整個遮罩都是不透明的。
SVG <mask> 作為遮罩源
遮罩可以是任何型別的 CSS <image> 或 <mask-source>。<mask-source> 是一個指向 SVG <mask> 元素的 <url> 引用。這與使用 CSS clip-path 屬性進行裁剪類似,在該情況下,“遮罩”是一個 SVG <clipPath> 元素(對於 clip-path,路徑的亮度無關緊要)。
在這個示例中,我們定義了一個包含 <mask> 元素、一個相同的 <clipPath> 元素和一個相同的 <path> 元素的 SVG,以便你可以檢視遮罩和裁剪路徑的源。
<img
src="https://mdn.github.io/shared-assets/images/examples/progress-pride-flag.jpg"
alt="Pride flag"
class="applied-mask" />
<svg class="mask-source">
<mask id="mask-heart">
<path
d="M20,70 A40,40,0,0,1,100,70 A40,40,0,0,1,180,70 Q180,130,100,190 Q20,130,20,70 Z"
fill="rgb(255 0 0 / 0.5)"
stroke="rgb(255 255 255 / 1)"
stroke-width="20" />
</mask>
<clippath id="clip-heart">
<path
d="M20,70 A40,40,0,0,1,100,70 A40,40,0,0,1,180,70 Q180,130,100,190 Q20,130,20,70 Z"
fill="rgb(255 0 0 / 0.5)"
stroke="rgb(255 255 255 / 1)"
stroke-width="20" />
</clippath>
<path
d="M20,70 A40,40,0,0,1,100,70 A40,40,0,0,1,180,70 Q180,130,100,190 Q20,130,20,70 Z"
fill="rgb(255 0 0 / 0.5)"
stroke="rgb(255 255 255 / 1)"
stroke-width="20" />
</svg>
<img
src="https://mdn.github.io/shared-assets/images/examples/progress-pride-flag.jpg"
alt="Pride flag"
class="applied-clip" />
.applied-mask {
mask-image: url("#mask-heart");
}
.applied-clip {
clip-path: url("#clip-heart");
}
因為影像源是 <mask>,且該遮罩既沒有設定 mask-type CSS 屬性,也沒有設定 mask-type SVG 屬性,所以 mask-type 預設為 alpha,因此 mask-mode: match-source 的預設值會解析為 luminance。這是因為,對於作為 SVG <mask> 元素的遮罩源,mask-type 預設為 luminance,除非 mask-type 屬性被明確設定為 alpha。
由於我們沒有在遮罩上設定 mask-type 屬性或 CSS 屬性,mask-mode 屬性的預設值 match-source 會解析為 luminance。切換複選框以將 mask-mode 值設定為 alpha 或讓其預設為 match-source。
這個示例還展示了 CSS 中遮罩和裁剪的區別。你會注意到,亮度和 Alpha 透明度與遮罩相關,但與裁剪無關。遮罩可用於控制元素的不透明度,而裁剪則顯示裁剪路徑內的所有內容,並完全隱藏裁剪路徑外的元素部分。被裁剪的區域是完全不可見的,而被遮罩的區域可以是部分或完全可見的。
如果你只需要形狀,裁剪可能就足夠了。但如果你需要漸變、可變不透明度,甚至控制位置和大小(我們將在另一篇指南中討論),那麼遮罩更合適。