绘制顺序与层叠
SVG 默认是 文档序画家算法:后面的兄弟盖住前面的。这不是 Canvas 的 globalCompositeOperation 图层系统,也不是完整的 HTML 层叠上下文教科书——但 HTML 的 z-index / opacity / filter 会在 inline SVG 上制造新的合成层。
1. 文档序
<svg viewBox="0 0 200 200">
<rect width="200" height="200" fill="#eee"/>
<circle cx="80" cy="80" r="40" fill="crimson"/>
<circle cx="110" cy="110" r="40" fill="steelblue"/>
</svg>
钢蓝盖住绯红。要改叠放,移动 DOM 节点(append / insertBefore),不要幻想有 ctx.restore 能把下面那层挖回来。
export function bringToFront(el: SVGElement): void {
el.parentNode?.append(el);
}
export function sendToBack(el: SVGElement): void {
const parent = el.parentNode;
if (!parent) return;
parent.insertBefore(el, parent.firstChild);
}
2. 组与隔离
<g> 是变换和样式的作用域,不是 自动合成层。组上的 opacity: 0.5 会先把子树画在离屏缓冲再整体淡出——两个半透明圆重叠处不会「各 50% 叠成 75%」,而是整组 50%。这是设计师常踩的坑。
需要「每个子节点自己透明」时,透明度写在叶子上,不要写在组上。
isolation: isolate、filter、mask、mix-blend-mode 同样可能逼出离屏层。性能见 滤镜合成层与重绘。
3. z-index 能用,但不要当编辑器模型
inline SVG 在 HTML 文档里,子元素可以建层叠上下文。用 z-index 调装饰层可以,用它当图层系统会和「文档序 = 文件格式」冲突:序列化时 z-index 不一定写进 SVG 文件,另一端打开就乱。
生产编辑器:图层 = DOM 兄弟序(必要时外加 <g data-layer>)。CSS z-index 只留给不进文件的 UI chrome。
4. display / visibility / pointer-events
| 属性 | 渲染 | 命中 | 布局/包围盒 |
|---|---|---|---|
display: none | 否 | 否 | 不占渲染树;getCTM 可能为 null |
visibility: hidden | 否 | 默认不命中 | 仍占几何 |
opacity: 0 | 看不见 | 默认可命中 | 仍占几何 |
pointer-events: none | 照常 | 否 | 照常 |
隐藏但要占位的占位符用 visibility。彻底拆下用 display 或从树里 remove。透明遮罩坑:opacity: 0 的大 rect 会挡住下面的点击。
5. 失败形态
| 症状 | 原因 |
|---|---|
| 导出后再打开图层全乱 | 靠 CSS z-index 叠放,没改 DOM 序 |
| 组 fade 后重叠色不对 | opacity 写在 <g> 上,整组先合成 |
| 点不到下面的节点 | 上面有全屏透明 rect 或组级 pointer-events |
| getBBox 抛错或全 0 | 元素 display: none 或不在文档里 |
权威资料
核对日期:2026-08-26