声明多个蒙版

CSS 遮罩是一种技术,允许你使用图像作为遮罩来定义元素的哪些部分是完全可见或半透明的。CSS 遮罩根据应用遮罩图像的 alpha 通道,在某些情况下还会根据颜色的亮度,选择性地显示或隐藏元素的部分。

CSS 遮罩与假面舞会(戴面具的舞会)上戴的遮罩相反。在假面舞会上,佩戴者的脸在遮罩不透明的地方被隐藏,在透过遮罩可见的地方被显示。在 CSS 中,组合遮罩层完全不透明的区域会显示元素,而透明区域则隐藏元素。

CSS 遮罩由一个或多个遮罩层组成。在本指南中,我们将讨论遮罩层的概念以及如何使用 mask 简写属性声明多个遮罩层。

理解遮罩层

你可以将 CSS 遮罩应用于所有 HTML 元素和大多数 SVG 元素。一个遮罩可以由一个或多个复合遮罩层组成。你可以在 mask 简写属性或 mask-image 属性中使用逗号分隔的值定义多个层——甚至设置为 none 的值也算作一个层。

每个遮罩层可以包含一个 遮罩图像,它相对于遮罩的起始框定位。图像可以调整大小、重复和裁剪。如果包含多个遮罩图像,则可以定义遮罩层的组合或合并方式。(本指南简要介绍了这些功能。有关更多详细信息和示例,请参阅遮罩属性指南。)

多遮罩层的语法

mask 简写属性接受逗号分隔的遮罩层列表。每个层的语法可以包括以下值:

<image> <position> / <size> <repeat> <origin> <clip> <composite> <mode>

遮罩层中的所有组件都是可选的。但是,如果你省略 mask-image 值,它将默认为透明黑色图像,这会完全隐藏该层中的元素。

mask 简写声明设置所有 mask-* 属性的值。层内未声明的任何组件都将默认为其初始值。mask 属性还会将所有 mask-border-* 属性重置为其初始值。仅包含 mask-image 值的 mask 声明隐式设置以下内容:

css
mask-mode: match-source;
mask-position: 0% 0%;
mask-size: auto;
mask-repeat: repeat;
mask-origin: border-box;
mask-clip: border-box;
mask-composite: add;

mask-border-source: none;
mask-border-mode: alpha;
mask-border-outset: 0;
mask-border-repeat: stretch;
mask-border-slice: 0;
mask-border-width: auto;

使用 mask-image 定义遮罩层

只要逗号分隔的 mask-image 属性声明中包含至少一个非 none 的值,就会为声明中的每个值创建一个遮罩层,即使是 none 值也是如此。无论你使用 mask-image 属性还是 mask 简写,此行为都适用。这些遮罩图像可以是渐变、图像或 SVG 源。你可以使用 CSS 渐变、位图图像(如 PNG)或 SVG <mask> 元素来定义它们。

css
.gradient-mask {
  mask-image: linear-gradient(to right, black, transparent);
}

.raster-mask {
  mask-image: url("alphaImage.png");
}

.mask-element-mask {
  mask-image: url("#svg-mask");
}

遮罩入门指南介绍了不同类型的遮罩图像及其模式。

mask-image 属性类似于 background-image 属性。与 background-image 属性一样,要包含多个遮罩图像,图像值用逗号分隔。

css
.multiple-gradient-mask {
  mask-image:
    linear-gradient(to right, black, transparent),
    radial-gradient(circle, white 50%, transparent 75%);
}

多图像声明中的每个遮罩图像都会创建一个遮罩层。本节中的所有示例都创建一个遮罩层,除了 multiple-gradient-mask 声明,它创建两个。

遮罩层和 none 关键字

如果 nonemask-image 属性的唯一值,则不会创建遮罩层,也不会发生遮罩。

css
.no-masks {
  mask-image: none;
}

类似地,在使用 mask 简写时,如果除了 none 之外没有 mask-image 值,则不会发生遮罩。如果声明了以下任何一项,则不会创建遮罩层,也不会隐藏任何内容:

css
mask: none;
mask: none 100px 100px no-repeat;
mask: 100px 100px no-repeat;

否则,只要声明了非 nonemask-image,就会为逗号分隔值列表中的每个值创建一个遮罩层,即使 mask-image 值在逗号分隔值列表中被省略或明确设置为 none 也是如此。换句话说,除非整个属性解析为 none,否则会为每个有效的逗号分隔值创建一个层。

css
.masked-element {
  mask-image:
    url("alphaImage.png"), linear-gradient(to right, black, transparent),
    radial-gradient(circle, white 50%, transparent 75%), none, url("#svg-mask");
}

遮罩源列表中的关键字 none 会创建一个遮罩层,尽管是一个透明的黑色图像层。任何带有 masked-element 类的元素都将有五个遮罩层:

我们也可以使用 mask 简写创建这些层:

css
.masked-element {
  mask:
    url("alphaImage.png"), linear-gradient(to right, black, transparent),
    radial-gradient(circle, white 50%, transparent 75%), none, url("#svg-mask");
}

如果逗号分隔值列表中的值是空图像,下载失败,引用不存在的 <mask> 元素,或者以其他方式无法显示(或设置为 none),它仍然算作一个遮罩图像层,渲染一个没有视觉效果的透明黑色遮罩图像。如果所有值都这样做,元素将完全隐藏。

如果整个属性解析为 none,则不会发生遮罩,这使得元素完全可见。另一方面,如果该值包含多个层并且至少一个不是 none,则 none 层不会显示元素的任何部分(或不会使元素的任何部分可见)。在此示例中,该值不会解析为 none;但由于所有非 none 图像都无效,因此会发生遮罩,并且元素将完全隐藏。

none 的计算值会创建一个 CSS 堆叠上下文

遮罩层如何影响 mask-* 属性

当你还在 mask 声明之后或使用比 mask 声明更具体的个别 mask-* 属性时,遮罩层的数量很重要。

mask-* 属性包括:

  • mask-mode:将每个遮罩层的模式设置为 alphaluminance,或通过将值设置为 match-source 允许它默认为源的模式。默认值为 match-source

  • mask-position:类似于 background-position 属性,其语法遵循 background-position<position> 语法,它设置遮罩图像相对于遮罩层起始框(由 mask-origin 属性定义)的初始位置。你可以指定一个、两个或四个 <position> 值。默认的 0% 0% 将遮罩的左上角定位在遮罩起始框的左上角。

  • mask-origin:类似于 background-origin 属性,它指定遮罩定位区域,即遮罩图像定位在其内的遮罩起始框区域。例如,如果 mask-positiontop left,此属性定义它是否相对于边框的外边缘、内边距的外边缘或内容的外边缘。

  • mask-clip:类似于 background-clip 属性,它确定受遮罩影响的元素区域。它定义遮罩绘制区域是边框、内边距还是内容框,将元素的绘制内容限制在此区域。如果遮罩层的 mask-image 源是 SVG <mask> 元素,则 mask-clip 属性无效。

  • mask-size:类似于 background-size 属性,用于调整遮罩层的大小。值可以是单个关键字(covercontainauto),单个长度或百分比,或两个空格分隔的值——每个值都可以是长度、百分比或 auto。默认值为 auto

  • mask-repeat:类似于 background-repeat 属性,它定义了遮罩层图像在调整大小和定位后如何平铺。

  • mask-composite:定义遮罩如何与下面的遮罩层组合。每个遮罩层要么添加到、减去、包含或排除于其下面的先前组合的遮罩层。与 mask-mode 类似,没有类似的 background-* 属性。

逗号分隔的 mask 组件属性列表中的每个 mask-* 值都应用于一个单独的遮罩层。如前所述,一个元素可以应用多个遮罩层——层的数量由 mask-imagemask 属性中逗号分隔值的数量决定。每个 mask-* 值都按顺序与一个遮罩层匹配。如果 mask-* 属性中的值数量大于遮罩层的数量,则任何多余的值都将被忽略。如果遮罩组件属性的值少于遮罩层的数量,则 mask-* 值会重复。

要了解有关这些单个属性的更多信息,请参阅 CSS 遮罩属性

简写组件属性的顺序

在大多数情况下,属性的顺序是灵活的,但有一些怪癖和例外。

mask-originmask-clip 的排序规则

在语法中列为 <origin>mask-origin 值位于在语法中列为 <clip>mask-clip 值之前。

<image> <position> / <size> <repeat> <origin> <clip> <composite> <mode>

两者都接受 <geometry-box> 关键字。此外,mask-clip 还接受 no-clip。因此,当你希望将 mask-clip 设置为 no-clip 之外的任何值时,这两者的顺序很重要。

  • 如果存在一个 <geometry-box> 值以及 no-clip 关键字,则 <geometry-box> 设置 mask-origin 值,并且 mask-clip 设置为 no-clip。在这种情况下,顺序无关紧要。

  • 如果只存在一个 <geometry-box> 值并且没有 no-clip 关键字,则 mask-originmask-clip 组件都设置为该值。由于只有一个值,因此顺序再次无关紧要。

  • 如果存在两个 <geometry-box> 值,则第一个设置 mask-origin 组件,第二个设置 mask-clip 组件。在这种情况下,顺序非常重要。

mask-originmask-clip 值设置顺序不正确可能会影响外观,但不会导致声明失败。

mask-sizemask-position 的排序规则

你可能已经注意到 mask-positionmask-size 之间有一个斜杠,在语法中列为 <position><size>。这两个属性接受相似的值。

<image> <position> / <size> <repeat> <origin> <clip> <composite> <mode>

在这种情况下,顺序非常重要。如果只存在一个或一对 <length-percentage> 值,它将定义图像的位置而不是大小。在遮罩层中同时包含位置和大小而不包含两者之间的斜杠将使整个声明无效。

css
mask:
  url("star.svg") bottom 2em right 4em / auto 2vw no-repeat padding-box
    content-box luminance,
  url("circle.svg") 100px 100px / 50% repeat-x border-box padding-box alpha;

如果存在单个 <length-percentage> 值对,它将设置 mask-position 属性,并且 mask-size 将为 auto。如果一个层同时包含 mask-sizemask-position,则 mask-size 属性值必须在 mask-position 属性值之后,并且值之间必须用正斜杠 (/) 分隔。即使 mask-size 设置为不是有效 mask-position 值的值,也需要斜杠。

css
mask: url("star.svg") contain;
mask: url("star.svg") 10px 10px cover;
mask: url("star.svg") top right 100px 100px;
css
mask: url("star.svg") 10px 10px / cover;
mask: url("star.svg") top 100px right 100px;
mask: url("star.svg") top right / 100px 100px;

要在使用 mask 简写声明的遮罩层中包含 mask-size,你必须在它之前紧接着包含一个带有斜杠的 mask-position 值。

警告:如果你在遮罩层中包含大小但忘记了位置后面的斜杠,则整个声明将变为无效。

另见