SVG 遮罩特性使得对 SVG 形状使用蒙版成为可能。遮罩确定 SVG 形状的哪些部分是可见的,以及具有什么透明度。你可以将 SVG 遮罩视作剪裁路径的更高级版本。
遮罩示例
下面是一个简单的遮罩示例:
<defs>
<mask id="mask1" x="0" y="0" width="100" height="100" >
<rect x="0" y="0" width="100" height="50"
style="stroke:none; fill: #ffffff"/>
</mask>
</defs>
<rect x="1" y="1" width="100" height="100"
style="stroke: none; fill: #0000ff; mask: url(#mask1)"/>
这个例子定义了 ID 为mask1
的遮罩,<mask>
元素内是一个<rect>
元素,正是这个<rect>
元素定义了遮罩的形状。
例子中还定义了一个使用遮罩的<rect>
元素。其通过 CSS 属性mask
引用遮罩。
最终图片如下:
<rect x="1" y="1" width="100" height="100" style="stroke: none; fill: #0000ff; mask: url(#mask1)"></rect>
<rect x="1" y="1" width="100" height="100" style="stroke: #000000; fill: none;"></rect>
注意要显示的矩形是 100 像素高,但垂直方向上只有前 50 像素可见。这是因为遮罩矩形只有 50 像素高。矩形仅在有遮罩矩形覆盖的部分中可见。
黑色轮廓矩形是没有遮罩的矩形的大小。
其它形状作为遮罩
你可以使用任何 SVG 形状作为遮罩。下面是使用圆形作为遮罩的例子:
<svg>
<defs>
<mask id="mask2" x="0" y="0" width="100" height="100" >
<circle cx="25" cy="25" r="25" style="stroke:none; fill: #ffffff"/>
</mask>
</defs>
<rect x="1" y="1" width="100" height="100"
style="stroke: none; fill: #0000ff; mask: url(#mask2)"/>
</svg>
最终图片如下:
<rect x="1" y="1" width="100" height="100" style="stroke: none; fill: #0000ff; mask: url(#mask2)"></rect>
<rect x="1" y="1" width="100" height="100" style="stroke: #000000; fill: none;"></rect>
再次注意,引用遮罩的矩形只在遮罩圆形区域可见。
遮罩形状颜色定义其不透明度
到目前为止,遮罩形状(圆形或矩形)的填充颜色都设置为#ffffff
。遮罩形状的颜色定义了使用遮罩形状的不透明度。遮罩形状的颜色越接近#ffffff
(白色),使用遮罩的形状越不透明。遮罩形状的颜色越接近#000000
(黑色),使用遮罩的形状越透明。
下面的例子中,遮罩又两个不同颜色的矩形组成(#ffffff
和#666666
)。遮罩在单个矩形上使用,因此你可以看到形状在两个不同颜色遮罩形状下的效果。
<defs>
<mask id="mask3" x="0" y="0" width="100" height="100" >
<rect x="0" y="0" width="100" height="50"
style="stroke:none; fill: #ffffff"/>
<rect x="0" y="50" width="100" height="50"
style="stroke:none; fill: #666666"/>
</mask>
</defs>
<text x="10" y="55" style="stroke: none; fill: #000000;">
This text is under the rectangle
</text>
<rect x="1" y="1" width="100" height="100"
style="stroke: none; fill: #0000ff; mask: url(#mask3)"/>
这个例子的矩形下方有一个文本,其仅可通过矩形遮罩是半透明的部分可见。
最终图片如下:
<text x="10" y="55" style="stroke: none; fill: #000000;">This text is under the rectangle</text>
<rect x="1" y="1" width="100" height="100" style="stroke: none; fill: #0000ff; mask: url(#mask3)"></rect>
遮罩中使用渐变
如果对你用作遮罩的形状应用渐变,则可以实现应用遮罩的形状的渐变透明度。
下面例子定义了一个渐变,一个使用渐变的遮罩,一个使用遮罩的矩形以及矩形下方的文本,因此你可以看到随着遮罩渐变的透明度的变化:
<defs>
<linearGradient id="gradient1"
x1="0%" y1="0%"
x2="100%" y2="0%"
spreadMethod="pad">
<stop offset="0%" stop-color="#ffffff" stop-opacity="1"/>
<stop offset="100%" stop-color="#000000" stop-opacity="1"/>
</linearGradient>
<mask id="mask4" x="0" y="0" width="200" height="100" >
<rect x="0" y="0" width="200" height="100"
style="stroke:none; fill: url(#gradient1)"/>
</mask>
</defs>
<text x="10" y="55" style="stroke: none; fill: #000000;">
This text is under the rectangle
</text>
<rect x="1" y="1" width="200" height="100"
style="stroke: none; fill: #0000ff; mask: url(#mask4)"/>
最终图片如下:
<mask id="mask4" x="0" y="0" width="200" height="100">
<rect x="0" y="0" width="200" height="100" style="stroke:none; fill: url(#gradient1)"></rect>
</mask>
</defs>
<text x="10" y="55" style="stroke: none; fill: #000000;">This text is under the rectangle</text>
<rect x="1" y="1" width="200" height="100" style="stroke: none; fill: #0000ff; mask: url(#mask4)"></rect>
渐变遮罩可以与其它效果(如填充图案)组合。下面例子中的可见矩形同时使用了填充图案和渐变遮罩:
<defs>
<linearGradient id="gradient2"
x1="0%" y1="0%"
x2="100%" y2="0%"
spreadMethod="pad">
<stop offset="0%" stop-color="#ffffff" stop-opacity="1"/>
<stop offset="100%" stop-color="#000000" stop-opacity="1"/>
</linearGradient>
<pattern id="pattern2"
x="10" y="10" width="20" height="20"
patternUnits="userSpaceOnUse" >
<circle cx="10" cy="10" r="10" style="stroke: none; fill: #0000ff; " />
</pattern>
<mask id="mask6" x="0" y="0" width="200" height="100" >
<rect x="0" y="0" width="200" height="100"
style="stroke:none; fill: url(#gradient2)"/>
</mask>
</defs>
<text x="10" y="55" style="stroke: none; fill: #000000;">
This text is under the rectangle
</text>
<rect x="1" y="1" width="200" height="100"
style="stroke: none; fill: url(#pattern2); mask: url(#mask6)"/>
注意要显示的矩形如何从其 CSS 属性fill
引用填充图案,并从其 CSS 属性mask
引用遮罩。
最终图片如下:
<linearGradient id="gradient2" x1="0%" y1="0%" x2="100%" y2="0%" spreadMethod="pad">
<stop offset="0%" stop-color="#ffffff" stop-opacity="1"></stop>
<stop offset="100%" stop-color="#000000" stop-opacity="1"></stop>
</linearGradient>
<pattern id="pattern2" x="10" y="10" width="20" height="20" patternUnits="userSpaceOnUse">
<circle cx="10" cy="10" r="10" style="stroke: none; fill: #0000ff; "></circle>
</pattern>
<mask id="mask6" x="0" y="0" width="200" height="100">
<rect x="0" y="0" width="200" height="100" style="stroke:none; fill: url(#gradient2)"></rect>
</mask>
</defs>
<text x="10" y="55" style="stroke: none; fill: #000000;">This text is under the rectangle</text>
<rect x="1" y="1" width="200" height="100" style="stroke: none; fill: url(#pattern2); mask: url(#mask6)"></rect>
遮罩中使用填充图案
你还可以在遮罩中使用填充图案,从而使遮罩成为填充图案的形状。示例如下:
<defs>
<pattern id="pattern1"
x="10" y="10" width="20" height="20"
patternUnits="userSpaceOnUse" >
<circle cx="10" cy="10" r="10" style="stroke: none; fill: #999999" />
</pattern>
<mask id="mask5" x="0" y="0" width="200" height="100" >
<rect x="0" y="0" width="200" height="100"
style="stroke:none; fill: url(#pattern1)"/>
</mask>
</defs>
<text x="10" y="55" style="stroke: none; fill: #000000;">
This text is under the rectangle
</text>
<rect x="1" y="1" width="200" height="100"
style="stroke: none; fill: #0000ff; mask: url(#mask5)"/>
最终图片如下。注意,现在矩形中填充图案部分是半透明的,其它部分是完全透明的。
<pattern id="pattern1" x="10" y="10" width="20" height="20" patternUnits="userSpaceOnUse">
<circle cx="10" cy="10" r="10" style="stroke: none; fill: #999999"></circle>
</pattern>
<mask id="mask5" x="0" y="0" width="200" height="100">
<rect x="0" y="0" width="200" height="100" style="stroke:none; fill: url(#pattern1)"></rect>
</mask>
</defs>
<text x="10" y="55" style="stroke: none; fill: #000000;">This text is under the rectangle</text>
<rect x="1" y="1" width="200" height="100" style="stroke: none; fill: #0000ff; mask: url(#mask5)"></rect>
mask vs clipPath
mask 和 clipPath 在用法和用途上非常相似,但 mask 是作为 clipPath 更高级的能力出现的。但有一点区别是 clipPath 不处理 alpha,它只会剪切标签中形状边界内的内容。我们来通过代码来看下:
<svg viewBox="0 5 100 40" class="clip-mask">
<linearGradient id="gradient" x2="0" y2="1">
<stop offset="0%" stop-color="black" />
<stop offset="100%" stop-color="white" />
</linearGradient>
<clipPath id="clip">
<rect x="0" y="15" width="100" height="20" fill="url(#gradient)" />
</clipPath>
<mask id="mask">
<rect x="0" y="15" width="100" height="20" fill="url(#gradient)" />
</mask>
<circle cx="25" cy="25" r="15" fill="pink" clip-path="url(#clip)" />
<circle cx="75" cy="25" r="15" fill="pink" mask="url(#mask)" />
</svg>
这段代码的运行结果如图所示:
之所以会有不同的结果,这是因为 clipPath 只关注形状的裁切,不关心 alpha 通道。更多信息参考 06. Clip-path & Mask