The position property controls how an element is placed on the page and how it interacts with surrounding elements. Understanding it requires understanding the concept of containing block and document flow.
Key concept: When you use top, right, bottom, or left — they only work if position is set to something other than static.
position: static (Default)
static is the default value for every element. Static elements follow the normal document flow — they appear in the order they are written in the HTML, left to right, top to bottom.
The top, right, bottom, and left properties have no effect on static elements. You almost never write position: static explicitly — it is just the default.
/* This does nothing — static is the default */
.box {
position: static;
top: 20px; /* has no effect */
left: 50px; /* has no effect */
}position: relative
relative positions an element relative to its own normal position in the document flow. The element still occupies its original space — other elements are not affected.
The most important use of relative is as a positioning context for absolutely positioned children.
.box {
position: relative;
top: 20px; /* move DOWN 20px from its normal position */
left: 30px; /* move RIGHT 30px from its normal position */
}
/* Common pattern: parent is relative so child absolute works */
.parent {
position: relative; /* creates positioning context */
}
.child {
position: absolute;
top: 0;
right: 0; /* anchors to top-right of parent */
}Think of position: relative as "I keep my spot, but I can shift from it." It is most valuable as a container for absolutely positioned children.
position: absolute
absolute removes the element from the normal document flow completely — other elements act as if it does not exist. The element is then positioned relative to its nearest positioned ancestor (any parent with position set to anything other than static).
If no positioned ancestor exists, the element positions itself relative to the <html> element (the initial containing block).
/* Tooltip that appears on top-right of its parent */
.card {
position: relative; /* <- IMPORTANT: creates the anchor */
padding: 1.5rem;
}
.badge {
position: absolute;
top: 10px;
right: 10px;
background: red;
color: white;
border-radius: 999px;
padding: 2px 8px;
font-size: 12px;
}
/* Common: centered overlay */
.overlay {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0; /* fill parent completely */
background: rgba(0, 0, 0, 0.5);
}Always set position: relative on the parent element when using position: absolute on a child. Otherwise the child will escape and position itself relative to the page.
position: fixed
fixed removes the element from normal flow and positions it relative to the browser viewport — the visible window. It stays in place even when the user scrolls.
/* Sticky navigation bar that stays at the top */
.navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 60px;
background: #fff;
z-index: 100; /* sit above other content */
box-shadow: 0 2px 8px rgba(0,0,0,.1);
}
/* Always-visible back-to-top button */
.back-to-top {
position: fixed;
bottom: 2rem;
right: 2rem;
background: #6d28d9;
color: #fff;
border-radius: 50%;
width: 44px;
height: 44px;
}
/* IMPORTANT: add top padding to body to prevent content hiding behind fixed nav */
body {
padding-top: 60px;
}Fixed elements take up no space in the document, so they can hide content beneath them. Always add padding or margin to prevent overlap.
position: sticky
sticky is a hybrid between relative and fixed. The element behaves like relative until the user scrolls to a certain point, then it "sticks" and behaves like fixed within its parent container.
/* Sticky table header */
thead th {
position: sticky;
top: 0; /* sticks to top when scrolling */
background: #fff; /* IMPORTANT: needs background or content shows through */
z-index: 1;
}
/* Sidebar that sticks while scrolling */
.sidebar {
position: sticky;
top: 80px; /* sticks 80px from top of viewport */
height: fit-content;
}
/* Sticky section headings (alphabet list style) */
.section-label {
position: sticky;
top: 0;
background: #f8f7ff;
padding: 0.5rem 1rem;
font-weight: 700;
}position: sticky not working? Check these common causes: (1) The parent has overflow: hidden set — remove it. (2) You forgot to set top, left, right, or bottom. (3) The parent is too short to allow scrolling.
Quick Comparison Table
| Value | Removed from Flow? | Positioned Relative To | Scrolls With Page? |
|---|---|---|---|
| static | No | Normal flow | Yes |
| relative | No (keeps its space) | Its own original position | Yes |
| absolute | Yes | Nearest positioned ancestor | Yes (unless inside fixed) |
| fixed | Yes | Browser viewport | No — always visible |
| sticky | No (until threshold) | Scroll position + parent | Partially |
Common Patterns
- Notification badge on icon — parent
relative, badgeabsolutetop-right - Image caption overlay — container
relative, captionabsolutebottom-0 - Sticky nav bar —
fixedorstickyattop: 0 - Modal / dialog — backdrop
fixedcovering viewport, dialogfixedcentered with transform - Sticky sidebar — sidebar
stickywithtopoffset - Tooltip — tooltip
absolute, positioned relative torelativeparent