跳到主要内容

裁剪与遮罩

裁剪和遮罩是控制图形可见区域的两种技术。裁剪使用几何形状定义可见区域,遮罩使用图像的亮度或透明度控制可见性。这两种技术可以创建复杂的视觉效果。

裁剪 - clipPath

裁剪使用 <clipPath> 元素定义一个裁剪区域,只有在该区域内的图形部分才会显示。

基本用法

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="clip-rect">
<rect x="50" y="20" width="100" height="100"/>
</clipPath>
</defs>
<circle cx="100" cy="75" r="60" fill="#3498db"/>
<circle cx="200" cy="75" r="60" fill="#e74c3c" clip-path="url(#clip-rect)"/>
</svg>

红色圆形被矩形裁剪,只有矩形区域内的部分可见。

使用 clip-path 属性

clip-path 属性引用定义好的裁剪路径:

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="circle-clip">
<circle cx="150" cy="75" r="50"/>
</clipPath>
</defs>
<rect x="0" y="0" width="300" height="150" fill="#2ecc71" clip-path="url(#circle-clip)"/>
</svg>

裁剪路径的内容

裁剪路径可以包含任何图形元素:

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="text-clip">
<text x="150" y="90" text-anchor="middle" font-size="60" font-weight="bold">SVG</text>
</clipPath>
</defs>
<rect x="0" y="0" width="300" height="150" fill="#9b59b6"/>
<rect x="0" y="0" width="300" height="150" fill="#f39c12" clip-path="url(#text-clip)"/>
</svg>

文字形状作为裁剪区域,显示底层的橙色。

多个裁剪形状

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="multi-clip">
<circle cx="75" cy="75" r="50"/>
<circle cx="150" cy="75" r="50"/>
<circle cx="225" cy="75" r="50"/>
</clipPath>
</defs>
<rect x="0" y="0" width="300" height="150" fill="#1abc9c" clip-path="url(#multi-clip)"/>
</svg>

多个形状的并集作为裁剪区域。

clipPathUnits 属性

clipPathUnits 定义裁剪路径的坐标系统:

  • userSpaceOnUse(默认):使用 SVG 画布坐标
  • objectBoundingBox:使用被裁剪元素的边界框坐标(0-1)
<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="bbox-clip" clipPathUnits="objectBoundingBox">
<rect x="0.2" y="0.2" width="0.6" height="0.6"/>
</clipPath>
</defs>
<rect x="10" y="10" width="80" height="80" fill="#e74c3c" clip-path="url(#bbox-clip)"/>
<rect x="110" y="10" width="160" height="100" fill="#3498db" clip-path="url(#bbox-clip)"/>
</svg>

使用 objectBoundingBox 时,裁剪区域自动适应被裁剪元素的大小。

遮罩 - mask

遮罩使用图像的亮度或透明度控制元素的可见性。与裁剪不同,遮罩支持半透明效果。

基本用法

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<defs>
<mask id="gradient-mask">
<rect x="0" y="0" width="300" height="150" fill="url(#fade-gradient)"/>
<linearGradient id="fade-gradient">
<stop offset="0%" stop-color="white"/>
<stop offset="100%" stop-color="black"/>
</linearGradient>
</mask>
</defs>
<rect x="0" y="0" width="300" height="150" fill="#3498db" mask="url(#gradient-mask)"/>
</svg>

遮罩中白色区域完全可见,黑色区域完全透明,灰色区域半透明。

遮罩原理

遮罩的工作原理:

  • 白色(RGB: 255, 255, 255)= 完全不透明
  • 黑色(RGB: 0, 0, 0)= 完全透明
  • 灰色 = 半透明
<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<defs>
<mask id="opacity-mask">
<rect x="20" y="20" width="60" height="60" fill="white"/>
<rect x="100" y="20" width="60" height="60" fill="#808080"/>
<rect x="180" y="20" width="60" height="60" fill="black"/>
</mask>
</defs>
<rect x="0" y="0" width="300" height="150" fill="#e74c3c" mask="url(#opacity-mask)"/>
</svg>

渐变遮罩

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<defs>
<mask id="radial-mask">
<radialGradient id="spotlight">
<stop offset="0%" stop-color="white"/>
<stop offset="70%" stop-color="white"/>
<stop offset="100%" stop-color="black"/>
</radialGradient>
<rect x="0" y="0" width="300" height="150" fill="url(#spotlight)"/>
</mask>
</defs>
<image href="https://picsum.photos/300/150" width="300" height="150" mask="url(#radial-mask)"/>
</svg>

文字遮罩

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<defs>
<mask id="text-mask">
<rect x="0" y="0" width="300" height="150" fill="black"/>
<text x="150" y="90" text-anchor="middle" font-size="50" font-weight="bold" fill="white">
MASK
</text>
</mask>
</defs>
<rect x="0" y="0" width="300" height="150" fill="#9b59b6"/>
<rect x="0" y="0" width="300" height="150" fill="#f39c12" mask="url(#text-mask)"/>
</svg>

maskUnits 和 maskContentUnits

与 clipPath 类似,mask 也支持坐标系统设置:

  • maskUnits:mask 元素的坐标系统
  • maskContentUnits:mask 内容的坐标系统
<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<defs>
<mask id="bbox-mask" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox">
<rect x="0.1" y="0.1" width="0.8" height="0.8" fill="white"/>
</mask>
</defs>
<rect x="10" y="10" width="80" height="60" fill="#e74c3c" mask="url(#bbox-mask)"/>
<rect x="110" y="10" width="160" height="100" fill="#3498db" mask="url(#bbox-mask)"/>
</svg>

裁剪与遮罩的区别

特性裁剪(clipPath)遮罩(mask)
定义方式几何形状图像亮度
透明度支持不支持(只有可见/不可见)支持(可半透明)
性能较好较差
复杂度简单复杂

CSS clip-path

CSS 也支持 clip-path 属性,可以直接在样式中定义裁剪:

基本形状

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<style>
.clip-circle { clip-path: circle(50px at 100px 75px); }
.clip-ellipse { clip-path: ellipse(80px 40px at 220px 75px); }
</style>
<rect x="0" y="0" width="200" height="150" fill="#e74c3c" class="clip-circle"/>
<rect x="150" y="0" width="150" height="150" fill="#3498db" class="clip-ellipse"/>
</svg>

多边形裁剪

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<style>
.clip-polygon { clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); }
</style>
<rect x="50" y="0" width="200" height="150" fill="#2ecc71" class="clip-polygon"/>
</svg>

inset 裁剪

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<style>
.clip-inset { clip-path: inset(20px 30px 20px 30px round 10px); }
</style>
<rect x="0" y="0" width="300" height="150" fill="#f39c12" class="clip-inset"/>
</svg>

实用示例

圆形头像

<svg width="150" height="150" xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="avatar-clip">
<circle cx="75" cy="75" r="70"/>
</clipPath>
</defs>
<rect x="5" y="5" width="140" height="140" fill="#bdc3c7" clip-path="url(#avatar-clip)"/>
<circle cx="75" cy="75" r="70" fill="none" stroke="#2c3e50" stroke-width="3"/>
</svg>

图片边框

<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="hex-clip">
<polygon points="100,10 180,50 180,150 100,190 20,150 20,50"/>
</clipPath>
</defs>
<rect x="0" y="0" width="200" height="200" fill="#3498db" clip-path="url(#hex-clip)"/>
<polygon points="100,10 180,50 180,150 100,190 20,150 20,50"
fill="none" stroke="#2c3e50" stroke-width="3"/>
</svg>

淡出效果

<svg width="300" height="100" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="fade-grad">
<stop offset="0%" stop-color="white"/>
<stop offset="70%" stop-color="white"/>
<stop offset="100%" stop-color="black"/>
</linearGradient>
<mask id="fade-mask">
<rect x="0" y="0" width="300" height="100" fill="url(#fade-grad)"/>
</mask>
</defs>
<text x="0" y="50" font-size="30" fill="#2c3e50" mask="url(#fade-mask)">
这段文字会逐渐淡出消失
</text>
</svg>

聚光灯效果

<svg width="300" height="200" xmlns="http://www.w3.org/2000/svg">
<defs>
<radialGradient id="spotlight-grad">
<stop offset="0%" stop-color="white"/>
<stop offset="30%" stop-color="white"/>
<stop offset="100%" stop-color="black"/>
</radialGradient>
<mask id="spotlight-mask">
<rect x="0" y="0" width="300" height="200" fill="url(#spotlight-grad)"/>
</mask>
</defs>
<rect x="0" y="0" width="300" height="200" fill="#2c3e50"/>
<rect x="0" y="0" width="300" height="200" fill="#3498db" mask="url(#spotlight-mask)"/>
</svg>

文字镂空

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<defs>
<mask id="cutout-mask">
<rect x="0" y="0" width="300" height="150" fill="white"/>
<text x="150" y="90" text-anchor="middle" font-size="60" font-weight="bold" fill="black">
SVG
</text>
</mask>
</defs>
<rect x="0" y="0" width="300" height="150" fill="#e74c3c" mask="url(#cutout-mask)"/>
</svg>

小结

裁剪和遮罩是控制图形可见性的强大工具。裁剪使用几何形状定义硬边界,遮罩使用图像亮度实现软过渡。裁剪适合简单的形状限制,遮罩适合需要透明度变化的复杂效果。两者结合使用可以创建丰富的视觉效果。