[javascript] How to use z-index in svg elements?

I'm using the svg circles in my project like this,

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

And I'm using the z-index in the g tag to show the elements the first. In my project I need to use only z-index value, but I can't use the z-index to my svg elements. I have googled a lot but I didn't find anything relatively. So please help me to use z-index in my svg.

Here is the DEMO.

This question is related to javascript jquery svg z-index

The answer is


Move to front by transform:TranslateZ

Warning: Only works in FireFox

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


We have already 2019 and z-index is still not supported in SVG.

You can see on the site SVG2 support in Mozilla that the state for z-indexNot implemented.

You can also see on the site Bug 360148 "Support the 'z-index' property on SVG elements" (Reported: 12 years ago).

But you have 3 possibilities in SVG to set it:

  1. With element.appendChild(aChild);
  2. With parentNode.insertBefore(newNode, referenceNode);
  3. With targetElement.insertAdjacentElement(positionStr, newElement); (No support in IE for SVG)

Interactive demo example

With all this 3 functions.

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


The clean, fast, and easy solutions posted as of the date of this answer are unsatisfactory. They are constructed over the flawed statement that SVG documents lack z order. Libraries are not necessary either. One line of code can perform most operations to manipulate the z order of objects or groups of objects that might be required in the development of an app that moves 2D objects around in an x-y-z space.

Z Order Definitely Exists in SVG Document Fragments

What is called an SVG document fragment is a tree of elements derived from the base node type SVGElement. The root node of an SVG document fragment is an SVGSVGElement, which corresponds to an HTML5 <svg> tag. The SVGGElement corresponds to the <g> tag and permits aggregating children.

Having a z-index attribute on the SVGElement as in CSS would defeat the SVG rendering model. Sections 3.3 and 3.4 of W3C SVG Recommendation v1.1 2nd Edition state that SVG document fragments (trees of offspring from an SVGSVGElement) are rendered using what is called a depth first search of the tree. That scheme is a z order in every sense of the term.

Z order is actually a computer vision shortcut to avoid the need for true 3D rendering with the complexities and computing demands of ray tracing. The linear equation for the implicit z-index of elements in an SVG document fragment.

z-index = z-index_of_svg_tag + depth_first_tree_index / tree_node_qty

This is important because if you want to move a circle that was below a square to above it, you simply insert the square before the circle. This can be done easily in JavaScript.

Supporting Methods

SVGElement instances have two methods that support simple and easy z order manipulation.

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

The Correct Answer That Doesn't Create a Mess

Because the SVGGElement (<g> tag) can be removed and inserted just as easily as a SVGCircleElement or any other shape, image layers typical of Adobe products and other graphics tools can be implemented with ease using the SVGGElement. This JavaScript is essentially a Move Below command.

parent.insertBefore(parent.removeChild(gRobot), gDoorway)

If the layer of a robot drawn as children of SVGGElement gRobot was before the doorway drawn as children of SVGGElement gDoorway, the robot is now behind the doorway because the z order of the doorway is now one plus the z order of the robot.

A Move Above command is almost as easy.

parent.insertBefore(parent.removeChild(gRobot), gDoorway.nextSibling())

Just think a=a and b=b to remember this.

insert after = move above
insert before = move below

Leaving the DOM in a State Consistent With the View

The reason this answer is correct is because it is minimal and complete and, like the internals of Adobe products or other well designed graphics editors, leaves the internal representation in a state that is consistent with the view created by rendering.

Alternative But Limited Approach

Another approach commonly used is to use CSS z-index in conjunction with multiple SVG document fragments (SVG tags) with mostly transparent backgrounds in all but the bottom one. Again, this defeats the elegance of the SVG rendering model, making it difficult to move objects up or down in the z order.


NOTES:

  1. (https://www.w3.org/TR/SVG/render.html v 1.1, 2nd Edition, 16 August 2011)

    3.3 Rendering Order Elements in an SVG document fragment have an implicit drawing order, with the first elements in the SVG document fragment getting "painted" first. Subsequent elements are painted on top of previously painted elements.

    3.4 How groups are rendered Grouping elements such as the ‘g’ element (see container elements) have the effect of producing a temporary separate canvas initialized to transparent black onto which child elements are painted. Upon the completion of the group, any filter effects specified for the group are applied to create a modified temporary canvas. The modified temporary canvas is composited into the background, taking into account any group-level masking and opacity settings on the group.


its easy to do it:

  1. clone your items
  2. sort cloned items
  3. replace items by cloned

_x000D_
_x000D_
function rebuildElementsOrder( selector, orderAttr, sortFnCallback ) {_x000D_
 let $items = $(selector);_x000D_
 let $cloned = $items.clone();_x000D_
 _x000D_
 $cloned.sort(sortFnCallback != null ? sortFnCallback : function(a,b) {_x000D_
    let i0 = a.getAttribute(orderAttr)?parseInt(a.getAttribute(orderAttr)):0,_x000D_
        i1 = b.getAttribute(orderAttr)?parseInt(b.getAttribute(orderAttr)):0;_x000D_
    return i0 > i1?1:-1;_x000D_
 });_x000D_
_x000D_
        $items.each(function(i, e){_x000D_
            e.replaceWith($cloned[i]);_x000D_
 })_x000D_
}_x000D_
_x000D_
$('use[order]').click(function() {_x000D_
    rebuildElementsOrder('use[order]', 'order');_x000D_
_x000D_
    /* you can use z-index property for inline css declaration_x000D_
    ** getComputedStyle always return "auto" in both Internal and External CSS decl [tested in chrome]_x000D_
    _x000D_
    rebuildElementsOrder( 'use[order]', null, function(a, b) {_x000D_
        let i0 = a.style.zIndex?parseInt(a.style.zIndex):0,_x000D_
        i1 = b.style.zIndex?parseInt(b.style.zIndex):0;_x000D_
    return i0 > i1?1:-1;_x000D_
    });_x000D_
    */_x000D_
});
_x000D_
use[order] {_x000D_
  cursor: pointer;_x000D_
}
_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>_x000D_
<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">_x000D_
<defs>_x000D_
    <symbol id="sym-cr" preserveAspectRatio="xMidYMid meet" viewBox="0 0 60 60">_x000D_
        <circle cx="30" cy="30" r="30" />_x000D_
        <text x="30" y="30" text-anchor="middle" font-size="0.45em" fill="white">_x000D_
            <tspan dy="0.2em">Click to reorder</tspan>_x000D_
        </text>_x000D_
    </symbol>_x000D_
</defs>_x000D_
    <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>_x000D_
    <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>_x000D_
    <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>_x000D_
    <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>_x000D_
    <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>_x000D_
    <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>_x000D_
</svg>
_x000D_
_x000D_
_x000D_


You can use use.

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

The green circle appears on top.
jsFiddle


There is no z-index for svgs. But svg determines which of your elements are the uppermost by theire position in the DOM. Thus you can remove the Object and place it to the end of the svg making it the "last rendered" element. That one is then rendered "topmost" visually.


Using jQuery:

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

usage:

moveUp($('#myTopElement'));

Using D3.js:

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

usage:

myTopElement.moveUp();


Push SVG element to last, so that its z-index will be in top. In SVG, there s no property called z-index. try below javascript to bring the element to top.

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

Target: Is an element for which we need to bring it to top svg: Is the container of elements


Another solution would be to use divs, which do use zIndex to contain the SVG elements.As here: https://stackoverflow.com/a/28904640/4552494


As others here have said, z-index is defined by the order the element appears in the DOM. If manually reordering your html isn't an option or would be difficult, you can use D3 to reorder SVG groups/objects.

Use D3 to Update DOM Order and Mimic Z-Index Functionality

Updating SVG Element Z-Index With D3

At the most basic level (and if you aren't using IDs for anything else), you can use element IDs as a stand-in for z-index and reorder with those. Beyond that you can pretty much let your imagination run wild.

Examples in code snippet

_x000D_
_x000D_
var circles = d3.selectAll('circle')_x000D_
var label = d3.select('svg').append('text')_x000D_
    .attr('transform', 'translate(' + [5,100] + ')')_x000D_
_x000D_
var zOrders = {_x000D_
    IDs: circles[0].map(function(cv){ return cv.id; }),_x000D_
    xPos: circles[0].map(function(cv){ return cv.cx.baseVal.value; }),_x000D_
    yPos: circles[0].map(function(cv){ return cv.cy.baseVal.value; }),_x000D_
    radii: circles[0].map(function(cv){ return cv.r.baseVal.value; }),_x000D_
    customOrder: [3, 4, 1, 2, 5]_x000D_
}_x000D_
_x000D_
var setOrderBy = 'IDs';_x000D_
var setOrder = d3.descending;_x000D_
_x000D_
label.text(setOrderBy);_x000D_
circles.data(zOrders[setOrderBy])_x000D_
circles.sort(setOrder);
_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>_x000D_
_x000D_
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 100"> _x000D_
  <circle id="1" fill="green" cx="50" cy="40" r="20"/> _x000D_
  <circle id="2" fill="orange" cx="60" cy="50" r="18"/>_x000D_
  <circle id="3" fill="red" cx="40" cy="55" r="10"/> _x000D_
  <circle id="4" fill="blue" cx="70" cy="20" r="30"/> _x000D_
  <circle id="5" fill="pink" cx="35" cy="20" r="15"/> _x000D_
</svg>
_x000D_
_x000D_
_x000D_

The basic idea is:

  1. Use D3 to select the SVG DOM elements.

    var circles = d3.selectAll('circle')
    
  2. Create some array of z-indices with a 1:1 relationship with your SVG elements (that you want to reorder). Z-index arrays used in the examples below are IDs, x & y position, radii, etc....

    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. Then, use D3 to bind your z-indices to that selection.

    circles.data(zOrders[setOrderBy]);
    
  4. Lastly, call D3.sort to reorder the elements in the DOM based on the data.

    circles.sort(setOrder);
    

Examples

enter image description here

  • You can stack by ID

enter image description here

  • With leftmost SVG on top

enter image description here

  • Smallest radii on top

enter image description here

  • Or Specify an array to apply z-index for a specific ordering -- in my example code the array [3,4,1,2,5] moves/reorders the 3rd circle (in the original HTML order) to be 1st in the DOM, 4th to be 2nd, 1st to be 3rd, and so on...


Using D3:

If you want to re-inserts each selected element, in order, as the last child of its parent.

selection.raise()

Try to invert #one and #two. Have a look to this fiddle : http://jsfiddle.net/hu2pk/3/

Update

In SVG, z-index is defined by the order the element appears in the document. You can have a look to this page too if you want : https://stackoverflow.com/a/482147/1932751


As discussed, svgs render in order and don't take z-index into account (for now). Maybe just send the specific element to the bottom of its parent so that it'll render last.

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"));

Worked for me.

Update

If you have a nested SVG, containing groups, you'll need to bring the item out of its parentNode.

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

A nice feature of SVG's is that each element contains it's location regardless of what group it's nested in :+1:


Using D3:

If you want to add the element in the reverse order to the data use:

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

Instead of .append

Adding an element to top of a group element


Specification

In the SVG specification version 1.1 the rendering order is based on the document order:

first element -> "painted" first

Reference to the SVG 1.1. Specification

3.3 Rendering Order

Elements in an SVG document fragment have an implicit drawing order, with the first elements in the SVG document fragment getting "painted" first. Subsequent elements are painted on top of previously painted elements.


Solution (cleaner-faster)

You should put the green circle as the latest object to be drawn. So swap the two elements.

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

Here the fork of your jsFiddle.

Solution (alternative)

The tag use with the attribute xlink:href and as value the id of the element. Keep in mind that might not be the best solution even if the result seems fine. Having a bit of time, here the link of the specification SVG 1.1 "use" Element.

Purpose:

To avoid requiring authors to modify the referenced document to add an ID to the root element.

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


Notes on SVG 2

SVG 2 Specification is the next major release and still supports the above features.

3.4. Rendering order

Elements in SVG are positioned in three dimensions. In addition to their position on the x and y axis of the SVG viewport, SVG elements are also positioned on the z axis. The position on the z-axis defines the order that they are painted.

Along the z axis, elements are grouped into stacking contexts.

3.4.1. Establishing a stacking context in SVG

...

Stacking contexts are conceptual tools used to describe the order in which elements must be painted one on top of the other when the document is rendered, ...


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to jquery

How to make a variable accessible outside a function? Jquery assiging class to th in a table Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Getting all files in directory with ajax Bootstrap 4 multiselect dropdown Cross-Origin Read Blocking (CORB) bootstrap 4 file input doesn't show the file name Jquery AJAX: No 'Access-Control-Allow-Origin' header is present on the requested resource how to remove json object key and value.?

Examples related to svg

How to extract svg as file from web page How to display svg icons(.svg files) in UI using React Component? Why don’t my SVG images scale using the CSS "width" property? How to show SVG file on React Native? Easiest way to use SVG in Android? IE11 meta element Breaks SVG img src SVG changing the styles with CSS How to use SVG markers in Google Maps API v3 Embedding SVG into ReactJS How to change the color of an svg element?

Examples related to z-index

Bootstrap Modal sitting behind backdrop How to make a Div appear on top of everything else on the screen? Floating Div Over An Image How to use z-index in svg elements? How to make child element higher z-index than parent? Bring element to front using CSS z-index issue with twitter bootstrap dropdown menu How to "z-index" to make a menu always on top of the content Why does z-index not work? Can't change z-index with JQuery