裁剪与遮罩
裁剪和遮罩是控制图形可见区域的两种技术。裁剪使用几何形状定义可见区域,遮罩使用图像的亮度或透明度控制可见性。这两种技术可以创建复杂的视觉效果。
裁剪 - 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>
小结
裁剪和遮罩是控制图形可见性的强大工具。裁剪使用几何形状定义硬边界,遮罩使用图像亮度实现软过渡。裁剪适合简单的形状限制,遮罩适合需要透明度变化的复杂效果。两者结合使用可以创建丰富的视觉效果。