clipPath-mask与marker
三者都是 渲染期效果,不修改 d。导出、布尔运算、节点编辑必须另写几何;命中是否跟着裁切走,也不要靠感觉。
1. clipPath vs mask
clipPath | mask | |
|---|---|---|
| 本质 | 硬裁切,按 clip 内容的填充形状 | 按亮度或 alpha 调制,可半透明 |
| 软边 | 没有(抗锯齿除外) | 有,blur / 渐变都能进 mask |
| 成本 | 相对低,仍可能建层 | 离屏缓冲,接近滤镜 |
| 单位 | clipPathUnits:userSpaceOnUse / objectBoundingBox | maskUnits + maskContentUnits,同样两套 |
<clipPath id="hole" clipPathUnits="userSpaceOnUse">
<rect x="10" y="10" width="80" height="80"/>
</clipPath>
<g clip-path="url(#hole)">...</g>
objectBoundingBox 的 clip/mask 同样会在 零宽或零高包围盒 上失败,见 渐变 Pattern 与滤镜。
CSS clip-path 可以 url(#id) 指到 SVG clipPath。交互层用 SVG 属性或 CSS 选一条写入通道,序列化进文件时要能还原。
mask-type: luminance(SVG 传统:白显黑隐)和 alpha 不要混。从设计工具拷来的 mask 发灰,先查是不是把 alpha 图当亮度用了。
适用:头像圆裁、地图视窗、淡入边缘。
不适用:想得到「挖洞后的 path 数据」——那是布尔运算,clip 只是看起来挖了。
2. 不要用 clip 当布尔运算
clip-path / mask 之后:
d仍是原路径,getTotalLength仍是全长。- 序列化 SVG 文件,下游打开仍是完整几何 + 一条 clip 引用。
- 命中:被裁掉的像素通常点不中,但几何 API(
isPointInFill、getBBox({ clipped: false }))仍按未裁形状。框选要对齐「数据」还是「可见」,必须显式选clipped。
编辑器要并/交/差:改 path 数据(或存 boolean 树再烘焙)。渲染期 clip 只给预览或装饰开窗。Canvas 侧同类边界见 路径布尔运算。
3. marker 坐标系
<marker id="arrow" viewBox="0 0 10 10" refX="10" refY="5"
markerWidth="6" markerHeight="6" orient="auto-start-reverse"
markerUnits="strokeWidth">
<path d="M 0 0 L 10 5 L 0 10 z" fill="context-stroke"/>
</marker>
<path d="M 10 10 L 90 10" stroke="currentColor" marker-end="url(#arrow)"/>
| 字段 | 含义 |
|---|---|
markerUnits="strokeWidth"(默认) | markerWidth 乘在 被标记元素的线宽 上 |
userSpaceOnUse | markerWidth 直接是用户单位 |
refX / refY | 钉在顶点上的局部点 |
orient="auto" | 跟切线;起点箭头用 auto-start-reverse |
vector-effect: non-scaling-stroke 改变的是 被标记 path 的线宽怎么画,marker 默认仍按 strokeWidth 单位放大。相机缩放后箭头相对线宽是否好看,要自己试;不要假定 marker 也 non-scaling。
marker 是绘制时戳印,不是可点的独立节点。不要对箭头做 elementFromPoint 指望点到 marker 里的 path——命中落在宿主 path 上(还受 pointer-events 约束)。可编辑箭头:把三角形烘焙进几何,或单独一条 path。
context-stroke / context-fill 让 marker 跟宿主走。实现仍有缺口时,回退成 currentColor 或写死并在主题切换时改 fill。
4. 失败形态
| 症状 | 原因 |
|---|---|
| 导出后再编辑,洞没了 | 只用了 clip,没有改 d |
| 框选到被裁掉的「幽灵」 | getBBox / 相交用了 clipped: false |
| 细线上 clip 消失 | objectBoundingBox 零尺寸 |
| 箭头随相机巨大 | markerUnits=strokeWidth 且线宽写在用户空间未补偿 |
| 点不中箭头 | 以为 marker 是 DOM 子树 |
权威资料
核对日期:2026-08-26