CSS 15 💻 position property
The position property is one of the most powerful tools in CSS for controlling the layout and placement of elements. It determines how an element is positioned in the document flow and how it responds to the top, right, bottom, and left properties.
Overview of position Values
| Value | Description |
|---|---|
static | Default — element stays in its normal flow |
relative | Positioned relative to its normal position |
absolute | Removed from flow — positioned relative to nearest positioned ancestor |
fixed | Removed from flow — positioned relative to the viewport |
sticky | Hybrid — relative until a threshold, then fixed |
1. position: static
The default value. Elements remain in their normal document flow. The top, right, bottom, left, and z-index properties have no effect.
.static {
position: static; /* Default */
margin: 10px;
padding: 20px;
border: 1px solid #ddd;
}
2. position: relative
The element is positioned relative to its normal position. The top, right, bottom, and left properties offset it from where it would normally be.
.relative {
position: relative;
top: 20px; /* Moves down 20px from normal position */
left: 50px; /* Moves right 50px from normal position */
}
Key Points:
- The element still occupies its original space in the flow
- Other elements are not affected by the offset
- Creates a positioning context for absolutely positioned children
3. position: absolute
The element is removed from the normal flow and positioned relative to its nearest positioned ancestor (or the <html> root if none exists).
.absolute {
position: absolute;
top: 20px;
left: 50px;
}
Key Points:
- Removed from the normal flow (other elements ignore it)
- Positioned relative to nearest ancestor with
position: relative,absolute,fixed, orsticky - If no positioned ancestor exists, it’s positioned relative to the initial containing block (the viewport)
- Creates a positioning context for its children
4. position: fixed
The element is removed from the normal flow and positioned relative to the viewport. It stays in the same place even when the page is scrolled.
.fixed {
position: fixed;
top: 20px;
right: 20px;
}
Key Points:
- Removed from the normal flow
- Positioned relative to the viewport (not the document)
- Stays fixed when scrolling
- Commonly used for sticky headers, floating buttons, and modals
5. position: sticky
The element behaves like relative until it reaches a threshold (specified by top, bottom, left, or right), then it becomes fixed relative to its nearest scrolling ancestor.
.sticky {
position: sticky;
top: 20px; /* Sticks when it reaches 20px from the top */
}
Key Points:
- Hybrid between
relativeandfixed - Stays in normal flow until threshold is reached
- Sticks to the specified position within its parent container
- Commonly used for sticky headers, sidebars, and table headers
Comparison Table
| Value | In Flow? | Positioned Relative To | Scrolls? | Creates Context? |
|---|---|---|---|---|
static | ✅ Yes | Normal flow | ✅ Yes | ❌ No |
relative | ✅ Yes | Its normal position | ✅ Yes | ✅ Yes |
absolute | ❌ No | Nearest positioned ancestor | ✅ Yes | ✅ Yes |
fixed | ❌ No | Viewport | ❌ No | ✅ Yes |
sticky | ✅ Yes | Nearest scrolling ancestor | Until threshold | ✅ Yes |
The z-index Property
When elements overlap, z-index controls which appears on top. It only works on positioned elements (relative, absolute, fixed, sticky).
.element {
position: relative;
z-index: 10; /* Higher = on top */
}
Complete Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>The position Property</title>
<style>
*, *::before, *::after {
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: #f8f9fa;
line-height: 1.6;
}
h1 {
color: #007bff;
border-bottom: 3px solid #007bff;
padding-bottom: 10px;
}
h2 {
color: #28a745;
border-left: 4px solid #28a745;
padding-left: 15px;
margin-top: 30px;
}
section {
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin: 20px 0;
}
.demo-box {
padding: 15px;
border-radius: 8px;
margin: 10px 0;
border: 2px solid #ddd;
background: #f8f9fa;
}
.code-block {
background: #1e1e1e;
color: #d4d4d4;
padding: 15px;
border-radius: 8px;
overflow-x: auto;
font-family: 'Courier New', monospace;
font-size: 0.9rem;
line-height: 1.8;
margin: 10px 0;
}
.reference-table {
width: 100%;
border-collapse: collapse;
margin: 15px 0;
}
.reference-table th,
.reference-table td {
padding: 10px;
border: 1px solid #ddd;
text-align: left;
}
.reference-table th {
background: #007bff;
color: white;
}
.reference-table tr:nth-child(even) {
background: #f8f9fa;
}
/* ====== POSITION DEMOS ====== */
.position-demo {
position: relative;
background: #e9ecef;
padding: 20px;
border-radius: 8px;
min-height: 300px;
border: 2px dashed #ccc;
}
.position-demo .label {
position: absolute;
top: 5px;
left: 10px;
font-size: 0.8rem;
font-weight: bold;
color: #666;
background: white;
padding: 2px 8px;
border-radius: 4px;
}
/* Static */
.static-box {
position: static;
background: #007bff;
color: white;
padding: 15px;
margin: 10px 0;
border-radius: 4px;
width: 200px;
}
/* Relative */
.relative-box {
position: relative;
top: 20px;
left: 50px;
background: #28a745;
color: white;
padding: 15px;
margin: 10px 0;
border-radius: 4px;
width: 200px;
}
/* Absolute */
.absolute-container {
position: relative;
background: #f8f9fa;
border: 2px dashed #007bff;
padding: 20px;
margin: 20px 0;
min-height: 200px;
border-radius: 8px;
}
.absolute-box {
position: absolute;
top: 20px;
right: 20px;
background: #dc3545;
color: white;
padding: 15px;
border-radius: 4px;
width: 180px;
}
/* Fixed */
.fixed-box {
position: fixed;
bottom: 20px;
right: 20px;
background: #6c5ce7;
color: white;
padding: 15px 25px;
border-radius: 50px;
box-shadow: 0 4px 15px rgba(108, 92, 231, 0.4);
z-index: 1000;
cursor: pointer;
transition: transform 0.3s;
}
.fixed-box:hover {
transform: scale(1.05);
}
/* Sticky */
.sticky-container {
background: #f8f9fa;
border: 2px dashed #ffc107;
padding: 20px;
margin: 20px 0;
border-radius: 8px;
height: 300px;
overflow-y: auto;
}
.sticky-header {
position: sticky;
top: 0;
background: #ffc107;
color: #333;
padding: 15px;
border-radius: 4px;
font-weight: bold;
z-index: 10;
}
.sticky-content {
padding: 15px;
}
.sticky-content p {
margin: 10px 0;
}
/* Overlap demo */
.overlap-container {
position: relative;
height: 150px;
background: #f8f9fa;
border: 2px dashed #ddd;
border-radius: 8px;
margin: 20px 0;
}
.overlap-box {
position: absolute;
width: 120px;
height: 80px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
border-radius: 8px;
}
.overlap-box:nth-child(1) {
background: #007bff;
top: 20px;
left: 20px;
z-index: 1;
}
.overlap-box:nth-child(2) {
background: #28a745;
top: 40px;
left: 60px;
z-index: 2;
}
.overlap-box:nth-child(3) {
background: #dc3545;
top: 60px;
left: 100px;
z-index: 3;
}
</style>
</head>
<body>
<h1>The position Property</h1>
<!-- ====== 1. STATIC ====== -->
<section>
<h2>1. position: static (default)</h2>
<p>Elements remain in their normal flow. The <code>top</code>, <code>right</code>, <code>bottom</code>, <code>left</code>, and <code>z-index</code> properties have <strong>no effect</strong>.</p>
<div class="position-demo">
<span class="label">static container</span>
<div class="static-box">Static Box 1</div>
<div class="static-box">Static Box 2</div>
<div class="static-box">Static Box 3</div>
</div>
<div class="code-block">
.static {
position: static; /* Default */
/* top, left, z-index have NO effect */
}
</div>
</section>
<!-- ====== 2. RELATIVE ====== -->
<section>
<h2>2. position: relative</h2>
<p>The element is positioned relative to its <strong>normal position</strong>. It still occupies its original space in the flow.</p>
<div class="position-demo">
<span class="label">relative container</span>
<div class="static-box" style="opacity: 0.3;">Normal position (ghost)</div>
<div class="relative-box">Relative Box (offset: top 20px, left 50px)</div>
<div class="static-box">Normal Box</div>
</div>
<div class="code-block">
.relative {
position: relative;
top: 20px; /* Moves down 20px from normal position */
left: 50px; /* Moves right 50px from normal position */
}
</div>
</section>
<!-- ====== 3. ABSOLUTE ====== -->
<section>
<h2>3. position: absolute</h2>
<p>The element is removed from the normal flow and positioned relative to its <strong>nearest positioned ancestor</strong>.</p>
<div class="absolute-container">
<span class="label">absolute container (position: relative)</span>
<p>This container has <code>position: relative</code>, making it the positioning context for the absolute box.</p>
<div class="absolute-box">Absolute Box (top: 20px, right: 20px)</div>
<div style="height: 150px;"></div>
</div>
<div class="code-block">
.absolute-container {
position: relative; /* Creates positioning context */
}
.absolute {
position: absolute;
top: 20px;
right: 20px;
}
</div>
</section>
<!-- ====== 4. FIXED ====== -->
<section>
<h2>4. position: fixed</h2>
<p>The element is removed from the flow and positioned relative to the <strong>viewport</strong>. It stays in place when scrolling.</p>
<p>Scroll down the page — the purple button at the bottom-right stays fixed!</p>
<div class="code-block">
.fixed {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 1000;
}
</div>
</section>
<!-- ====== 5. STICKY ====== -->
<section>
<h2>5. position: sticky</h2>
<p>The element behaves like <code>relative</code> until it reaches a threshold, then becomes <code>fixed</code> within its parent.</p>
<div class="sticky-container">
<div class="sticky-header">📌 Sticky Header (scroll inside this box)</div>
<div class="sticky-content">
<p>Scroll inside this container to see the sticky header stay at the top.</p>
<p>Line 1 — Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<p>Line 2 — Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Line 3 — Ut enim ad minim veniam, quis nostrud exercitation ullamco.</p>
<p>Line 4 — Duis aute irure dolor in reprehenderit in voluptate velit.</p>
<p>Line 5 — Excepteur sint occaecat cupidatat non proident.</p>
<p>Line 6 — Sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Line 7 — Sed ut perspiciatis unde omnis iste natus error sit voluptatem.</p>
<p>Line 8 — Accusantium doloremque laudantium, totam rem aperiam.</p>
<p>Line 9 — Eaque ipsa quae ab illo inventore veritatis et quasi architecto.</p>
<p>Line 10 — Beatae vitae dicta sunt explicabo.</p>
</div>
</div>
<div class="code-block">
.sticky {
position: sticky;
top: 0; /* Sticks when it reaches the top */
}
</div>
</section>
<!-- ====== 6. Z-INDEX ====== -->
<section>
<h2>6. z-index (stacking order)</h2>
<p>When elements overlap, <code>z-index</code> controls which appears on top. Higher values appear on top.</p>
<div class="overlap-container">
<div class="overlap-box">z-index: 1</div>
<div class="overlap-box">z-index: 2</div>
<div class="overlap-box">z-index: 3</div>
</div>
<div class="code-block">
.overlap-box:nth-child(1) { z-index: 1; }
.overlap-box:nth-child(2) { z-index: 2; }
.overlap-box:nth-child(3) { z-index: 3; }
</div>
</section>
<!-- ====== REFERENCE TABLES ====== -->
<section>
<h2>7. Reference Tables</h2>
<h3>position Values</h3>
<table class="reference-table">
<tr>
<th>Value</th>
<th>In Flow?</th>
<th>Positioned Relative To</th>
<th>Scrolls?</th>
</tr>
<tr>
<td><code>static</code></td>
<td>✅ Yes</td>
<td>Normal flow</td>
<td>✅ Yes</td>
</tr>
<tr>
<td><code>relative</code></td>
<td>✅ Yes</td>
<td>Its normal position</td>
<td>✅ Yes</td>
</tr>
<tr>
<td><code>absolute</code></td>
<td>❌ No</td>
<td>Nearest positioned ancestor</td>
<td>✅ Yes</td>
</tr>
<tr>
<td><code>fixed</code></td>
<td>❌ No</td>
<td>Viewport</td>
<td>❌ No</td>
</tr>
<tr>
<td><code>sticky</code></td>
<td>✅ Yes</td>
<td>Nearest scrolling ancestor</td>
<td>Until threshold</td>
</tr>
</table>
<h3>Positional Properties</h3>
<table class="reference-table">
<tr>
<th>Property</th>
<th>Description</th>
<th>Example</th>
</tr>
<tr>
<td><code>top</code></td>
<td>Offset from the top</td>
<td><code>top: 20px;</code></td>
</tr>
<tr>
<td><code>right</code></td>
<td>Offset from the right</td>
<td><code>right: 20px;</code></td>
</tr>
<tr>
<td><code>bottom</code></td>
<td>Offset from the bottom</td>
<td><code>bottom: 20px;</code></td>
</tr>
<tr>
<td><code>left</code></td>
<td>Offset from the left</td>
<td><code>left: 20px;</code></td>
</tr>
<tr>
<td><code>z-index</code></td>
<td>Stacking order (higher = on top)</td>
<td><code>z-index: 10;</code></td>
</tr>
</table>
</section>
<!-- ====== BEST PRACTICES ====== -->
<section>
<h2>8. Best Practices</h2>
<div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
<h3 style="margin-top: 0; color: #155724;">✅ Do This:</h3>
<ul>
<li>Use <code>position: relative</code> to create a positioning context for absolute children</li>
<li>Use <code>position: fixed</code> for sticky headers and floating buttons</li>
<li>Use <code>position: sticky</code> for table headers and sidebars</li>
<li>Use <code>z-index</code> sparingly and with meaningful values</li>
<li>Use <code>position: absolute</code> for overlays, tooltips, and badges</li>
</ul>
</div>
<div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
<h3 style="margin-top: 0; color: #721c24;">❌ Don't Do This:</h3>
<ul>
<li>Don't use <code>position: absolute</code> without a positioned ancestor</li>
<li>Don't use <code>z-index: 9999</code> — use meaningful values</li>
<li>Don't use <code>position: fixed</code> for large elements (can block content)</li>
<li>Don't forget that <code>position: absolute</code> removes elements from the flow</li>
</ul>
</div>
</section>
<!-- ====== FIXED BUTTON ====== -->
<div class="fixed-box" onclick="window.scrollTo({top: 0, behavior: 'smooth'});">
↑ Back to Top
</div>
</body>
</html>
Quick Reference
| Value | In Flow? | Positioned Relative To | Scrolls? | Creates Context? |
|---|---|---|---|---|
static | ✅ Yes | Normal flow | ✅ Yes | ❌ No |
relative | ✅ Yes | Its normal position | ✅ Yes | ✅ Yes |
absolute | ❌ No | Nearest positioned ancestor | ✅ Yes | ✅ Yes |
fixed | ❌ No | Viewport | ❌ No | ✅ Yes |
sticky | ✅ Yes | Nearest scrolling ancestor | Until threshold | ✅ Yes |
Best Practices
✅ Do This:
/* Create a positioning context */
.card {
position: relative; /* Parent */
}
.card .badge {
position: absolute; /* Child */
top: 10px;
right: 10px;
}
/* Sticky header */
.header {
position: sticky;
top: 0;
z-index: 100;
}
/* Fixed floating button */
.back-to-top {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 1000;
}
❌ Don’t Do This:
/* Don't use absolute without a positioned parent */
.badge {
position: absolute;
top: 0;
/* Will position relative to the viewport, not the card */
}
/* Don't use z-index: 9999 */
.element {
z-index: 9999; /* Use meaningful values like 10, 100, 1000 */
}
/* Don't use fixed for large elements */
.overlay {
position: fixed;
width: 100%;
height: 100%;
/* May block content and break scrolling */
}
Pro Tip: Use position: relative on a parent to create a positioning context for absolutely positioned children. Use position: fixed for elements that should always be visible (like a back-to-top button). Use position: sticky for table headers or sidebars that should stay visible while scrolling. Remember that absolute and fixed elements are removed from the normal flow, so they don’t affect the layout of other elements!
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!