图像遮罩 ( mask )
所谓的“遮罩”泛指一个形状区域,透过形状可以看见元素的内容,而形状外的内容就会被遮住,这篇教学会介绍 CSS 遮罩相关样式属性,例如 mask、mask-image、mask-mode、mask-position、mask-clip、mask-origin、mask-repeat、mask-size、mask-type 等遮罩相关样式属性。
CSS 遮罩的
mask-type属于 SVG 元素的样式属性,在本篇教学中不会介绍,有兴趣可以参考这篇文教学:SVG 研究之路 (9) - Clipping and Masking
快速导览:
认识遮罩
“遮罩”泛指一个形状区域,透过形状可以看见元素的内容,而形状外的内容就会被遮住,就如同透过一个具有形状的不透明纸板看图像,在许多绘图软件中,遮罩是几乎是必备的功能,透过遮罩,可以快速实现。
CSS 的遮罩和 clip-path 裁切路径的效果有点类似,但仍有下列的差异:
| 差异 | 遮罩 | clip-path |
|---|---|---|
| 定义范围 | 图像 | 长度或座标 |
| 透明度 | 可设定透明度、渐层遮罩 | 不支援透明度,单纯剪裁出范围 |
| 动态改变范围 | 无法动态改变范围,需要改变遮罩图片内容 | 改变座标就可动态改变范围 |
mask-image 图像遮罩
mask-image 样式属性可以指定一张图片作为“遮罩图片”,用法和 background-image 相同,没有继承特性,支援 jpg、png、SVG 以及使用 CSS 渐层,在 mask-mode: luminance 模式下,浏览器会将图片转换成“灰阶”图像,根据图像中的“黑白程度 ( 亮度 )”决定遮罩的透明度,“越黑”越透明,“越白”越不透明,如果图片有透明度则根据透明度决定遮罩是否透明。如果是 mask-mode: alpha 模式,则会根据图像中的“透明度”决定遮罩的透明度,由于 jpg 图像没有透明度,使用透明度作为遮罩会完全没有作用。
注意,元素所有一切,包含边框、阴影都会被遮罩所遮住。
下方范例会使用 mask-mode: luminance 模式,让四种不同格式图片产生遮罩效果。
<!-- HTML 程式碼-->
<div></div><div></div>
<div></div><div></div>
<div></div><div></div>
<div></div><div></div>
<!-- CSS 程式碼 -->
<style>
div {
width:500px;
height: 210px;
margin: 20px;
float: left;
mask-mode: luminance; /* 設定遮罩圖片為亮度模式 */
background: url('https://steam.oxxostudio.tw/image/index-css.jpg');
}
div:nth-child(2n+1) {clear: both;}
div:nth-child(1) {background: url('https://steam.oxxostudio.tw/download/css/mask-demo-01.png');}
div:nth-child(2) {mask-image: url('https://steam.oxxostudio.tw/download/css/mask-demo-01.png');}
div:nth-child(3) {background: url('https://steam.oxxostudio.tw/download/css/mask-demo-02.jpg');}
div:nth-child(4) {mask-image: url('https://steam.oxxostudio.tw/download/css/mask-demo-02.jpg');}
div:nth-child(5) {background: url('https://steam.oxxostudio.tw/download/css/mask-demo-03.svg');}
div:nth-child(6) {mask-image: url('https://steam.oxxostudio.tw/download/css/mask-demo-03.svg');}
div:nth-child(7) {
background: repeating-linear-gradient(
to right,
white 0%, white 5%,
black 5%, black 10%
);
}
div:nth-child(8) {
mask-image: repeating-linear-gradient(
to right,
white 0%, white 5%,
black 5%, black 10%
);
};
</style>
透过渐层色的方式,甚至可以让图像呈现“双重背景”的有趣效果,下方范例会使用渐层作为遮罩,让两个 div 的背景互相重叠融合。
延伸阅读:CSS 函数 ( 渐层色 )
<!-- HTML 程式碼-->
<div><div></div></div>
<!-- CSS 程式碼 -->
<style>
div {
width:500px;
height: 220px;
margin: 20px;
background: url('https://steam.oxxostudio.tw/image/index-css.jpg');
}
div div {
margin: 0;
background: url('https://steam.oxxostudio.tw/image/index-html.jpg');
}
div div {
mask-image: repeating-linear-gradient(
to right,
#0000 0%, #0000 10%,
#000f 90% , #000f 100%);
}
</style>
除了单一遮罩,mask-image 也支援“多重遮罩”,只需要用逗号分隔多组遮罩图片,就能实现多重遮罩的效果,进行多重遮罩时,会采用所有遮罩图片中“比较透明”或“比较黑”的色彩作为遮罩本身的颜色或透明度。
<!-- HTML 程式碼-->
<div></div>
<!-- CSS 程式碼 -->
<style>
div {
width:500px;
height: 220px;
margin: 20px;
background: url('https://steam.oxxostudio.tw/image/index-css.jpg');
}
div {
mask-mode: luminance;
mask-image: repeating-linear-gradient(
to right,
#000 0%, #000 5%,
#fff 5%, #fff 6%),
repeating-linear-gradient(
to bottom,
#000 0%, #000 5%,
#fff 5%, #fff 6%),
url('https://steam.oxxostudio.tw/download/css/mask-demo-01.png');
};
</style>
除了使用外部的 SVG,mask-image 也可以读取在 HTML 里 SVG 的 <mask> 标签,下方范例会读取 HTML 里 SVG 中 id 为 myMask 的遮罩形状,并将这个形状作为遮罩图像,注意,读取 HTML 里的 SVG 的 <mask> 标签时只支援 mask-mode: luminance; 模式。
<!-- HTML 程式碼-->
<svg>
<mask x="0" y="0" width="105.4" height="106.8" id="myMask">
<rect x="0" y="0" width="220" height="220" fill="white" />
<path fill="black" d="M97.8,13.2l-13.6,35l21.1,31l-37.5-2.1l-23,29.7l-9.6-36.3L0,57.9l31.5-20.3L32.7,0l29.1,23.7L97.8,13.2z"/>
</mask>
</svg>
<div></div>
<!-- CSS 程式碼 -->
<style>
div {
width:500px;
height: 220px;
margin: 20px;
background: url('https://steam.oxxostudio.tw/image/index-css.jpg');
}
svg {
width: 0;
height: 0;
}
path {transform: scale(2.0);} /* 放大遮罩路徑 */
div {
mask-mode: luminance;
mask-image: url(#myMask); /* 讀取遮罩路徑 */
};
</style>
mask-mode 遮罩模式
mask-mode 可以设定遮罩模式,没有继承特性,有下列属性值:
| 属性值 | 说明 |
|---|---|
| alpha | 根据透明度,图像越透明遮罩越透明。 |
| luminance | 根据亮度 ( 灰阶化后的黑白程度 ),颜色越黑遮罩越透明。 |
| match-source | 默认值,如果是图像就用 alpha,如果是 SVG mask 标签就用 luminance。 |
下方范例会使用默认模式的 mask-mode,如果是图像就会自动使用 alpha,如果是 SVG mask 标签就会使用 luminance。
<!-- HTML 程式碼-->
<svg>
<mask x="0" y="0" width="105.4" height="106.8" id="myMask">
<rect x="0" y="0" width="220" height="220" fill="#ccc" />
<path fill="black" d="M97.8,13.2l-13.6,35l21.1,31l-37.5-2.1l-23,29.7l-9.6-36.3L0,57.9l31.5-20.3L32.7,0l29.1,23.7L97.8,13.2z"/>
</mask>
</svg>
<div></div>
<div></div>
<!-- CSS 程式碼 -->
<style>
div {
width:500px;
height: 220px;
margin: 20px;
background: url('https://steam.oxxostudio.tw/image/index-css.jpg');
}
svg {
width: 0;
height: 0;
}
path {transform: scale(2.0);}
/* 使用 HTML 裡 SVG 的 mask 遮罩 */
div:nth-of-type(1) {mask-image: url(#myMask);}
/* 使用外部圖片 */
div:nth-of-type(2) {
mask-image: url('https://steam.oxxostudio.tw/download/css/mask-demo-01.png');
}
</style>
mask-repeat 遮罩重复方式
mask-repeat 可以定义“遮罩重复的方式”,使用方式和 background-repeat 完全相同,没有继承特性,具有下列几个属性值:
| 属性值 | 说明 |
|---|---|
| repeat | ( 默认值 ) 使用遮罩图片所设定的尺寸连续并重复出现,超过范围的遮罩会被裁切。 |
| no-repeat | 不重复,使用单一张遮罩图片。 |
| space | 使用空白分隔重复的遮罩图片,保持原本长宽尺寸重复且不被裁切。 |
| round | 修改重复的遮罩图片的长宽比例,让重复的遮罩图片不被裁切。 |
| repeat-x | 等同 repeat 但只在水平方向重复。 |
| repeat-y | 等同 repeat 但只在垂直方向重复。 |
下列范例会让不同的 div 呈现不同的 mask-repeat 遮罩效果。
<!-- HTML 程式碼-->
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
<div class="d"></div>
<div class="e"></div>
<div class="f"></div>
<!-- CSS 程式碼 -->
<style>
div {
width:300px;
height: 150px;
margin: 20px;
background: url('https://steam.oxxostudio.tw/image/index-css.jpg');
mask-image: url('https://steam.oxxostudio.tw/download/css/mask-demo-01.png');
mask-size: 130px 60px;
}
.a {mask-repeat: repeat;} /* 按照遮罩圖片設定尺寸重複 */
.b {mask-repeat: no-repeat;} /* 不重複 */
.c {mask-repeat: space;} /* 使用空白分隔重複的遮罩圖片,保持原本長寬尺寸重複且不被裁切 */
.d {mask-repeat: round;} /* 修改重複的遮罩圖片的長寬比例,讓重複的遮罩圖片不被裁切 */
.e {mask-repeat: repeat-x;} /* 水平重複 */
.f {mask-repeat: repeat-y;} /* 垂直重複 */
</style>
mask-position 遮罩位置
mask-position 可以定义“遮罩位置”,使用方式和 background-position 几乎完全相同,没有继承特性,使用“对齐关键字”或“位置偏移量”来定义遮罩图片的位置,可以将关键字与偏移量互相搭配,产生“1~4”个属性值,下列方列出相关撰写语法:
对齐关键字
单纯使用位置名称进行对齐,这个写法会有“1~2”个属性值,使用后表示会将遮罩图片的边缘或中心点贴齐指定位置,注意,不能同时使用“top 与 bottom”或“left 与 right”。
关键字 等同属性值 说明 top center top靠上对齐 right right center靠右对齐 bottom center bottom靠下对齐 left left center靠左对齐 center center center置中对齐 left top - 靠左上对齐 ( 默认值 ) left bottom - 靠左下对齐 right top - 靠右上对齐 right bottom - 靠右下对齐 位置偏移量 ( 百分比 )
使用百分比单位,在没有设定对齐关键字的状态下,采用“
left top”的方式进行偏移,并按照“百分比公式”计算偏移量,由于最终偏移结果是按照公式计算出的数值,如果遮罩图片尺寸大于元素尺寸,计算后会往反向移动 ( 类似设定负值的 px ),如果遮罩图片尺寸小于元素尺寸,计算后会顺向移动,这个写法会有“1~2”个属性值。( 容器寬度 - 遮罩圖片寬度 ) * x 偏移百分比 = x 方向偏移量 ( 容器高度 - 遮罩圖片高度 ) * y 偏移百分比 = y 方向偏移量属性值 等同属性值 ( top left ) 说明 50%50% 50%左往右偏移 50%,上往下偏移 50% 50% 100%- 左往右偏移 50%,上往下偏移 100% 位置偏移量 ( px、em、rem )
使用非百分比的长度单位,在没有设定对齐关键字的状态下,采用“
left top”的方式进行偏移,px 表示像素,em 表示元素本身字号,rem 表示根元素字号,设定负值会往反方向移动,这个写法会有“1~2”个属性值。属性值 等同属性值 ( top left ) 说明 50px50px 50px左往右偏移 50px,上往下偏移 50px 50px 100px- 左往右偏移 50px,上往下偏移 100px 混合对齐关键字与位置偏移量
将“对齐关键字”和“位置偏移量”组合,就能指定“哪个方向的偏移量”,这个写法会有“4”个属性值,注意,不支援使用 center 位置关键字。
属性值 等同属性值 说明 right 20% bottom 20%-20% -20% 右往左偏移 20%,下往上偏移 20% left 20% top 20%20% 20% 右往左偏移 20%,上往下偏移 20%
下列范例会让不同的 div 呈现不同的 mask-position 遮罩效果。
<!-- HTML 程式碼-->
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
<div class="d"></div>
<div class="e"></div>
<div class="f"></div>
<!-- CSS 程式碼 -->
<style>
div {
width:300px;
height: 150px;
margin: 20px;
background: url('https://steam.oxxostudio.tw/image/index-css.jpg');
mask-image: url('https://steam.oxxostudio.tw/download/css/mask-demo-03.svg');
mask-repeat: no-repeat;
mask-size: 200px;
}
.a {mask-position: center center;} /* 水平置中,垂直置中 */
.b {mask-position: 0% 0%;} /* 靠左靠上對齊,偏移 0% */
.c {mask-position: right bottom;} /* 靠右靠下對齊 */
.d {mask-position: 20px 50px;} /* 靠左靠上對齊,往右移動 20px,往下移動 50px */
.e {mask-position: right 20px bottom 50px;} /* 靠右靠下對齊,往左移動 20px,往上移動 50px */
.f {mask-position: left 20px top 50px;} /* 靠左靠上對齊,往右移動 20px,往下移動 50px */
</style>
mask-size 遮罩尺寸
mask-size 可以设定“遮罩尺寸”,使用方式和 background-size 完全相同,使用“尺寸关键字”或“尺寸数值”的属性值来定义遮罩图片的尺寸,没有继承特性,由于 mask-size 主要针对“具有长宽尺寸或比例”的图片计算出遮罩图片的长宽,因此如果使用的图片没有长宽尺寸或比例 ( 例如渐层色、部分特殊设定的 SVG ),就不会套用遮罩图片尺寸样式。
注意,
mask-size一定要放在mask-image和mask-position后方才会正常显示。
下方列出属性值的说明:
| 属性值 | 类型 | 说明 |
|---|---|---|
| cover | 关键字 | 维持图片比例,将宽度或高度缩放至元素“最大边长”( 无法和数值搭配 )。 |
| contain | 关键字 | 维持图片比例,将宽度或高度缩放至元素“最小边长””( 无法和数值搭配 )。 |
| auto | 关键字 | 维持图片比例,根据宽调整高,或根据高调整宽,没有设定宽高就使用图片原始尺寸。 |
| N% | 数值 | 宽 = 元素宽 x N%,高 = 元素高 x N%。 |
| X% Y% | 数值 | 宽 = 元素宽 x X%,高 = 元素高 x Y%。 |
| Npx | 数值 | 宽 = Npx,高 = Npx。 |
| Xpx Ypx | 像数值 | 宽 = Xpx,高 = Ypx。 |
| em | 数值 | 使用元素字号,算法等同 px 或 % |
| rem | 数值 | 使用根元素字号,算法等同 px 或 % |
使用 mask-size 时,只有 auto 关键字可以和数值共同使用,产生 1~2 个属性值,如果 auto 写在数值左方表示宽度等比例调整,auto 写在数值右方表示高度等比例调整,下方范例会用不同的属性值,呈现不同的 mask-size 属性值的效果。
<!-- HTML 程式碼-->
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
<div class="d"></div>
<div class="e"></div>
<div class="f"></div>
<!-- CSS 程式碼 -->
<style>
div {
width:300px;
height: 150px;
margin: 20px;
background: url('https://steam.oxxostudio.tw/image/index-css.jpg');
mask-image: url('https://steam.oxxostudio.tw/download/css/mask-demo-01.png');
}
.a {mask-size: cover;} /* 填滿最大邊長 */
.b {mask-size: contain;} /* 填滿最小邊長 */
.c {mask-size: auto 40%;} /* 寬度等比例,高度 = 元素高 x 40% */
.d {mask-size: 40%;} /* 寬度 = 元素寬 x 40%,高度 = 元素高 x 40% */
.e {mask-size: 80% 20px;} /* 寬度 = 元素寬 x 80%,高度 = 20px */
.f {mask-size: 30px 200px;} /* 寬度 = 30px,高度 = 200px */
</style>
mask-origin 遮罩参照
mask-origin 表示遮罩“参照容器盒子模型”而产生的“范围”,参考“容器盒子模型 (Box Model )”教学内容,mask-origin 具有下列属性值:
| 属性值 | 说明 |
|---|---|
| border-box | 遮罩范围包含边框宽度。 |
| padding-box | 遮罩范围包含内边距宽度。 |
| content-box | 遮罩范围只有内容尺寸。 |
下方范例会呈现不同的 mask-origin 遮罩范围所呈现的效果,遮罩缩放效果会因为范围不同而有所不同,可以注意范例中垂直遮罩线条的粗细不同。
<!-- HTML 程式碼-->
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
<!-- CSS 程式碼 -->
<style>
div {
margin: 30px;
padding: 20px;
border: 20px solid red;
width: 200px;
height: 100px;
background: url('https://steam.oxxostudio.tw/image/index-css.jpg');
mask-image: repeating-linear-gradient(
to right,
#0006 0%, #0006 5%,
#000f 5%, #000f 10%
);
mask-size: contain;
mask-position: center;
mask-repeat: no-repeat;
}
.a {mask-origin: content-box;}
.b {mask-origin: padding-box;}
.c {mask-origin: border-box;}
</style>
mask-clip 遮罩裁切
mask-clip 表示“参考容器盒子模型”而“裁切”后的遮罩,有点类似 mask-origin,参考“容器盒子模型 (Box Model )”教学内容,mask-clip 具有下列属性值:
| 属性值 | 说明 |
|---|---|
| border-box | 遮罩裁切范围包含边框宽度。 |
| padding-box | 遮罩裁切范围包含内边距宽度。 |
| content-box | 遮罩裁切范围只有内容尺寸。 |
下方范例会呈现不同的 mask-clip 遮罩范围所呈现的效果。
<!-- HTML 程式碼-->
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
<!-- CSS 程式碼 -->
<style>
div {
margin: 30px;
padding: 20px;
border: 20px solid red;
width: 200px;
height: 100px;
background: url('https://steam.oxxostudio.tw/image/index-css.jpg');
mask-image: url('https://steam.oxxostudio.tw/download/css/mask-demo-03.svg');
mask-size: contain;
mask-position: center;
mask-repeat: no-repeat;
}
.a {mask-clip: content-box;}
.b {mask-clip: padding-box;}
.c {mask-clip: border-box;}
</style>
mask-composite 遮罩集合运算
mask-composite 表示多重遮罩之间的“集合”,根据不同的集合方式,会产生不同的效果,下方列出支援的集合方式:
| 集合方式 | 说明 |
|---|---|
| add | 联集,所有遮罩图形都是遮罩范围。 |
| subtract | 差集,前方遮罩会移除和后方遮罩的重叠范围。 |
| intersect | 交集,保留遮罩重叠的部分。 |
| exclude | 对称差集,移除重叠的部分。 |
下方会使用垂直和水平两种渐层条纹,搭配九宫格的背景,清楚呈现这些集合方式的差异。
<!-- HTML 程式碼-->
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
<div class="d"></div>
<!-- CSS 程式碼 -->
<style>
div {
margin: 30px;
width: 200px;
height: 200px;
background: url('https://steam.oxxostudio.tw/download/css/border-img-2.jpg');
background-size: cover;
mask-image: repeating-linear-gradient(
to right,
#000f 0%, #000f 33.33%,
#0000 33.33%, #0000 66.66%
),repeating-linear-gradient(
to bottom,
#000f 0%, #000f 33.33%,
#0000 33.33%, #0000 66.66%
);
mask-size: cover;
}
.a {mask-composite: add;}
.b {mask-composite: subtract;}
.c {mask-composite: intersect;}
.d {mask-composite: exclude;}
</style>
mask 遮罩 ( 缩写格式 )
元素套用遮罩时,为了避免 CSS 程序码过于冗长,有时会使用缩写的 mask 样式属性,这个样式没有继承特性,需要注意下列的几个事项:
mask-size一定要接在mask-position之后且使用“/”分隔,若只有长度数值则表示mask-position属性值。- 出现
mask-origin和mask-clip相关属性值时,如果只有一个就是mask-origin,出现的第二个是mask-clip。- 使用
mask可能会覆盖掉对应的遮罩样式,反之其他遮罩样式也可能会覆盖mask里对应的样式。- 如果有多重遮罩,使用“逗号”分隔多个遮罩样式。
下方列出一些符合规范的 mask 写法:
div {
mask: url(...);
/* 等同 */
/* mask-image: url(...) */
mask: url(...) luminance;
/* 等同 */
/* mask-image: url(...); */
/* mask-mode: luminance; */
mask: url(...) luminance 20% 30%;
/* 等同 */
/* mask-image: url(...); */
/* mask-mode: luminance; */
/* mask-position: 20% 30%; */
mask: url(...) luminance 20% 30% / 50%;
/* 等同 */
/* mask-image: url(...); */
/* mask-mode: luminance; */
/* mask-position: 20% 30%; */
/* mask-size: 50%; */
background: url(...) luminance 20% 30% / 50% padding-box;
/* 等同 */
/* mask-image: url(...); */
/* mask-mode: luminance; */
/* mask-position: 20% 30%; */
/* mask-size: 50%; */
/* mask-origin: padding-box */
background: url(...) luminance 20% 30% / 50% padding-box padding-box;
/* 等同 */
/* mask-image: url(...); */
/* mask-mode: luminance; */
/* mask-position: 20% 30%; */
/* mask-size: 50%; */
/* mask-origin: padding-box */
/* mask-clip: padding-box */
}
下方范例会使用 mask 缩写样式表现图像遮罩。
<!-- HTML 程式碼-->
<div></div>
<div></div>
<!-- CSS 程式碼 -->
<style>
div {
position: absolute;
top: 10px;
left: 10px;
width: 600px;
height: 320px;
}
div:nth-child(1) {
background: url('https://steam.oxxostudio.tw/image/index-css.jpg') center / cover;
opacity: 0.6;
}
div:nth-child(2) {
width: 600px;
height: 320px;
background: url('https://steam.oxxostudio.tw/image/index-css.jpg') center / cover;
mask: url('https://steam.oxxostudio.tw/download/css/mask-demo-01.png') center / 15% space;
}
</style>
小结
透过 mask 可以轻松实现网页的简单特效,虽然过去的浏览器对于这个样式的支援度不高,但随着科技的进步,目前大部分浏览器都已经支援,也可以开始使用这个样式属性,做出各种有趣的遮罩效果!
微信扫码关注
抖音扫码关注