Position is one of the fundamental property allowing to layout content. By default, HTML elements position and order follow the flow of how they are written in the document. However, CSS position allow to override this, move elements based on their original position, and even to move out of the flow elements, fix them in a specific position.

Static & Relative

static is the default — top/right/bottom/left do nothing. relative offsets an element from its natural position while keeping the original space reserved.

<div class="sr-demo">
    <div class="col">
        <div class="col-label">position: static (default)</div>
        <div class="box b-static">Box A</div>
        <div class="box b-flow">Box B</div>
        <p class="note">top/left have no effect</p>
    </div>
    <div class="col">
        <div class="col-label">position: relative</div>
        <div class="box b-relative">Box A</div>
        <div class="box b-flow">Box B</div>
        <p class="note">Box A: top:-12px; left:12px<br>Original space is kept</p>
    </div>
</div>
.sr-demo { 
    display: flex; 
    gap: 2rem; 
    flex-wrap: wrap; 
}
.col { 
    flex: 1; 
    min-width: 140px; 
}
.col-label { 
    font-size: .7rem; 
    font-weight: 600; 
    text-transform: uppercase; 
    letter-spacing: .05em; 
    color: #94a3b8; 
    margin-bottom: 1.5rem; 
}
.box { 
    width: 80px; 
    height: 40px; 
    border-radius: 6px; 
    display: flex; 
    align-items: center; 
    justify-content: center; 
    font-size: .75rem; 
    font-weight: 600; 
    color: white; 
    font-family: monospace; 
}
.b-static   { 
    background: #a5b4fc; 
    position: static; 
}
.b-flow     { 
    background: #e0e7ff; 
    color: #1e1b4b; 
}
.b-relative { 
    background: #6366f1; 
    position: relative; 
    top: -12px; 
    left: 12px; 
}
.b-placeholder { 
    background: #e0e7ff; 
    border: 2px dashed #a5b4fc; 
    color: #6366f1; 
}
.note { 
    font-size: .7rem; 
    color: #94a3b8; 
    margin-top: .5rem; 
}
/* static — default, no special positioning */
.box { position: static; }  /* top/right/bottom/left have no effect */
 
/* relative — shift from normal position, original space kept */
.box {
    position: relative;
    top:  -12px;   /* moves up */
    left:  12px;   /* moves right */
}
 
/* relative also creates a positioning context for absolute children */
.parent { position: relative; }

Absolute

Removed from normal flow, placed relative to its nearest non-static ancestor. If no such ancestor exists, it positions relative to the viewport.

<div class="abs-parent">
    <span class="parent-label">position: relative</span>
    <div class="abs-child c-tr">top:8 right:8</div>
    <div class="abs-child c-bl">bottom:8 left:8</div>
    <div class="abs-child c-center">centered</div>
</div>    
.abs-parent {
    position: relative;
    width: 100%; height: 200px;
    background: #f1f5f9;
    border: 2px dashed #cbd5e1;
    border-radius: 8px;
}
.parent-label { 
    padding: .5rem; 
    font-size: .7rem; 
    color: #94a3b8; 
    font-family: monospace; 
}
.abs-child {
    position: absolute;
    background: #6366f1; color: white;
    padding: .35rem .75rem; border-radius: 6px;
    font-size: .75rem; font-family: monospace;
}
 
.c-tr { top: 8px;  right: 8px;  }
.c-bl { bottom: 8px; left: 8px; }
.c-center {
    top: 50%; left: 50%;
    transform: translate(-50%, -50%);
}
.parent {
    position: relative; /* creates the positioning context */
    width: 400px;
    height: 200px;
}
 
.child {
    position: absolute;
    top:   0;
    right: 0;   /* top-right corner of parent */
}
 
/* centering trick with absolute + transform */
.centered {
    position: absolute;
    top:  50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

Fixed

Positioned relative to the viewport. Stays in place as you scroll — ideal for navbars, overlays, and floating buttons.

<div class="fixed-demo">
    <div class="fixed-mock">
        position: fixed navbar (simulated)
    </div>
    <div class="fixed-content">
        <p>Scroll content line 1 — navbar stays fixed</p>
        <p>Scroll content line 2 — navbar stays fixed</p>
        <p>Scroll content line 3 — navbar stays fixed</p>
        <p>Scroll content line 4 — navbar stays fixed</p>
        <p>Scroll content line 5 — navbar stays fixed</p>
        <p>Scroll content line 6 — navbar stays fixed</p>
        <p>Scroll content line 7 — navbar stays fixed</p>
        <p>Scroll content line 8 — navbar stays fixed</p>
        <p>Scroll content line 9 — navbar stays fixed</p>
        <p>Scroll content line 10 — navbar stays fixed</p>
        <p>Scroll content line 11 — navbar stays fixed</p>
        <p>Scroll content line 12 — navbar stays fixed</p>
        <p>Scroll content line 13 — navbar stays fixed</p>
        <p>Scroll content line 14 — navbar stays fixed</p>
        <p>Scroll content line 15 — navbar stays fixed</p>
        <p>Scroll content line 16 — navbar stays fixed</p>
    </div>
    <div class="fixed-fab">+</div>
</div>
.fixed-demo { 
    position: relative; height: 160px; 
    background: #f1f5f9; border-radius: 8px; 
    overflow: hidden; 
}
.fixed-mock {
    position: absolute;
    left: 0; right: 0; top: 0;
    background: #6366f1; color: white;
    padding: .5rem 1rem;
    font-size: .8rem; font-family: monospace;
    z-index: 10;
}
.fixed-content { 
    position: absolute; /* should be fixed */
    inset: 0;
    padding: 3rem 1rem 1rem; 
    font-size: .8rem; 
    color: #64748b; 
    overflow-y: auto; 
    box-sizing: border-box;
}
.fixed-fab {
    position: absolute; 
    bottom: 12px; right: 12px;
    width: 2.5rem; height: 2.5rem;
    background: #6366f1; color: white;
    border-radius: 50%; 
    display: flex; align-items: center; justify-content: center;
    font-size: 1.2rem; 
    box-shadow: 0 4px 12px rgba(99,102,241,.4);
}
.navbar {
    position: fixed;
    top:   0;
    left:  0;
    right: 0;       /* full width */
    z-index: 100;
}
 
.fab {
    position: fixed;
    bottom: 24px;
    right:  24px;
}
 
.overlay {
    position: fixed;
    inset: 0;       /* shorthand for top:0 right:0 bottom:0 left:0 */
    background: rgba(0, 0, 0, 0.5);
}

Sticky

Behaves like relative until it reaches the threshold you define — then sticks like fixed. Scroll inside the demo to see it in action.

<div class="scroll-area">
    <div class="sticky-header">
        Sticky header (position: sticky; top: 0)
    </div>
    <div class="item">Item 1 — scroll down</div>
    <div class="item">Item 2 — scroll down</div>
    <div class="item">Item 3 — scroll down</div>
    <div class="item">Item 4 — scroll down</div>
    <div class="item">Item 5 — scroll down</div>
    <div class="item">Item 6 — scroll down</div>
    <div class="item">Item 7 — scroll down</div>
    <div class="item">Item 8 — scroll down</div>
    <div class="item">Item 9 — scroll down</div>
    <div class="item">Item 10 — scroll down</div>
    <div class="item">Item 11 — scroll down</div>
    <div class="item">Item 12 — scroll down</div>
</div>
.scroll-area { 
    height: 240px; 
    overflow-y: auto; 
    border: 1px solid #e2e8f0; 
    border-radius: 8px; 
}
.sticky-header {
    position: sticky; 
    top: 0;
    z-index: 1;
    background: #6366f1; color: white;
    padding: .6rem 1rem; font-weight: 600;
}
.item { 
    padding: .75rem 1rem; 
    border-bottom: 1px solid #f1f5f9; 
}

Z-index & Stacking

z-index controls the stacking order. Higher numbers are on top. Each positioned element creates a stacking context — z-index is relative within it.

<div class="stack">
    <div class="layer l1">z-index: 1</div>
    <div class="layer l2">z-index: 2</div>
    <div class="layer l3">z-index: 3</div>
</div>
.stack { 
    position: relative; 
    width: 200px; height: 140px; 
}
.layer {
    position: absolute;
    width: 120px; height: 80px;
    border-radius: 8px;
    display: flex; align-items: center; justify-content: center;
    font-weight: 600; font-size: .875rem;
}
.l1 { 
    background: #bfdbfe; 
    top: 0; left: 0;   
    z-index: 1; 
}
.l2 { 
    background: #a5f3fc; 
    top: 60px; left: 60px; 
    z-index: 2; 
}
.l3 { 
    background: #bbf7d0; 
    top: 120px; left: 120px; 
    z-index: 3; 
}
/* z-index only works on positioned elements (not static) */
.tooltip { position: absolute; z-index: 500; }
.modal   { position: fixed;    z-index: 1000; }
.overlay { position: fixed;    z-index: 900; }
 
/* common z-index scale */
--z-base:     1;
--z-dropdown: 10;
--z-sticky:   20;
--z-overlay:  30;
--z-modal:    40;
--z-toast:    50;