What causes a new stacking context to be formed when using position: relative without z-index?

After reading this informative piece:

When two elements share the same stack level, their layering is determined by their order in the source code. Elements stacked successively are placed on top of those that came before them.

And referencing this article:

A stacking context comes into existence anywhere within a document due to certain conditions being met, such as: ... 2. An element with either a "relative" or "absolute" position values coupled with a non-"auto" z-index value.

Now let's observe the following code snippet:

.c1 {
  position: relative;
  top: 50px;
}


.c2 {
   background: green;
   width: 200px;
   height: 200px;
 }
<div class="c1">
  Why am I visible?
</div> 

<div class="c2">&nbsp;</div>

Based on the aforementioned statements, it's expected that div.c1 does not establish a new stacking context because it lacks a specific z-index value. Therefore, both div.c1 and div.c2 belong to the <html> stacking context and should be rendered accordingly. So why does div.c2 appear below div.c1?

Answer №1

There's a common misconception that the CSS properties top, left, bottom, and right dictate the stacking order of elements, but in reality, it's not the case. By removing the top property and adding a negative value to margin-bottom, you can still achieve the desired layout.

.c1 {
  position: relative;
  margin-bottom: -50px;
}


.c2 {
   background: green;
   width: 200px;
   height: 200px;
 }
<div class="c1">
  Why am I still visible?
</div>

<div class="c2">&nbsp;</div>

Understanding the concepts of stack level and stacking contexts sheds light on why the relatively positioned element appears on top. The stack level is influenced by the z-index property, where elements with z-index: auto default to stack level 0. As per the spec, elements with lower stack levels are painted first within each stacking context. Check out this section for more details.

  1. the background and borders of the element forming the stacking context.
  2. the child stacking contexts with negative stack levels (most negative first).
  3. the in-flow, non-inline-level, non-positioned descendants. the non-positioned floats.
  4. the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks.
  5. the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.
  6. the child stacking contexts with positive stack levels (least positive first).

To illustrate this further, let's compare a relatively positioned element that creates a stacking context versus one that doesn't.

const blueBox = document.querySelector('#blue-box');
const button = document.querySelector('button');
const opacity1 = document.querySelector('#opacity-1');
const opacityNot1 = document.querySelector('#opacity-not-1');

let opacity = 1;

button.addEventListener('click', () => {
  if(opacity == 1){
    opacity = .9;
    opacity1.hidden = true;
    opacityNot1.hidden = false;
  }
  else {
    opacity = 1;
    opacity1.hidden = false;
    opacityNot1.hidden = true;
  }
  blueBox.style.opacity = opacity;
})
#blue-box {
  width: 100px;
  height: 100px;
  position: relative;
  background: blue;
}

#yellow-box {
  width: 50px;
  height: 50px;
  position: relative;
  top: 75px;
  z-index: 1;
  background: yellow;
}

#red-box {
  width: 100px;
  height: 100px;
  position: relative;
  background: red;
}
<div id="blue-box" style="opacity: 1">
  <div id="yellow-box"></div>
</div>

<div id="red-box"></div>

<button>Toggle opacity for blue box</button>
<p id="opacity-1">Blue box has <code>opacity: 1;</code> (so does NOT create a new stacking context)</p>
<p id="opacity-not-1" hidden>Blue box has <code>opacity: .9;</code> (so it creates a new stacking context)</p>

In this scenario, all three boxes are relatively positioned, but the yellow box stands out as it creates a stacking context with a higher stack level. Toggling the opacity of the blue box changes its behavior accordingly.

What happens when the blue box does not create a stacking context? The painting order follows the specified sequence, placing the yellow box above the blue and red boxes due to its elevated stack level.

Conversely, enabling the blue box to create a new stacking context shifts the dynamics. Now, the blue box and its associated stacking context are painted together, leading to the red box being displayed on top of the yellow box.


In summary, elements with position: relative do not inherently establish a new stacking context but rely on their positioning and stack level to determine display order relative to other elements.

Answer №2

When using the property position: relative, elements are first rendered in their normal flow before any offsets are applied. The offset is then calculated relative to the element's own position. In this specific scenario without the 10px offset provided to "c1", the correct order of rendering would be to display "c1" first and then place "c2" below it (not overlapping). Since both "c1" and "c2" are block elements, they should not overlap by default. However, due to the offset given to "c1", it was displaced 10px downwards causing it to overlap with "c2".

Answer №3

When you apply relative positioning to an element, it allows you to use the z-index property on that element. This is a feature that doesn't function well with statically positioned elements. Consequently, even if you do not specify a z-index value, this particular element will now be displayed on top of any other statically positioned element.

Moreover, if you declare position: relative; for an element without any other positioning attributes such as top, left, bottom, or right, it will have no impact on its positioning whatsoever. The element will remain in the same position as it would if its position was set to static. However, if you do add another positioning attribute like in your case, setting top: 50px;, the element will move 50 pixels downwards from its original position.

This explains why .c1 appears "stacked" above .c2.

Answer №4

In this scenario, c1 establishes the stacking context because it has position:relative applied to it. If you then apply position:absolute to c2, both divs will be at the same level and layered based on their source order.

.c1 {
  position:relative;
  background:blue;
  top: 50px;
}


.c2 {
  position:absolute;
   background: green;
   width: 100px;
   height: 100px;
 }
<div class="c1">
  Am I visible?
</div> 

<div class="c2">&nbsp;</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

When mousing over a subitem of the Image menu, ensure that the Image menu

Is there a way to prevent the image menu from reverting back to its original image when hovering over its subitems? I have 5 navigation menu items, but only one has a dropdown. Whenever I hover on the subitems of About Us, the image for About Us changes ba ...

The behavior of Datatables varies depending on the screen resolution

In my data table, there are numerous entries with child tables on each row of the main table. I am currently in the process of incorporating this type of functionality into my table, with a few modifications to create a table within the child row. You can ...

Having trouble updating the icon on my website using FontAwsome

Just a heads up - I'm not familiar with HTML/CSS/JS. This template is pre-made, and I'm simply making some adjustments to it. Hello, I'm currently working on my portfolio website and I want to display my projects based on the programming la ...

Using Cascading Style Sheets (CSS) to make posts appear above an image in a scrolling format

Can anyone guide me on how to show the text above an image contained within a scroll bar, similar to the picture below? Despite trying position property and searching online, I haven't found a solution yet. Your help would be greatly appreciated. ...

Subnav sticks when scrolling down but becomes unresponsive on resizing

My webpage has a main header that sticks to the top of the window and a subnav fixed at the bottom. The hero image adjusts its height based on the window minus the header and subnav heights. When scrolling past the subnav, it sticks just below the main nav ...

Is there a way to keep this table fixed in place as the user scrolls?

Is there an alternative way to fix the content on the header so that it remains visible on the screen until the next table, even when scrolling? I've tried using position: sticky and top: 0, but the header still scrolls past. I have checked for any ov ...

Issues with Hovering over Button Contained in Slider

I can't seem to figure this out. It should be a simple fix. I have 5 slider images with black buttons that link to different galleries. I want the button background color to change on hover, but it's only working on one of the sliders. It seems ...

How can I synchronize two webkit-animations at the same speed but with one covering a greater distance?

[Update: The solution involved creating two containers, with the second animation container configured to have left: 100%.] I designed a simple animation that moves a large gif image across the page horizontally, where the width of the gif is 1536px. Sin ...

What is the best way to incorporate Font Awesome icons into a UTF-16 encoded HTML document?

Trying to incorporate Font Awesome icons in UTF-16 encoded HTML pages can be a bit tricky. Following these steps should help you achieve the desired results: <head> <meta charset="UTF-8"> <link rel="stylesheet" href="https://use.fontawe ...

Is there a way to add a border around a div that extends beyond the div, similar to what

I'm attempting to create a border around this section, as seen in the image. However, I'm unsure of how to move it a few pixels outside of the main box. Here is what I've tried so far, but it's not quite achieving the desired result. H ...

Guide for changing the background color exclusively in the final row of a dynamically-generated HTML table with PHP

<table width="100%"> <tr> <? $count=0; $i=1; foreach($gallery as $key => $list1) { $count++; ?> <td> <img src='<?echo base ...

Is it possible to divide a column in an HTML table into two separate

I am currently working with an array of elements that I need to iterate over. For each element, I create a <td></td> tag. When dealing with 10 elements, it results in a table with one column and 10 rows. Is there a method, using either HTML o ...

Tips for adjusting the size of a textarea to perfectly fit within a table cell

I have a textarea displayed within an input in a table, but I am looking to resize it so that it completely fills the table cell up to the borders. Here is the logic: <textarea type="textarea" value="{{data.directRowNo}}" id = " ...

Having trouble with the postcss-import grunt plugin?

Here is the layout of my project: my_project |-- css | -- main.css |-- css-dev | -- main.css |-- node_modules | -- bootstrap | -- dist | -- css | -- bootstrap.css |-- package.json `-- Gruntfile.js The contents of my Gr ...

Can a JavaScript framework be created to ensure all browsers adhere to standards?

As someone who isn't an expert in JavaScript, I wonder if it's feasible to create a comprehensive embeddable JavaScript file that ensures all browsers adhere to standards. Could there be a compilation of known JavaScript hacks that compel each br ...

How to style CSS to ensure printed table content fits perfectly within the page

Does anyone know how to resize the contents of a table using CSS so that everything shows up when printing, without wrapping text in individual cells? In this scenario, <table class="datatables" id="table1"> <tr> <td style="white-space:nowr ...

Can you explain the guidelines for overlapping CSS media queries?

When it comes to spacing out media queries accurately to prevent overlap, how should we approach it? Let's examine the following code as an example: @media (max-width: 20em) { /* styles for narrow viewport */ } @media (min-width: 20em) and (max ...

Can someone explain why the min-width property is not being respected by the <input> element?

Visit this link for the code The text field in the provided link should only be 10px wide but it is currently displaying a width of 152px. Here is the code snippet: .input { width: 100%; box-sizing: border-box; } .cont { padding: 2px; } .main ...

The number of TH elements does not match the number of columns in the table

Is there a way to make only one th span the full width of the table, even with 5 columns below? I want to color the background of the th to cover the entire width. However, since the rest of the table contains 5 columns, the single th only stretches acros ...

How wide should the website layout be?

What is the perfect size for a standard portal website? I've seen many sites with widths ranging from 960px to 1000px. ...