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

IT技术 javascript jquery svg z-index
2021-01-20 20:00:09

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

这是演示。

6个回答

规格

在 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 “使用” 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 Specification是下一个主要版本,仍然支持上述功能。

3.4. 渲染顺序

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

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

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

...

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

@Michael:在您的场景中,首先我会尝试了解是否真的需要对元素进行分组。
2021-03-21 20:00:09
对于在 2021 年或之后发现这个答案的人来说,SVG 2 版本xlink:href已被弃用,而支持href.
2021-03-27 20:00:09
'use xlink:href' 很酷很奇怪,非常适合我的需要!!
2021-03-30 20:00:09
oop!按照您希望绘制的顺序绘制元素并不总是那么容易,特别是如果对象以编程方式生成并且可能出现嵌套(例如,看起来g不能包含 a、b,这样 a 低于 g 兄弟c 但 b 在它之上)
2021-03-31 20:00:09
还有一个关于覆盖渲染顺序的旧草案,但它是一个不可用的功能。草稿参考
2021-04-08 20:00:09

正如这里的其他人所说,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-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]
    }
    
  3. 然后,使用 D3 将您的 z 索引绑定到该选择。

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

    circles.sort(setOrder);
    

例子

在此处输入图片说明

  • 可以按ID堆叠

在此处输入图片说明

  • 最左边的SVG在顶部

在此处输入图片说明

  • 顶部的最小半径

在此处输入图片说明

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

绝对是这里最好的答案...... 10/10。为什么现在可以接受?
2021-03-29 20:00:09
@Tigerrrrrr 导入外部库来做一些像控制堆叠顺序一样简单的事情是疯狂的。更糟糕的是,D3 是一个特别大的库。
2021-04-02 20:00:09
@iMe,说得好。虽然这是一个问题解决方案,但值得在这里;它不是,也绝不应该是,答案。唯一应该取代当前答案的是,如果出现更新的规范并且浏览器发生变化。任何想要使用此答案的人,不要导入所有 D3,只需导入您需要的module。不要为了这个而导入所有的 D3。
2021-04-07 20:00:09

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

Update

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

任何 SVG 规范中都没有 z-index 属性。定义哪些元素出现在顶部,哪些出现在底部的唯一方法是使用 DOM 排序
2021-03-19 20:00:09
行。你想要#one 在#two 上还是相反?
2021-03-23 20:00:09
d3.selection.prototype.moveToFront = function() { return this.each(function() { this.parentNode.appendChild(this); }); };然后你可以selection.moveToFront()通过stackoverflow.com/questions/14167863/...
2021-03-27 20:00:09
谢谢,但我需要基于 z-index 值的元素。
2021-04-05 20:00:09
是的,如果我说 #one 的 z-index 值为 -1 意味着它将显示在顶层。
2021-04-09 20:00:09

您可以使用使用

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

绿色圆圈出现在顶部。
js小提琴

这会绘制#one 两次吗?
2021-03-13 20:00:09
+1 因为它不需要 javascript 而 -1 因为你也可以<g>在加载之前更改 DOM 时更改其本身的顺序
2021-03-23 20:00:09
@mareoraft 是的,#one绘制了两次。但是如果你愿意,你可以通过 CSS 隐藏第一个实例。use与克隆引用的 DOM 元素具有相同的效果
2021-03-24 20:00:09
对于在 2021 年或之后发现这个答案的人来说,SVG 2 版本xlink:href已被弃用,而支持href.
2021-03-30 20:00:09

如前所述,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,则需要将该项目从其 parentNode 中取出。

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

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

@gavin SVG 元素按从上到下的顺序绘制。为了把一个元素放在最上面,我们 append() 它使它成为最后一个元素。相反,如果我们想要一个元素发送到底部,我们可以通过 prepend() 将它作为第一个元素。函数BringToBottomofSVG(targetElement){ let parent = targetElement.ownerSVGElement; parent.prepend(targetElement); }
2021-03-12 20:00:09
这仅在组没有转换属性时才是正确的:“.. 每个元素都包含它的位置,无论它嵌套在哪个组中”
2021-03-19 20:00:09
嗨,这对我有用,但是“降到最低”的等价物是什么?谢谢
2021-03-26 20:00:09