什么是 mask

mask 属性允许使用者通过遮罩或者裁切特定区域的图片的方式来隐藏一个元素的部分或者全部可见区域。如果你用过PhotoShop的蒙版,那一定非常好理解。

mask 属性主要基于遮罩图像进行操作,通过将遮罩图像应用于元素的内容部分来达到蒙版效果。遮罩图像可以是一张图片、一个渐变或者一个 SVG 矢量图形,即可应用于 CSS background 的属性值。

当遮罩图像应用到元素上时,mask 属性会根据图像的==透明度==为元素的每个像素设置一个 alpha 值(透明度),从而决定像素的可见程度。透明度值为 1 的像素完全可见,透明度值为 0 的像素完全隐藏。

如何使用 mask

使用mask时可以用多种方式进行设置,例如加载一张图片、设置一个背景(指背景的css语法)等。上面已经说过了,mask 是利用图像的透明度信息作为元素的透明度值的。

下面看一下mask常用的属性:

mask-composite

如果你了解ps的选区,这里就很容易理解了,分别有四个属性对应了四种方式

image-20230808224325111

  • add:累加,所有的设置都生效;;
  • subtract:相减,即相交的地方不生效;
  • intersect:重合,遮罩相交的地方生效;
  • exclude:从元素主内容中排除与遮罩内容重叠的部分。

mask-image

用于指定用作遮罩的图片。默认值是none,也就是无遮罩图片。所谓遮罩,就是原始图片只显示遮罩图片非透明的部分。

mask-mode(仅火狐支持)

mask-mode属性的默认值是match-source,意思是根据资源的类型自动采用合适的遮罩模式。

  • alpha:透明度遮罩。
  • luminance:亮度遮罩。
  • match-source:根据类型资源自动采用合适的模式,

mask-position

用于定义遮罩的位置。

支持单个关键字,如top,bottom,left,right,center(缺省关键字的解析为center);

支持各类数值(百分数或数值),例如:mask-position: 30% 50%;

mask-position也支持多属性值,例如:mask-position: 0 0, center;

mask-size

用于指定遮罩图像的大小。

mask-size作用是控制遮罩图片尺寸,默认值是auto。

支持contain和cover这两个关键字

支持各类数值(缺省高度会自动计算为auto),例如:mask-size: auto 6px;

支持多属性值,例如:mask-size: 50%, 25%, 25%;

mask-repeat

设置遮罩图像的重复方式。

  • repeat-x:水平铺开;
  • repeat-y:垂直铺开;
  • repeat:水平和垂直铺开;
  • no-repeat:不平铺;
  • space:尽可能平铺并且不发生裁剪;
  • round:图片尽可能靠在一起没有间隙,同步不发生裁剪。

mask-origin

定义遮罩图像的起点位置。

  • content-box:相对于内容区域;
  • padding-box:相对于padding区域;
  • border-box:相对于border区域;
  • margin-box:相对于margin区域;
  • fill-box:相对于对象边界框中;
  • stroke-box:相对于stroke边界框中;
  • view-box:使用最近的SVG视图作为参考框。如果SVG元素指定了viewBox属性,则参考框位于viewBox坐标系原点。

mask-clip

确定遮罩的剪辑区域。

  • content-box:将绘制的内容剪切到内容区域;
  • padding-box:将绘制的内容剪切到padding区域;
  • border-box:将绘制的内容剪切到border区域;
  • margin-box:将绘制的内容剪切到margin区域;
  • fill-box:将绘制的内容剪切到对象边界框中;
  • stroke-box:将绘制的内容剪切到stroke边界框中;
  • view-box:使用最近的SVG视图作为参考框。如果viewBox属性指定用于创建SVG视口的元素,引用框位于由viewBox属性和引用框的维度设置为viewBox属性。
  • no-clip:没有剪切。

mask-border-source

用于定义将作为元素边框的图像。它允许您在元素的边框上使用图像作为遮罩。

以下是使用mask-border-source属性的示例:

.element {
  mask-border-source: url(mask.png);
}

在上述示例中,通过指定url(mask.png)来设置mask-border-source属性,将名为 mask.png 的图像应用为元素的边框遮罩。

请注意,mask-border-source属性仅在特定的情况下适用,即在使用border-image属性定义了一种可缩放边框时才能使用。这样,图像遮罩将被应用于边框的可视部分。

mask-border-slice

用于控制图像作为遮罩时如何被切割,以创建可变大小的图像边框。

该属性接受一组值,用空格分隔,可以指定 1 到 4 个值。每个值表示在元素的顶部、右侧、底部和左侧切割图像的边距。

以下是使用mask-border-slice属性的示例:

.element {
  mask-border-slice: 10% 20% 30% 40%; 
}

在上述示例中,mask-border-slice属性设置了四个值,分别表示从元素的顶部、右侧、底部和左侧切割图像的边距。这些值可以是百分比、长度值或fill关键字。

请注意,mask-border-slice属性仅在特定的情况下适用,即在使用border-image属性定义了一种可缩放边框并且使用mask-border-source属性指定了图像遮罩时才能使用。

mask-border-width

用于定义图像遮罩的边框宽度。

该属性接受一组值,用空格分隔,可以指定 1 到 4 个值。每个值表示在元素的顶部、右侧、底部和左侧的边框宽度。

以下是使用mask-border-width属性的示例:

.element {
  mask-border-width: 2px 4px 6px 8px; 
}

在上述示例中,mask-border-width属性设置了四个值,分别表示在元素的顶部、右侧、底部和左侧的边框宽度。这些值可以是长度值或百分比。

请注意,mask-border-width属性仅在特定的情况下适用,即在使用border-image属性定义了一种可缩放边框并且使用mask-border-source属性指定了图像遮罩时才能使用。

mask-border-outset

用于指定图像遮罩的外部扩展值,以创建一个更大的可见边框区域。

该属性接受一组值,用空格分隔,可以指定 1 到 4 个值。每个值表示在元素的顶部、右侧、底部和左侧的外部扩展量。

以下是使用mask-border-outset属性的示例:

.element {
  mask-border-outset: 10px 20px 30px 40px;
}

在上述示例中,mask-border-outset属性设置了四个值,分别表示在元素的顶部、右侧、底部和左侧的外部扩展量。这些值可以是长度值或百分比。

请注意,mask-border-outset属性仅在特定的情况下适用,即在使用border-image属性定义了一种可缩放边框并且使用mask-border-source属性指定了图像遮罩时才能使用。

mask-border-repeat

用于指定图像遮罩边框的重复方式。

该属性接受一个值,可以是一个关键字或一个由空格分隔的两个关键字。

以下是常见的mask-border-repeat属性值:

  • stretch:默认值,图像将被拉伸以适应边框区域(可能导致图像变形)。
  • repeat:图像将在边框区域内重复平铺。
  • round:图像将在边框区域内等比例重复平铺,尽可能多地填充。
  • space:图像将在边框区域内等比例重复平铺,如果有剩余空间则使用空白填充。

以下是使用mask-border-repeat属性的示例:

.element {
  mask-border-repeat: stretch; /* 图像将被拉伸以适应边框 */
}

.element {
  mask-border-repeat: repeat space; /* 图像在边框区域内重复平铺,使用空白填充 */
}

请注意,mask-border-repeat属性仅在特定的情况下适用,即在使用border-image属性定义了一种可缩放边框并且使用mask-border-source属性指定了图像遮罩时才能使用。

实际应用

使用mask绘制不规则图形

例如优惠券,一般设计师给的优惠券样式都是那种不规则图案,例如

image-20230807225202172

如果单纯是这种不规则图形还好,如果带有边框的话就没法使用border属性来设置了,上面的效果我用了前景和背景在制造了一种外边框的错觉,看完后面的代码就懂了。

.border {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 301px;
  height: 76px;
  background: #f8fafe;
  border-radius: 8px;
  cursor: pointer;
  mask: radial-gradient(circle at 159px 0, transparent 8px, black 0),
    radial-gradient(circle at 159px 100%, transparent 8px, black 0);
  mask-composite: source-in;

  .content {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 297px;
    height: 72px;
    background: #f8fafe;
    border-radius: 6px;
    mask: radial-gradient(circle at 159px 0, transparent 8px, black 0),
      radial-gradient(circle at 159px 100%, transparent 8px, black 0);
    mask-composite: source-in;

    .left {
      box-sizing: border-box;
      width: 158px;
      padding: 25px 0 25px 16px;
      font-size: 16px;
      font-family: PingFangSC-Semibold;
      line-height: 22px;
    }

    .right {
      box-sizing: border-box;
      width: 142px;
      padding: 16px;
      color: #5c6b8a;
      font-weight: 400;
      font-size: 12px;
      line-height: 18px;
    }
  }

  // 中间的虚线
  &::before {
    position: absolute;
    left: 158px;
    z-index: 99;
    width: 1px;
    height: 37px;
    border-left: 1px dashed #cdd5e4;
    content: '';
  }
}

// 选中后改变背景色及mask
.borderActive {
  background: #006aff;

  .content {
    mask: radial-gradient(circle at 157px -2px, transparent 10px, black 0),
      radial-gradient(circle at 157px calc(100% + 2px), transparent 10px, black 0);
  }
}

视频弹幕防挡

相关领域最知名的便是B站(Bilibili)了,例如下面的视频中

image-20230807225921017

可以看淡弹幕并没有盖住雷总的头,这里的弹幕就是通过mask来处理的,可以使用浏览器的开发者工具抓包看一下,这种防挡弹幕会一直加载和当前播放时刻对应的蒙版。

image-20230807230114501

这种防挡弹幕有直播实时计算和点播提前计算两种形式,这里不是本文的重点,不做展开。


前端小白