Tailwind CSS 18 🎨 Positioning Mechanics (Static, Relative, Absolute, Fixed, Sticky, Inset)
CSS positioning determines where an element is placed in the document and how it responds to scrolling and to the other elements around it. Tailwind provides a utility for each of the five position values — static, relative, absolute, fixed, and sticky — plus the inset utilities that control the offsets for the positioned elements. Together they are the mechanism for overlays, dropdowns, toolbars, sidebars, badges, and any element that must be placed precisely relative to another element or to the viewport.
The five values are not interchangeable. static is the default and ignores the offsets. relative establishes a positioning context and offsets the element from its normal position without removing it from the flow. absolute removes the element from the flow and positions it relative to its nearest positioned ancestor. fixed removes the element from the flow and positions it relative to the viewport. sticky keeps the element in the flow until a scroll threshold is reached, then fixes it to the viewport for the duration of its container. Understanding which value to use for which situation is the whole of positioning.
This chapter covers the five position values, the inset utilities, the concept of a positioning context, the z-index interaction, the patterns for overlays, dropdowns, sticky headers, and the mistakes that produce elements in unexpected places.
Key point: relative establishes a positioning context without removing the element from the flow. absolute positions an element relative to its nearest positioned ancestor and removes it from the flow. fixed positions relative to the viewport. sticky scrolls with the page until a threshold, then fixes. The inset utilities (top-*, right-*, bottom-*, left-*, inset-*) only apply to positioned elements.
Why positioning matters
The overlay problem. A modal, a dropdown, a tooltip, or a popover must appear above the rest of the content. Positioning, combined with z-index, is the mechanism that places these elements above the flow.
The badge problem. A notification badge in the corner of an avatar must be placed precisely relative to the avatar. The avatar is relative, and the badge is absolute with an inset offset.
The sticky header problem. A table header or a navigation bar that stays visible while the content scrolls below it uses sticky. The element remains in the flow until it reaches the top of the viewport, then sticks.
The fixed toolbar problem. A toolbar or a floating action button that stays in the same place regardless of scrolling uses fixed. The element is positioned relative to the viewport and does not move.
The flow problem. static and relative keep the element in the normal flow. absolute and fixed remove it. sticky keeps the element in the flow but allows it to stick at a threshold. The choice determines whether the element affects the layout of its siblings.
a. The five position values
Each value has a specific role.
| Utility | CSS | In flow | Positioning context |
|---|---|---|---|
static | position: static | Yes | No |
relative | position: relative | Yes | Yes |
absolute | position: absolute | No | Yes |
fixed | position: fixed | No | Yes |
sticky | position: sticky | Yes | Yes |
<div class="static">Default flow</div>
<div class="relative">Offset from normal position</div>
<div class="absolute">Positioned against an ancestor</div>
<div class="fixed">Positioned against the viewport</div>
<div class="sticky top-0">Sticks at the top</div>
The static value ignores the inset utilities. Setting top-4 on a static element has no effect. The element must be positioned — relative, absolute, fixed, or sticky — for the offsets to apply.
The relative value is the most common way to establish a positioning context. A parent that should contain its absolute children is relative, and the children are positioned relative to the parent’s box.
The absolute value removes the element from the flow. The space it would have occupied is not reserved. The element is positioned relative to its nearest positioned ancestor, or to the initial containing block if there is none.
The fixed value removes the element from the flow and positions it relative to the viewport. It does not move when the page scrolls.
The sticky value keeps the element in the flow but allows it to stick at a threshold. The threshold is defined by one of the inset utilities, typically top-0. The element sticks for the duration of its parent container and then scrolls away with the parent.
b. The inset utilities
The inset utilities control the offsets for positioned elements.
| Utility | CSS |
|---|---|
top-0 | top: 0 |
right-0 | right: 0 |
bottom-0 | bottom: 0 |
left-0 | left: 0 |
inset-0 | inset: 0 |
inset-x-0 | left: 0; right: 0 |
inset-y-0 | top: 0; bottom: 0 |
top-4 | top: 1rem |
-top-2 | top: -0.5rem |
<div class="relative">
<div class="absolute top-0 right-0">Top right corner</div>
<div class="absolute inset-0 bg-black/50">Full overlay</div>
<div class="absolute -top-2 -right-2">Outside the corner</div>
</div>
The inset-0 utility sets all four offsets to zero, which makes the absolute element fill its positioned ancestor. This is the pattern for an overlay that covers a card or a modal backdrop.
The inset-x-0 and inset-y-0 utilities set the offsets on one axis. inset-x-0 stretches the element from the left edge to the right edge, which is used for a full-width bar inside a positioned container.
The negative offsets pull the element outside the bounds of its positioned ancestor. A badge that sits on the corner of an avatar uses -top-1 -right-1 to move half outside the avatar’s box.
c. The positioning context
An absolute element is positioned relative to its nearest positioned ancestor. If there is no positioned ancestor, it is positioned relative to the initial containing block, which is the viewport.
<!-- Badge relative to the avatar -->
<div class="relative inline-block">
<img class="w-12 h-12 rounded-full" src="avatar.jpg" alt="" />
<span class="absolute top-0 right-0 bg-red-500 text-white text-xs rounded-full px-1">
3
</span>
</div>
The avatar’s container is relative, which establishes the positioning context. The badge is absolute with top-0 right-0, which places it in the top right corner of the container. Without the relative on the container, the badge would be positioned relative to the viewport and would appear in the top right corner of the page.
The rule is: an absolute element is positioned relative to the nearest ancestor with a position other than static. The relative utility is the most common way to set that ancestor, because it does not change the element’s own position.
d. Fixed positioning
The fixed value positions an element relative to the viewport. The element does not scroll with the page.
<button class="fixed bottom-4 right-4 rounded-full bg-blue-500 text-white p-4 shadow-lg">
+
</button>
The floating action button is fixed with bottom-4 right-4, so it stays in the bottom right corner of the viewport regardless of scrolling. This is the standard pattern for a floating action button.
A fixed header that spans the full width:
<header class="fixed top-0 inset-x-0 h-16 bg-white shadow z-50">
Header
</header>
The inset-x-0 stretches the header from the left edge to the right edge. The top-0 places it at the top. The content below must have top padding to account for the fixed header, because the header is removed from the flow.
A fixed sidebar:
<aside class="fixed left-0 top-0 bottom-0 w-64 bg-gray-100">
Sidebar
</aside>
The left-0 top-0 bottom-0 stretches the sidebar from the top to the bottom of the viewport, and w-64 sets the width. The main content must have a left margin to avoid being covered by the sidebar.
e. Sticky positioning
The sticky value keeps the element in the flow until a scroll threshold is reached, then fixes it to the viewport for the duration of its container.
<header class="sticky top-0 bg-white shadow z-10">
Sticky header
</header>
The top-0 defines the threshold. When the element reaches the top of the viewport, it sticks. As long as the parent container is still in view, the element stays at the top. When the parent scrolls out, the element scrolls with it.
A sticky table header:
<div class="max-h-96 overflow-y-auto">
<table>
<thead class="sticky top-0 bg-white">
<tr>
<th>Name</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<!-- rows -->
</tbody>
</table>
</div>
The sticky top-0 on the thead makes the header stay at the top of the scroll container while the body scrolls.
Sticky requires two conditions: the element must have a threshold defined by an inset utility, and the parent container must be tall enough for the element to stick within it. If the parent is the same height as the element, there is nothing to stick against.
A common pitfall is a parent with overflow: hidden, which prevents the sticky element from sticking. The sticky element needs an ancestor that scrolls, and if that ancestor is the viewport, the sticky element’s parent must not have overflow: hidden.
f. Z-index and stacking
Positioned elements participate in a stacking context, and the z-index utilities control their order along the z-axis.
| Utility | CSS |
|---|---|
z-0 | z-index: 0 |
z-10 | z-index: 10 |
z-20 | z-index: 20 |
z-50 | z-index: 50 |
z-auto | z-index: auto |
<div class="relative z-10">Above</div>
<div class="relative z-20">Above that</div>
A higher z-index places the element above a lower one, but only within the same stacking context. A z-index on a child does not escape its parent’s stacking context. This is why a modal that is z-50 may still appear below a dropdown that is z-10 if the modal’s parent has a lower z-index than the dropdown’s parent.
A stacking context is created by several properties, including position combined with z-index, transform, opacity less than 1, and filter. Understanding which element creates a stacking context explains why z-index sometimes seems not to work.
The common pattern for overlays is z-50 for the overlay and z-40 for the content that must appear below it. Tailwind’s default scale runs from z-0 to z-50 in steps of 10, plus z-auto.
Complete Example Session
<!-- ============================================
PART 1: STATIC VS RELATIVE
============================================ -->
<div class="static">Default flow</div>
<div class="relative top-4 left-4">Offset from normal position</div>
<!-- ============================================
PART 2: ABSOLUTE WITHIN RELATIVE
============================================ -->
<div class="relative w-64 h-64 bg-gray-100">
<div class="absolute top-4 right-4 bg-blue-500 text-white p-2">
Top right
</div>
</div>
<!-- ============================================
PART 3: FULL OVERLAY WITH INSET-0
============================================ -->
<div class="relative w-64 h-64">
<img class="w-full h-full object-cover" src="image.jpg" alt="" />
<div class="absolute inset-0 bg-black/50"></div>
</div>
<!-- ============================================
PART 4: BADGE ON AVATAR
============================================ -->
<div class="relative inline-block">
<img class="w-12 h-12 rounded-full" src="avatar.jpg" alt="" />
<span class="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full w-5 h-5 flex items-center justify-center">
3
</span>
</div>
<!-- ============================================
PART 5: FIXED FLOATING BUTTON
============================================ -->
<button class="fixed bottom-4 right-4 rounded-full bg-blue-500 text-white p-4 shadow-lg">
+
</button>
<!-- ============================================
PART 6: FIXED HEADER
============================================ -->
<header class="fixed top-0 inset-x-0 h-16 bg-white shadow z-50">
Header
</header>
<main class="pt-16">
Content below the fixed header
</main>
<!-- ============================================
PART 7: STICKY HEADER
============================================ -->
<header class="sticky top-0 bg-white shadow z-10">
Sticky header
</header>
<!-- ============================================
PART 8: STICKY TABLE HEADER
============================================ -->
<div class="max-h-96 overflow-y-auto">
<table>
<thead class="sticky top-0 bg-white">
<tr><th>Name</th><th>Value</th></tr>
</thead>
<tbody>
<tr><td>Item</td><td>Value</td></tr>
</tbody>
</table>
</div>
<!-- ============================================
PART 9: Z-INDEX STACKING
============================================ -->
<div class="relative z-10">Above</div>
<div class="relative z-20">Above that</div>
<!-- ============================================
PART 10: MODAL BACKDROP
============================================ -->
<div class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center">
<div class="bg-white rounded-lg p-8 z-50">
Modal content
</div>
</div>
These ten parts cover static versus relative, absolute within relative, a full overlay with inset-0, a badge on an avatar, a fixed floating button, a fixed header, a sticky header, a sticky table header, z-index stacking, and a modal backdrop.
Quick Reference
Position Values
| Utility | CSS | In flow | Context |
|---|---|---|---|
static | position: static | Yes | No |
relative | position: relative | Yes | Yes |
absolute | position: absolute | No | Yes |
fixed | position: fixed | No | Yes |
sticky | position: sticky | Yes | Yes |
Inset Utilities
| Utility | CSS |
|---|---|
inset-0 | inset: 0 |
inset-x-0 | left: 0; right: 0 |
inset-y-0 | top: 0; bottom: 0 |
top-4 | top: 1rem |
right-4 | right: 1rem |
bottom-4 | bottom: 1rem |
left-4 | left: 1rem |
-top-2 | top: -0.5rem |
-right-2 | right: -0.5rem |
Z-Index
| Utility | CSS |
|---|---|
z-0 | z-index: 0 |
z-10 | z-index: 10 |
z-20 | z-index: 20 |
z-30 | z-index: 30 |
z-40 | z-index: 40 |
z-50 | z-index: 50 |
z-auto | z-index: auto |
Common Patterns
| Pattern | Classes |
|---|---|
| Overlay | relative + absolute inset-0 |
| Badge | relative + absolute -top-1 -right-1 |
| Fixed header | fixed top-0 inset-x-0 |
| Sticky header | sticky top-0 |
| Floating button | fixed bottom-4 right-4 |
| Modal | fixed inset-0 z-50 |
Positioning Context
| Rule | Detail |
|---|---|
| Absolute ancestor | Nearest non-static ancestor |
| No positioned ancestor | Initial containing block |
| Relative | Most common context |
| Fixed | Always the viewport |
| Sticky | Threshold via inset |
Best Practices
✅ Do This:
<!-- Relative parent for absolute children -->
<div class="relative">
<div class="absolute top-0 right-0">Badge</div>
</div>
<!-- inset-0 for full overlays -->
<div class="absolute inset-0 bg-black/50"></div>
<!-- sticky with a threshold -->
<header class="sticky top-0">
<!-- fixed with content offset -->
<header class="fixed top-0 inset-x-0"></header>
<main class="pt-16">
<!-- z-index for stacking -->
<div class="fixed inset-0 z-50">
❌ Don’t Do This:
<!-- Absolute without a positioned ancestor -->
<div class="absolute top-0"> <!-- ❌ positions against viewport -->
<!-- Inset on a static element -->
<div class="static top-4"> <!-- ❌ no effect -->
<!-- Sticky without a threshold -->
<div class="sticky"> <!-- ❌ does not stick -->
<!-- Sticky inside overflow-hidden -->
<div class="overflow-hidden">
<div class="sticky top-0"> <!-- ❌ does not stick -->
</div>
<!-- Forgetting the content offset for a fixed header -->
<header class="fixed top-0"></header>
<main> <!-- ❌ covered by header -->
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Absolute against viewport | No positioned ancestor | Add relative to the parent |
| Inset has no effect | Element is static | Add relative or absolute |
| Sticky does not stick | No threshold or overflow: hidden ancestor | Add top-0, remove overflow-hidden |
| Fixed header covers content | No top padding on the content | Add pt-16 to the content |
| Z-index ignored | Different stacking contexts | Check the ancestor’s stacking context |
| Badge inside the avatar | Missing negative offset | Use -top-1 -right-1 |
| Sticky stops early | Parent is too short | Make the parent taller |
Real-World Examples
1. Badge on Avatar
<div class="relative inline-block">
<img class="w-12 h-12 rounded-full" src="avatar.jpg" alt="" />
<span class="absolute -top-1 -right-1 bg-red-500 rounded-full w-5 h-5"></span>
</div>
2. Card Overlay
<div class="relative">
<img src="image.jpg" alt="" />
<div class="absolute inset-0 bg-black/50"></div>
</div>
3. Fixed Header
<header class="fixed top-0 inset-x-0 h-16 bg-white shadow z-50"></header>
4. Sticky Header
<header class="sticky top-0 bg-white shadow"></header>
5. Floating Button
<button class="fixed bottom-4 right-4 rounded-full bg-blue-500 p-4"></button>
6. Fixed Sidebar
<aside class="fixed left-0 top-0 bottom-0 w-64"></aside>
7. Modal
<div class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center">
<div class="bg-white rounded-lg p-8">Modal</div>
</div>
8. Dropdown
<div class="relative">
<button>Menu</button>
<div class="absolute top-full left-0 bg-white shadow">Dropdown</div>
</div>
9. Sticky Table Header
<thead class="sticky top-0 bg-white"></thead>
10. Full-Screen Overlay
<div class="fixed inset-0 bg-black/80 z-50"></div>
Visual
Positioning Context
┌──────────────────────────────────────────────────────────────┐
│ <div class="relative"> │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ <div class="absolute top-0 right-0"> │ │
│ │ ┌──────────────────────────────────────────────────┐ │ │
│ │ │ ┌────────┐ │ │ │
│ │ │ Parent (relative) │ Badge │ │ │ │
│ │ │ └────────┘ │ │ │
│ │ │ │ │ │
│ │ └──────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ The badge is positioned relative to the parent's box. │
└──────────────────────────────────────────────────────────────┘
Fixed vs Sticky
┌──────────────────────────────────────────────────────────────┐
│ FIXED: │
│ ┌──────────────────────┐ ← viewport │
│ │ Header (fixed) │ │
│ ├──────────────────────┤ │
│ │ Content scrolls │ │
│ │ Content scrolls │ │
│ │ Content scrolls │ │
│ └──────────────────────┘ │
│ Header stays at the top; content scrolls under it. │
│ │
│ STICKY: │
│ ┌──────────────────────┐ │
│ │ Before the header │ │
│ ├──────────────────────┤ ← header reaches top │
│ │ Header (sticky) │ │
│ ├──────────────────────┤ │
│ │ Content scrolls │ │
│ └──────────────────────┘ │
│ Header scrolls until it reaches the top, then sticks. │
└──────────────────────────────────────────────────────────────┘
Inset Offsets
┌──────────────────────────────────────────────────────────────┐
│ inset-0: fills the parent │
│ ┌────────────────────────────────────────────────────────┐ │
│ │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │
│ │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ top-0 right-0: top right corner │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ ┌──────────┐ │ │
│ │ │ Element │ │ │
│ │ └──────────┘ │ │
│ │ │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ -top-1 -right-1: outside the corner │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ ┌──────────┐ │ │
│ │ │ Element │ │ │
│ └──────────────────────────────────────────└──────────┘──┘ │
└──────────────────────────────────────────────────────────────┘
Z-Index and Stacking Contexts
┌──────────────────────────────────────────────────────────────┐
│ z-50 │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Modal │ │
│ └────────────────────────────────────────────────────────┘ │
│ z-40 │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Overlay │ │
│ └────────────────────────────────────────────────────────┘ │
│ z-10 │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Sticky header │ │
│ └────────────────────────────────────────────────────────┘ │
│ z-0 │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Page content │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ Higher z-index appears above lower within the same stack. │
└──────────────────────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
static | Default; ignores offsets |
relative | In flow; establishes positioning context |
absolute | Out of flow; positioned against nearest ancestor |
fixed | Out of flow; positioned against viewport |
sticky | In flow; sticks at a threshold |
| Inset | top-*, right-*, bottom-*, left-*, inset-* |
inset-0 | Fills the positioned parent |
| Negative offsets | Pull outside the parent |
| Z-index | z-10, z-20, z-50 |
| Common pattern | relative parent + absolute child |
Key takeaways:
- The five position values each have a role.
staticis the default.relativeestablishes a context without leaving the flow.absoluteleaves the flow and positions against the nearest positioned ancestor.fixedpositions against the viewport.stickystays in the flow and sticks at a threshold. relativeis the most common way to establish a positioning context. Anabsolutechild is positioned relative to the nearest ancestor with a position other thanstatic. Without a positioned ancestor, the child positions against the viewport.- The inset utilities only apply to positioned elements.
top-4on astaticelement has no effect. The element must berelative,absolute,fixed, orsticky. inset-0fills the positioned parent. It sets all four offsets to zero, which is the pattern for overlays and backdrops.- Negative offsets pull the element outside its parent.
-top-1 -right-1places a badge half outside the corner of the avatar. fixedremoves the element from the flow and pins it to the viewport. The content below needs padding to account for the space the fixed element would have occupied.stickyrequires a threshold and a scrolling ancestor.top-0defines the threshold. The parent must not haveoverflow: hidden, and the parent must be taller than the sticky element for the sticking to be visible.- Z-index controls the stacking order within a context. A higher value appears above a lower one, but only within the same stacking context. Understanding which ancestor creates the context explains why z-index sometimes seems not to work.
Remember: Positioning is the mechanism that takes an element out of the normal flow and places it precisely. The five values each have a specific role, and the choice determines whether the element affects its siblings and what it is positioned against. relative establishes the context that absolute children use. fixed pins to the viewport. sticky sticks at a threshold. The inset utilities control the offsets, and the z-index controls the stacking. The patterns — overlays, badges, sticky headers, fixed toolbars, and modals — are all built from these primitives. Understanding positioning is understanding how elements are placed on the page when the normal flow is not enough.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!