如何在svg元素中使用z-index?

Kar*_*yan 140 javascript jquery svg z-index

我在我的项目中使用svg圈子,

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 120">
    <g>
        <g id="one">
            <circle fill="green" cx="100" cy="105" r="20" />
        </g>
        <g id="two">
            <circle fill="orange" cx="100" cy="95" r="20" />
        </g>
    </g>
</svg>
Run Code Online (Sandbox Code Playgroud)

我在g标签中使用z-index 来显示第一个元素.在我的项目中,我只需要使用z-index值,但我不能将z-index用于我的svg元素.我google了很多,但我找不到任何相对的东西.所以请帮我在我的svg中使用z-index.

这是DEMO.

Mai*_*lpt 152

规格

在SVG规范1.1版中,呈现顺序基于文档顺序:

first element -> "painted" first
Run Code Online (Sandbox Code Playgroud)

参考SVG 1.1.规格

3.3渲染顺序

SVG文档片段中的元素具有隐式绘制顺序,SVG文档片段中的第一个元素首先"绘制".后续元素绘制在先前绘制的元素之上.


解决方案(清洁更快)

您应该将绿色圆圈作为要绘制的最新对象.所以交换这两个元素.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="30 70 160 120"> 
   <!-- First draw the orange circle -->
   <circle fill="orange" cx="100" cy="95" r="20"/> 

   <!-- Then draw the green circle over the current canvas -->
   <circle fill="green" cx="100" cy="105" r="20"/> 
</svg>
Run Code Online (Sandbox Code Playgroud)

这里是你的jsFiddle的分支.

解决方案(替代)

use具有属性的标记xlink:href和作为元素的id的值.请记住,即使结果看起来不错,也可能不是最佳解决方案.有一点时间,这里是规范SVG 1.1"使用"元素的链接.

目的:

避免要求作者修改引用的文档以向根元素添加ID.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="30 70 160 120">
    <!-- First draw the green circle -->
    <circle id="one" fill="green" cx="100" cy="105" r="20" />
    
    <!-- Then draw the orange circle over the current canvas -->
    <circle id="two" fill="orange" cx="100" cy="95" r="20" />
    
    <!-- Finally draw again the green circle over the current canvas -->
    <use xlink:href="#one"/>
</svg>
Run Code Online (Sandbox Code Playgroud)


关于SVG 2的注释

SVG 2规范是下一个主要版本,仍然支持上述功能.

3.4.渲染顺序

SVG中的元素以三维方式定位.除了它们在SVG视口的x和y轴上的位置之外,SVG元素也位于z轴上.z轴上的位置定义了它们的绘制顺序.

沿z轴,元素被分组为堆叠上下文.

3.4.1.在SVG中建立堆叠上下文

...

堆叠上下文是用于描述在呈现文档时元素必须一个在另一个上面绘制的顺序的概念工具,...

  • 哎呀!按照您希望它们绘制的顺序绘制元素并不总是很容易,特别是如果以编程方式生成对象并且可能看起来是嵌套的(例如,它看起来**g**不能包含a,b,这样一个低于g兄弟c但b高于它) (6认同)
  • 对于在 2021 年或以后发现这个答案的人来说,随着 SVG 2 版本的发布,“xlink:href”已被弃用,取而代之的是“href”。 (3认同)

Luc*_*ems 30

尝试反转#one#two.看看这个小提琴:http://jsfiddle.net/hu2pk/3/

Update

在SVG中,z-index由元素在文档中出现的顺序定义.如果需要,您也可以查看此页面:https://stackoverflow.com/a/482147/1932751

  • 任何SVG规范中都没有z-index属性.定义哪些元素出现在顶部以及哪些元素出现在底部的唯一方法是使用DOM排序 (9认同)
  • `d3.selection.prototype.moveToFront = function(){return this.each(function(){this.parentNode.appendChild(this);}); 然后你可以通过http://stackoverflow.com/questions/14167863/how-can-i-bring-a-circle-to-the-front-with-d3说'selection.moveToFront()` (9认同)

Ste*_*ich 24

正如其他人所说,z-index是由元素在DOM中出现的顺序定义的.如果手动重新排序您的html不是一个选项或者很难,您可以使用D3来重新排序SVG组/对象.

使用D3更新DOM顺序和模拟Z-Index功能

使用D3更新SVG元素Z-Index

在最基本的级别(如果您不使用其他任何ID),您可以使用元素ID作为z-index的替代,并重新排序.除此之外,你几乎可以让你的想象力疯狂.

代码段中的示例

var circles = d3.selectAll('circle')
var label = d3.select('svg').append('text')
    .attr('transform', 'translate(' + [5,100] + ')')

var zOrders = {
    IDs: circles[0].map(function(cv){ return cv.id; }),
    xPos: circles[0].map(function(cv){ return cv.cx.baseVal.value; }),
    yPos: circles[0].map(function(cv){ return cv.cy.baseVal.value; }),
    radii: circles[0].map(function(cv){ return cv.r.baseVal.value; }),
    customOrder: [3, 4, 1, 2, 5]
}

var setOrderBy = 'IDs';
var setOrder = d3.descending;

label.text(setOrderBy);
circles.data(zOrders[setOrderBy])
circles.sort(setOrder);
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 100"> 
  <circle id="1" fill="green" cx="50" cy="40" r="20"/> 
  <circle id="2" fill="orange" cx="60" cy="50" r="18"/>
  <circle id="3" fill="red" cx="40" cy="55" r="10"/> 
  <circle id="4" fill="blue" cx="70" cy="20" r="30"/> 
  <circle id="5" fill="pink" cx="35" cy="20" r="15"/> 
</svg>
Run Code Online (Sandbox Code Playgroud)

基本思路是:

  1. 使用D3选择SVG DOM元素.

    var circles = d3.selectAll('circle')
    
    Run Code Online (Sandbox Code Playgroud)
  2. 创建一些与您的SVG元素(要重新排序)的1:1关系的z-indices数组.以下示例中使用的Z-index数组是ID,x和y位置,半径等....

    var zOrders = {
        IDs: circles[0].map(function(cv){ return cv.id; }),
        xPos: circles[0].map(function(cv){ return cv.cx.baseVal.value; }),
        yPos: circles[0].map(function(cv){ return cv.cy.baseVal.value; }),
        radii: circles[0].map(function(cv){ return cv.r.baseVal.value; }),
        customOrder: [3, 4, 1, 2, 5]
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 然后,使用D3将z-indices绑定到该选择.

    circles.data(zOrders[setOrderBy]);
    
    Run Code Online (Sandbox Code Playgroud)
  4. 最后,调用D3.sort根据数据重新排序DOM中的元素.

    circles.sort(setOrder);
    
    Run Code Online (Sandbox Code Playgroud)

例子

在此输入图像描述

  • 您可以按ID进行堆叠

在此输入图像描述

  • 最左边的SVG在顶部

在此输入图像描述

  • 顶部最小的半径

在此输入图像描述

  • 或指定一个数组以应用特定排序的z-index - 在我的示例代码中,数组[3,4,1,2,5]移动/重新排序第3个圆圈(在原始HTML顺序中)为DOM中的第1个,第4个为第2个,第1个为第3个, 等等...

  • @Tigerrrrrrr 导入外部库来做一些像控制堆叠顺序这样简单的事情是疯狂的。更糟糕的是,D3 是一个特别大的库。 (4认同)
  • @iMe,说得好。虽然这是一个问题的解决方案,但让它值得出现在这里;它不是,也不应该是*答案。唯一应该取代当前答案的是如果有更新的规范出现并且浏览器发生变化。任何想要使用这个答案的人,不要导入所有的 D3,只需导入您需要的模块。不要为此导入所有 D3。 (4认同)

Jos*_*tos 21

你可以使用.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 120">
    <g>
        <g id="one">
            <circle fill="green" cx="100" cy="105" r="20" />
        </g>
        <g id="two">
            <circle fill="orange" cx="100" cy="95" r="20" />
        </g>
    </g>
    <use xlink:href="#one" />
</svg>
Run Code Online (Sandbox Code Playgroud)

绿色圆圈显示在顶部.
的jsfiddle

  • 这会画两次#one吗? (4认同)
  • +1 因为它不需要 javascript,但 -1 因为你也可以在加载之前更改 DOM 时更改 `&lt;g&gt;` 本身的顺序。 (2认同)

bum*_*ard 13

如上所述,svgs按顺序呈现,并且不考虑z-index(现在).也许只是将特定元素发送到其父元素的底部,以便它最后呈现.

function bringToTop(targetElement){
  // put the element at the bottom of its parent
  let parent = targetElement.parentNode;
  parent.appendChild(targetElement);
}

// then just pass through the element you wish to bring to the top
bringToTop(document.getElementById("one"));
Run Code Online (Sandbox Code Playgroud)

为我工作.


Jos*_*nce 11

这是有关 z-index 和 SVG 的 Google 搜索的最高结果。读完所有答案(其中一些答案非常好)后,我仍然感到困惑。

所以对于像我这样的新手来说,这是当前的总结,9年后的2022年。

您不能将 z-index 与 SVG 一起使用。

在 SVG 中,z-index 由元素在文档中出现的顺序定义。

如果您希望某些内容显示在顶部或更靠近用户,请最后绘制或插入之前。 来源

SVG 2 可以支持 z-index 但可能永远不会出现

SVG 2 是实现该功能和其他功能的提案,但它面临着永远无法推进的风险。

SVG 2于2016年进入候选推荐阶段,并于2018年进行修订,最新草案于2021年6月8日发布。来源

然而它没有得到很多支持,也很少有人致力于它。来源所以不要屏住呼吸等待这一点。

您可以使用 D3,但可能不应该

D3常用于可视化数据,通过绑定 z 索引然后排序来支持 z 索引,但它是一个大型且复杂的库,如果您只想让某个 SVG 出现在堆栈顶部,那么它可能不是最佳选择。


Haf*_*ich 9

svgs没有z-index.但是svg确定哪些元素在DOM中的最重要位置.因此,您可以删除Object并将其放在svg的末尾,使其成为"最后渲染"元素.然后,那个视觉呈现为"最顶层".


使用jQuery:

function moveUp(thisObject){
    thisObject.appendTo(thisObject.parents('svg>g'));
}
Run Code Online (Sandbox Code Playgroud)

用法:

moveUp($('#myTopElement'));
Run Code Online (Sandbox Code Playgroud)

使用D3.js:

d3.selection.prototype.moveUp = function() {
    return this.each(function() {
        this.parentNode.appendChild(this);
    });
};
Run Code Online (Sandbox Code Playgroud)

用法:

myTopElement.moveUp();
Run Code Online (Sandbox Code Playgroud)


小智 9

使用D3:

如果要按顺序重新插入每个选定元素,作为其父级的最后一个子元素.

selection.raise()
Run Code Online (Sandbox Code Playgroud)

  • `selection.raise()`是自v4起D3中的新功能. (3认同)

Nat*_*her 8

使用D3:

如果要以相反的顺序将元素添加到数据使用:

.insert('g', ":first-child")
Run Code Online (Sandbox Code Playgroud)

而不是.append

将元素添加到组元素的顶部


Rom*_*ler 5

另一个解决方案是使用div,该div确实使用zIndex包含SVG元素。例如:https : //stackoverflow.com/a/28904640/4552494


Dou*_*eco 5

截至本答案发布之日,发布的干净、快速和简单的解决方案并不令人满意。它们是基于 SVG 文档缺乏 z 顺序的有缺陷的陈述而构建的。图书馆也不是必需的。一行代码可以执行大多数操作来操纵对象或对象组的 z 顺序,这些操作在开发在 xyz 空间中移动 2D 对象的应用程序中可能需要。

Z 顺序绝对存在于 SVG 文档片段中

所谓的 SVG 文档片段是从基本节点类型 SVGElement 派生的元素树。SVG 文档片段的根节点是一个 SVGSVGElement,它对应于 HTML5 <svg>标签。SVGGElement 对应于<g>标记并允许聚合子项。

在 SVGElement 上拥有一个 z-index 属性就像在 CSS 中一样会破坏 SVG 渲染模型。W3C SVG Recommendation v1.1 2nd Edition 的第 3.3 和 3.4 节声明 SVG 文档片段(来自 SVGSVGElement 的后代树)是使用所谓的树深度优先搜索来呈现的。该方案在该术语的任何意义上都是 az 顺序。

Z 顺序实际上是一种计算机视觉捷径,可避免由于光线追踪的复杂性和计算需求而需要真正的 3D 渲染。SVG 文档片段中元素的隐式 z-index 的线性方程。

z-index = z-index_of_svg_tag + depth_first_tree_index / tree_node_qty
Run Code Online (Sandbox Code Playgroud)

这很重要,因为如果您想将位于正方形下方的圆移动到其上方,只需在圆之前插入正方形即可。这可以在 JavaScript 中轻松完成。

支持方法

SVGElement 实例有两种支持简单易行的 z 顺序操作的方法。

  • parent.removeChild(child)
  • parent.insertBefore(child, childRef)

不会造成混乱的正确答案

由于可以像删除和插入 SVGCircleElement 或任何其他形状一样轻松地删除和插入SVGGElement(<g>标记),因此可以使用 SVGGElement 轻松实现 Adob​​e 产品和其他图形工具的典型图像层。这个 JavaScript 本质上是一个移动下方命令。

parent.insertBefore(parent.removeChild(gRobot), gDoorway)
Run Code Online (Sandbox Code Playgroud)

如果绘制为 SVGGElement gRobot 的孩子的机器人的层在绘制为 SVGGElement gDoorway 的孩子的门口之前,机器人现在在门口后面,因为门口的 z 阶现在是机器人的 z 阶加一。

一个以上移动命令是几乎一样简单。

parent.insertBefore(parent.removeChild(gRobot), gDoorway.nextSibling())
Run Code Online (Sandbox Code Playgroud)

想想 a=a 和 b=b 来记住这一点。

insert after = move above
insert before = move below
Run Code Online (Sandbox Code Playgroud)

让 DOM 处于与视图一致的状态

这个答案正确的原因是因为它是最小的和完整的,并且像 Adob​​e 产品或其他设计良好的图形编辑器的内部一样,使内部表示处于与通过渲染创建的视图一致的状态。

替代但有限的方法

另一种常用的方法是将 CSS z-index 与多个 SVG 文档片段(SVG 标签)结合使用,除了底部之外,所有的背景几乎都是透明的。同样,这破坏了 SVG 渲染模型的优雅,使得在 z 顺序中向上或向下移动对象变得困难。


笔记:

  1. https://www.w3.org/TR/SVG/render.html v 1.1,第 2 版,2011 年 8 月 16 日)

    3.3 渲染顺序 SVG 文档片段中的元素具有隐式绘制顺序,SVG 文档片段中的第一个元素首先被“绘制”。后续元素绘制在先前绘制的元素之上。

    3.4 如何呈现组 诸如“g”元素(请参阅容器元素)之类的分组元素具有生成临时单独画布的效果,该画布初始化为透明黑色,在其上绘制子元素。组完成后,为组指定的任何滤镜效果都将应用于创建修改后的临时画布。修改后的临时画布合成到背景中,考虑到组上的任何组级遮罩和不透明度设置。