positioning fundamentals
The position property controls how an element is positioned relative to the normal document flow. Elements can be static (default, in normal flow), relative (in flow but offset), absolute (out of flow, positioned relative to a containing block), fixed (out of flow, positioned relative to viewport), or sticky (in flow until scroll threshold). The top, right, bottom, and left properties specify the offset for positioned elements.
The position values
Value | In flow? | Relative to | Use case |
|---|---|---|---|
| Yes | Normal flow | Default, part of document flow |
| Yes | Its normal position | Slight adjustments, context for absolute children |
| No | Nearest positioned ancestor | Overlays, modals, precise positioning |
| No | Viewport | Headers, sticky navigation, sticky chat |
| Yes/No | Scroll position & parent | Sticky headers, table headers |
/* Static — default, in normal flow */ position: static; /* element flows normally, top/left ignored */ /* Relative — in flow, but offset from normal position */ position: relative; top: 10px; /* offset 10px from where it would normally be */ left: 20px; /* offset 20px to the right */ /* Absolute — out of flow, positioned precisely */ position: absolute; top: 50px; /* 50px from top of containing block */ left: 100px; /* 100px from left of containing block */ /* Fixed — out of flow, positioned to viewport */ position: fixed; top: 0; /* stick to top of viewport */ right: 0; /* stick to right edge */ /* Sticky — in flow until scroll threshold */ position: sticky; top: 0; /* stick to top when scrolled past */
The containing block concept
Positioned elements are placed relative to a "containing block." For most elements, this is the parent element. For absolutely positioned elements, it's the nearest ancestor with position: relative (or other non-static position). Understanding containing blocks is crucial for positioning.
<!-- Example HTML structure -->
<div class="parent">
<div class="child">Child</div>
</div>
/* Parent without position — default is static */
.parent {
width: 300px;
height: 200px;
/* position: static (default) */
/* NOT a containing block for absolutely positioned children */
}
.child {
position: absolute;
top: 50px;
left: 100px;
/* positioned relative to VIEWPORT (no positioned ancestor) */
}
/* Parent with position: relative — becomes containing block */
.parent {
width: 300px;
height: 200px;
position: relative; /* creates containing block */
}
.child {
position: absolute;
top: 50px; /* 50px from parent's top */
left: 100px; /* 100px from parent's left */
/* positioned relative to parent */
}
/* Same applies to other position values */
.positioned-parent {
position: absolute; /* also creates containing block */
}
.positioned-parent {
position: fixed; /* also creates containing block */
}Static positioning (default)
/* Static — default value */
position: static;
/* Element behaves normally */
div {
position: static; /* explicit, but usually implied */
top: 10px; /* ignored when position: static */
left: 20px; /* ignored when position: static */
}
/* Remove positioning by resetting to static */
.positioned {
position: absolute;
top: 50px;
left: 100px;
}
.positioned.normal {
position: static; /* back to normal flow */
top: auto;
left: auto;
}Offset properties: top, right, bottom, left
These four properties specify the position offset for relative, absolute, fixed, and sticky positioned elements.
/* Offset from all sides */
.positioned {
position: absolute;
top: 10px; /* 10px from top */
right: 20px; /* 20px from right */
bottom: 30px; /* 30px from bottom */
left: 40px; /* 40px from left */
}
/* Positioning from specific corners */
.top-left {
position: absolute;
top: 10px;
left: 10px;
}
.top-right {
position: absolute;
top: 10px;
right: 10px;
}
.bottom-right {
position: absolute;
bottom: 10px;
right: 10px;
}
.bottom-left {
position: absolute;
bottom: 10px;
left: 10px;
}
/* Opposite sides define sizing */
.stretch-horizontally {
position: absolute;
left: 0;
right: 0;
/* Stretches to fill width */
}
.stretch-vertically {
position: absolute;
top: 0;
bottom: 0;
/* Stretches to fill height */
}
.stretch-all {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
/* Fills containing block completely */
}In flow vs out of flow
This is a critical distinction: elements with position: relative stay in the normal flow and take up space. Elements with position: absolute or fixed are removed from the flow and don't take up space.
<!-- Three similar-looking elements -->
<div class="element">Normal</div>
<div class="element relative">Relative</div>
<div class="element absolute">Absolute</div>
<div class="element">After</div>
/* All three elements, but different positioning */
.element {
width: 100px;
height: 100px;
background: lightblue;
margin: 10px;
}
.relative {
position: relative;
top: 20px;
left: 20px;
/* Still takes space in flow, offset visually */
}
/* Layout appears as */
[Normal]
[Relative offset]
[After] <!-- moves up because absolute doesn't take space -->
.absolute {
position: absolute;
top: 20px;
left: 20px;
/* Removed from flow, doesn't take up space */
}
/* Layout appears as */
[Normal]
[After] <!-- moves up because absolute is out of flow -->
(absolute element floats above)Position + display interaction
When you use position: absolute or fixed, the display property changes: inline elements become block-like and can receive width/height.
<!-- Inline element (normally ignores width/height) -->
<span>Text</span>
span {
display: inline; /* default */
width: 100px; /* ignored */
height: 50px; /* ignored */
}
<!-- Same element, but absolutely positioned -->
<span class="positioned">Text</span>
.positioned {
position: absolute;
width: 100px; /* NOW works */
height: 50px; /* NOW works */
/* Absolute positioning makes inline elements respect sizing */
}
/* This is implicit — no need to set display: block */Practical positioning patterns
/* Overlay badge on image */
.image-container {
position: relative; /* containing block for child */
display: inline-block;
width: 200px;
height: 200px;
overflow: hidden;
border-radius: 8px;
}
.badge {
position: absolute;
top: 10px;
right: 10px;
background: #f44336;
color: white;
padding: 4px 8px;
border-radius: 12px;
/* Badge positioned in corner of image */
}
/* Close button on modal */
.modal {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/* Modal centered on screen */
}
.close-button {
position: absolute;
top: 10px;
right: 10px;
width: 30px;
height: 30px;
/* Close button in modal corner */
}
/* Sticky header */
.header {
position: sticky;
top: 0;
background: white;
z-index: 10;
/* Header sticks to top while scrolling */
}