Does Z-Index Specify the Stack Level of a Non-Positioned Flex Item

flex items and negative z-index numbers

An element can be placed directly behind its parent div, even if the parent is a flex-item. Albeit we have to take care of three players:

  1. The flex container: Must have a position (not static, of course) and a z-index.

  2. The flex item: Should have a position, but MUST NOT have a z-index.

  3. The child behind: Must have a position and z-index:-1

Try it in this JSFiddle

We can even finetune the appearance of the child behind:

  1. Child shall appear directly behind the flex item, but above the flex container: Apply any z-index to the flex container, but none to the flex item.
  2. Child shall appear behind the flex group (behind the flex item and behind the flex container): Do not apply z-index to flex container nor flex item.

Update: As turned out in the discussion (see question comments, if interested), this behaviour and solution is not limited to flex. Nevertheless, it will occur especially there as flexbox is a 2-tier structure itself (flex container > flex item > child behind).

Flexbox, z-index & position: static: Why isn't it working?

Like you wrote in your question, elements do not need to be positioned for z-index to work in a flex container.

Flex items can participate in a z-index stacking order even with position: static, which is not true for other CSS box models (except Grid) where z-index only works on positioned elements.

4.3. Flex Item Z-Ordering

Flex items paint exactly the same as inline blocks, except
that order-modified document order is used in place of raw document
order, and z-index values other than auto create a stacking context
even if position is static.

The reason z-index isn't working in your code is that div.header and div.core are not flex items. They are children of body, but body is not a flex container.

In order for z-index to work here, you'll need to apply display: flex to body.

Add this to your code:

body {
display: flex;
flex-direction: column;
}

Revised Demo

More details: https://stackoverflow.com/a/35772825/3597276

Why does position:relative; appear to change the z-index?

You need to refer to the specification and more precisely the painting order to understand when each layer is painted.

Without position:relative your element is not positioned and will be painted at the step (4):


  1. For all its in-flow, non-positioned, block-level descendants in tree
    order: If the element is a block, list-item, or other block
    equivalent:

Then we paint the positioned elements (including the .mask) at the step (8)


  1. All positioned, opacity or transform descendants, in tree order that fall into the following categories

Now when you add position:relative you make the container also positioned thus it will fall in the step (8) too and as described there we consider the tree order since both don't have any z-index specified. So the .container will painted later in this case.

If you change the order of the element (you make the container before the mask) you will notice that position:relative won't have any effect because in both cases the painting order will be the same:

body {
margin: 0;
font-family: arial;
}
section {
position: relative;
background: url(https://preview.webpixels.io/boomerang-v3.6.1/assets/images/backgrounds/slider/img-41.jpg)
no-repeat left center/cover;
height: 70vh;
display: flex;
justify-content: center;
}
.container {
position: relative; /* you can remove this*/
width: 100%;
max-width: 1280px;
display: flex;
justify-content: center;
align-items: center;
color: white;
}
.mask {
position: absolute;
width: 100%;
height: 100%;
background: #3452ff;
opacity: 0.7;
}
<section>
<div class="container">
<h1>Hello World</h1>
</div>
<div class="mask"></div>
</section>

Why does z-index not work?

The z-index property only works on elements with a position value other than static (e.g. position: absolute;, position: relative;, or position: fixed).

There is also position: sticky; that is supported in Firefox, is prefixed in Safari, worked for a time in older versions of Chrome under a custom flag, and is under consideration by Microsoft to add to their Edge browser.

Why does z-index not work with display: flex; and a negative margin?

You need to use position: relative to make z-index behave like you want it to.

.small-text {  margin-bottom: -20px;  position: relative;  z-index: 1;}
.small-text span { background-color: orange;}
.big-container { display: flex; align-items: center; background-color: purple;}
.big-text { display: flex; flex-direction: column; align-items: center;}
.big-text span { margin-top: 50px; background-color: lime;}
<div class="small-text">  <span>I want to select/highlight this.</span></div><div class="big-container">  <div class="big-text">    <span>But this element's margin is covering it up.</span>  </div></div>

element with higher z-index value not overlaying another

z-index works on positioned elements, but with CSS3 elements which are flex items or grid items can use z-index when elements are static

From MDN

The z-index property specifies the z-order of an element and its
descendants. When elements overlap, z-order determines which one
covers the other. An element with a larger z-index generally covers an
element with a lower one.

For a positioned box, the z-index property specifies:

  • The stack level of the box in the current stacking context.

  • Whether the box establishes a local stacking context.


Applies to positioned elements

Set position:relative to parent header and position:absolute to #mtitle and change z-index value

body {  margin: 0}header {  position: relative}#mtitle {  display: inline-block;  background-color: #000000;  position: absolute;  margin:0;  z-index: 0;  color: #fff}#tsub {  display: inline-block;  left: 0;  position: absolute;  font-size: 85px;  z-index: -1;  background: red}
<header>  <h1 id="mtitle">Tepid Beans</h1>  <div id="tsub">- Games</div></header>


Related Topics



Leave a reply



Submit