207

我在我的项目中使用 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>

我使用g标签中的 z-index 来首先显示元素。在我的项目中,我只需要使用 z-index 值,但我不能将 z-index 用于我的 svg 元素。我用谷歌搜索了很多,但我没有找到任何相对的东西。所以请帮助我在我的 svg 中使用 z-index。

这是演示。

4

16 回答 16

207

规格

在 SVG 规范 1.1 版中,渲染顺序基于文档顺序:

first element -> "painted" first

参考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>

这里是你的jsFiddle的分支。

解决方案(替代)

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

目的:

避免要求作者修改引用的文档以将 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>


SVG 2 的注意事项

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

3.4. 渲染顺序

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

沿着 z 轴,元素被分组到堆叠上下文中。

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

...

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

于 2014-08-14T07:23:10.710 回答
38

正如其他人所说,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);
<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>

基本思想是:

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

    var circles = d3.selectAll('circle')
    
  2. 创建一些与您的 SVG 元素(要重新排序)具有 1:1 关系的 z 索引数组。以下示例中使用的 Z 索引数组是 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]
    }
    
  3. 然后,使用 D3 将您的 z 索引绑定到该选择。

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

    circles.sort(setOrder);
    

例子

在此处输入图像描述

  • 您可以按 ID 堆叠

在此处输入图像描述

  • 最左边的 SVG 在顶部

在此处输入图像描述

  • 顶部最小半径

在此处输入图像描述

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

于 2016-04-20T07:01:29.410 回答
37

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

Update

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

于 2013-07-22T11:44:28.147 回答
22

您可以使用.

<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>

绿色圆圈出现在顶部。
jsFiddle

于 2014-10-09T11:36:36.417 回答
18

正如所讨论的,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"));

为我工作。

更新

如果您有一个包含组的嵌套 SVG,则需要将项目从其父节点中取出。

function bringToTopofSVG(targetElement){
  let parent = targetElement.ownerSVGElement;
  parent.appendChild(targetElement);
}

SVG 的一个很好的特性是每个元素都包含它的位置,而不管它嵌套在哪个组中:+1:

于 2017-11-15T03:25:18.683 回答
17

使用 D3:

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

selection.raise()
于 2017-11-14T12:47:45.977 回答
9

svgs 没有 z-index。但是 svg 通过它们在 DOM 中的位置来确定哪些元素是最上面的。因此,您可以删除对象并将其放置在 svg 的末尾,使其成为“最后渲染”的元素。然后将那个在视觉上呈现为“最顶层”。


使用 jQuery:

function moveUp(thisObject){
    thisObject.appendTo(thisObject.parents('svg>g'));
}

用法:

moveUp($('#myTopElement'));

使用 D3.js:

d3.selection.prototype.moveUp = function() {
    return this.each(function() {
        this.parentNode.appendChild(this);
    });
};

用法:

myTopElement.moveUp();

于 2016-10-24T22:22:45.520 回答
8

使用 D3:

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

.insert('g', ":first-child")

而不是 .append

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

于 2016-04-22T11:29:19.087 回答
6

截至本答案发布之日,干净、快速、简单的解决方案并不令人满意。它们是建立在 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 轻松实现 Adob​​e 产品和其他图形工具的典型图像层。这个 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 处于与视图一致的状态

这个答案正确的原因是因为它是最小且完整的,并且像 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'元素(参见容器元素)具有生成一个临时独立画布的效果,该画布初始化为透明黑色,子元素被绘制在其上。组完成后,将应用为组指定的任何滤镜效果以创建修改后的临时画布。修改后的临时画布被合成到背景中,同时考虑到组上的任何组级蒙版和不透明度设置。

于 2018-06-12T12:52:30.973 回答
5

另一种解决方案是使用 div,它使用 zIndex 来包含 SVG 元素。如下所示: https ://stackoverflow.com/a/28904640/4552494

于 2015-03-06T18:15:41.993 回答
4

我们已经2019 年了,z-index但 SVG 仍然不支持。

您可以在 Mozilla 的 SVG2 支持网站上看到状态为z-index-未实现

您还可以在站点上看到Bug 360148“支持 SVG 元素上的 'z-index' 属性”(报告:12 年前)。

但是你在 SVG 中有 3 种可能性来设置它:

  1. element.appendChild(aChild);
  2. parentNode.insertBefore(newNode, referenceNode);
  3. targetElement.insertAdjacentElement(positionStr, newElement);(在 IE 中不支持 SVG)

交互式演示示例

拥有这 3 个功能。

var state = 0,
    index = 100;

document.onclick = function(e)
{
    if(e.target.getAttribute('class') == 'clickable')
    {
        var parent = e.target.parentNode;

        if(state == 0)
            parent.appendChild(e.target);
        else if(state == 1)
            parent.insertBefore(e.target, null); //null - adds it on the end
        else if(state == 2)
            parent.insertAdjacentElement('beforeend', e.target);
        else
            e.target.style.zIndex = index++;
    }
};

if(!document.querySelector('svg').insertAdjacentElement)
{
    var label = document.querySelectorAll('label')[2];
    label.setAttribute('disabled','disabled');
    label.style.color = '#aaa';
    label.style.background = '#eee';
    label.style.cursor = 'not-allowed';
    label.title = 'This function is not supported in SVG for your browser.';
}
label{background:#cef;padding:5px;cursor:pointer}
.clickable{cursor:pointer}
With: 
<label><input type="radio" name="check" onclick="state=0" checked/>appendChild()</label>
<label><input type="radio" name="check" onclick="state=1"/>insertBefore()</label><br><br>
<label><input type="radio" name="check" onclick="state=2"/>insertAdjacentElement()</label>
<label><input type="radio" name="check" onclick="state=3"/>Try it with z-index</label>
<br>
<svg width="150" height="150" viewBox="0 0 150 150">
    <g stroke="none">
        <rect id="i1" class="clickable" x="10" y="10" width="50" height="50" fill="#80f"/>
        <rect id="i2" class="clickable" x="40" y="40" width="50" height="50" fill="#8f0"/>
        <rect id="i3" class="clickable" x="70" y="70" width="50" height="50" fill="#08f"/>
    </g>
</svg>

于 2019-01-28T18:27:12.600 回答
2

将 SVG 元素推到最后,使其 z-index 位于顶部。在 SVG 中,没有称为 z-index 的属性。尝试下面的 javascript 将元素置于顶部。

var Target = document.getElementById(event.currentTarget.id);
var svg = document.getElementById("SVGEditor");
svg.insertBefore(Target, svg.lastChild.nextSibling);

目标:是我们需要将其置于顶部的元素 svg:是元素的容器

于 2018-07-29T09:12:52.683 回答
1

这是有关 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-index 然后排序来支持 z-index,但它是一个庞大而复杂的库,如果您只是希望某个 SVG 出现在堆栈顶部,它可能不是最好的选择。

于 2022-01-24T21:13:38.857 回答
1

通过变换移动到前面:TranslateZ

警告:仅适用于 FireFox

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 160" style="width:160px; height:160px;">
    <g style="transform-style: preserve-3d;">
        <g id="one" style="transform-style: preserve-3d;">
            <circle fill="green" cx="100" cy="105" r="20" style="transform:TranslateZ(1px);"></circle>
        </g>
        <g id="two" style="transform-style: preserve-3d;">
            <circle fill="orange" cx="100" cy="95" r="20"></circle>
        </g>
    </g>
</svg>

于 2020-10-08T01:29:12.100 回答
0

很容易做到:

  1. 克隆你的物品
  2. 对克隆的项目进行排序
  3. 用克隆替换项目

function rebuildElementsOrder( selector, orderAttr, sortFnCallback ) {
	let $items = $(selector);
	let $cloned = $items.clone();
	
	$cloned.sort(sortFnCallback != null ? sortFnCallback : function(a,b) {
  		let i0 = a.getAttribute(orderAttr)?parseInt(a.getAttribute(orderAttr)):0,
  		    i1 = b.getAttribute(orderAttr)?parseInt(b.getAttribute(orderAttr)):0;
  		return i0 > i1?1:-1;
	});

        $items.each(function(i, e){
            e.replaceWith($cloned[i]);
	})
}

$('use[order]').click(function() {
    rebuildElementsOrder('use[order]', 'order');

    /* you can use z-index property for inline css declaration
    ** getComputedStyle always return "auto" in both Internal and External CSS decl [tested in chrome]
    
    rebuildElementsOrder( 'use[order]', null, function(a, b) {
        let i0 = a.style.zIndex?parseInt(a.style.zIndex):0,
  		    i1 = b.style.zIndex?parseInt(b.style.zIndex):0;
  		return i0 > i1?1:-1;
    });
    */
});
use[order] {
  cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="keybContainer" viewBox="0 0 150 150" xml:space="preserve">
<defs>
    <symbol id="sym-cr" preserveAspectRatio="xMidYMid meet" viewBox="0 0 60 60">
        <circle cx="30" cy="30" r="30" />
        <text x="30" y="30" text-anchor="middle" font-size="0.45em" fill="white">
            <tspan dy="0.2em">Click to reorder</tspan>
        </text>
    </symbol>
</defs>
    <use order="1" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sym-cr" x="0" y="0" width="60" height="60" style="fill: #ff9700; z-index: 1;"></use>
    <use order="4" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sym-cr" x="50" y="20" width="50" height="50" style="fill: #0D47A1; z-index: 4;"></use>
    <use order="5" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sym-cr" x="15" y="30" width="50" height="40" style="fill: #9E9E9E; z-index: 5;"></use>
    <use order="3" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sym-cr" x="25" y="30" width="80" height="80" style="fill: #D1E163; z-index: 3;"></use>
    <use order="2" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sym-cr" x="30" y="0" width="50" height="70" style="fill: #00BCD4; z-index: 2;"></use>
    <use order="0" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sym-cr" x="5" y="5" width="100" height="100" style="fill: #E91E63; z-index: 0;"></use>
</svg>

于 2019-04-05T00:54:11.520 回答
-1

我最终使用了一个更好的use示例。

<svg>
  <defs>
    <circle id="one" fill="green" cx="40" cy="40" r="20" /> 
    <circle id="two" fill="orange" cx="50" cy="40" r="20"/> 
  </defs>
  <use href="#two" />
  <use href="#one" />
</svg>

要控制顺序,您可以更改这些元素href的属性值。use这对动画很有用。

多亏了defs,圆形元素只被绘制一次。

jsfiddle.net/7msv2w5d

于 2021-11-01T07:17:48.200 回答