CSS Stacking Order

CSS Stacking Order (Without z-index)

When elements on a webpage overlap, the browser needs to decide which element appears on top. If the z-index property is not specified on any element, the browser follows a strict set of rules to determine the stacking context.

Elements are stacked in the following order (from bottom to top):

  1. The Root Element: The background and borders of the root element (usually <html>).
  2. Non-Positioned Elements: Descendant elements that are not positioned (i.e., they have position: static), rendered in the exact order they appear in the HTML code.
  3. Positioned Elements: Descendant elements that are positioned (i.e., relative, absolute, fixed, or sticky), also rendered in the order they appear in the HTML code.

Important Note: When the CSS order property alters the rendering of items within flex containers, it similarly affects the order for their stacking context.


Example: Stacking Without z-index

In the example below, DIV #1 through DIV #4 are positioned elements. DIV #5 is static (non-positioned).

Because positioned elements are always painted after (and therefore on top of) non-positioned elements, DIV #5 is drawn completely below the other four elements, even though it is the very last element written in the HTML markup!

Default Stacking Context Example:

<!DOCTYPE html>
<html>
<head>
    <style>
        .stacking-container {
            position: relative; /* Acts as a container for absolute items */
            height: 400px;
            border: 2px solid navy;
            background-color: #f4f4f9;
        }
        .stacking-container strong {
            font-family: sans-serif;
        }
        .stacking-container div {
            padding: 10px;
            border: 2px dashed;
            text-align: center;
        }
        .static {
            position: static;
            height: 80px;
            background-color: #ffffcc;
            border-color: #999966;
        }
        .absolute {
            position: absolute;
            width: 150px;
            height: 350px;
            background-color: #ffdddd;
            border-color: #990000;
            opacity: 0.8; /* Makes overlapping visible */
        }
        .relative {
            position: relative;
            height: 80px;
            background-color: #ccffcc;
            border-color: #669966;
            opacity: 0.8;
        }
        #abs1 { top: 10px; left: 10px; }
        #rel1 { top: 30px; margin: 0px 50px; }
        #rel2 { top: 15px; left: 20px; margin: 0px 50px; }
        #abs2 { top: 10px; right: 10px; }
        #sta1 { margin: 0px 50px; }
    </style>
</head>
<body>
    <div class="stacking-container">
        <div id="abs1" class="absolute">
            <strong>DIV #1</strong><br />position: absolute;
        </div>
        <div id="rel1" class="relative">
            <strong>DIV #2</strong><br />position: relative;
        </div>
        <div id="rel2" class="relative">
            <strong>DIV #3</strong><br />position: relative;
        </div>
        <div id="abs2" class="absolute">
            <strong>DIV #4</strong><br />position: absolute;
        </div>
        <!-- Even though DIV #5 is last in the HTML, it renders at the bottom! -->
        <div id="sta1" class="static">
            <strong>DIV #5</strong><br />position: static;
        </div>
    </div>
</body>
</html>

Summary

Understanding the default stacking context is crucial before you start applying manual z-index values. If two elements overlap and neither has a z-index:


Exercise

?

If an unpositioned (static) element is written AFTER an absolutely positioned element in the HTML code, which one will appear on top visually?