截至本答案发布之日,干净、快速、简单的解决方案并不令人满意。它们是建立在 SVG 文档缺乏 z 顺序的有缺陷的陈述之上的。库也不是必需的。一行代码可以执行大多数操作来操纵在 xyz 空间中移动 2D 对象的应用程序开发中可能需要的对象或对象组的 z 顺序。
SVG 文档片段中肯定存在 Z 顺序
所谓的 SVG 文档片段是从基本节点类型 SVGElement 派生的元素树。SVG 文档片段的根节点是一个 SVGSVGElement,它对应于 HTML5 <svg>标签。SVGGElement 对应于<g>标签并允许聚合子元素。
像在 CSS 中那样在 SVGElement 上具有 z-index 属性会破坏 SVG 渲染模型。W3C SVG Recommendation v1.1 2nd Edition 的第 3.3 和 3.4 节指出 SVG 文档片段(来自 SVGSVGElement 的后代树)是使用所谓的树的深度优先搜索来呈现的。该方案在任何意义上都是按顺序排列的。
Z 顺序实际上是一种计算机视觉捷径,可以避免需要真正的 3D 渲染以及光线追踪的复杂性和计算需求。SVG 文档片段中元素的隐式 z-index 的线性方程。
z-index = z-index_of_svg_tag + depth_first_tree_index / tree_node_qty
这很重要,因为如果您想将低于正方形的圆圈移动到其上方,您只需将正方形插入圆圈之前。这可以在 JavaScript 中轻松完成。
支持方法
SVGElement 实例有两种方法支持简单易用的 z 顺序操作。
- parent.removeChild(子)
- parent.insertBefore(孩子,childRef)
不会造成混乱的正确答案
因为 SVGGElement(<g>标签)可以像 SVGCircleElement 或任何其他形状一样轻松地删除和插入,所以可以使用 SVGGElement 轻松实现 Adobe 产品和其他图形工具的典型图像层。这个 JavaScript 本质上是一个“下移”命令。
parent.insertBefore(parent.removeChild(gRobot), gDoorway)
如果作为 SVGGElement gRobot 的子级绘制的机器人的层在作为 SVGGElement gDoorway 的子级绘制的门口之前,则机器人现在位于门口之后,因为门口的 z 顺序现在是机器人的 z 顺序的 1。
上移命令几乎同样简单。
parent.insertBefore(parent.removeChild(gRobot), gDoorway.nextSibling())
只要想想 a=a 和 b=b 就可以记住这一点。
insert after = move above
insert before = move below
让 DOM 处于与视图一致的状态
这个答案正确的原因是因为它是最小且完整的,并且像 Adobe 产品或其他设计良好的图形编辑器的内部一样,使内部表示处于与渲染创建的视图一致的状态。
另类但有限的方法
另一种常用的方法是将 CSS z-index 与多个 SVG 文档片段(SVG 标签)结合使用,除了底部之外,所有的背景都大多是透明的。再一次,这破坏了 SVG 渲染模型的优雅,使得在 z 顺序中向上或向下移动对象变得困难。
笔记:
- (https://www.w3.org/TR/SVG/render.html v 1.1,第 2 版,2011 年 8 月 16 日)
3.3 渲染顺序 SVG 文档片段中的元素具有隐式的绘制顺序,SVG 文档片段中的第一个元素首先被“绘制”。随后的元素被绘制在先前绘制的元素之上。
3.4 组是如何呈现的 分组元素,如'g'元素(参见容器元素)具有生成一个临时独立画布的效果,该画布初始化为透明黑色,子元素被绘制在其上。组完成后,将应用为组指定的任何滤镜效果以创建修改后的临时画布。修改后的临时画布被合成到背景中,同时考虑到组上的任何组级蒙版和不透明度设置。