How does positioning work in CSS?
Positioning in CSS
By default, elements on a webpage follow the "normal document flow"—they stack one after another, from top to bottom. However, we can opt into Positioned layout using the position property.
It can be set to relative, absolute, fixed, or sticky. Each one works in a unique way, like a mini-layout-algorithm within the larger layout engine.
Static (The Default)
The default value of the position property is static.
When an element is static, it's not using Positioned layout; it's using Flow, Flexbox, or Grid. Directional values like top, bottom, left, or right have no effect here.
If an element is currently using Positioned layout and you want to opt out, you can set position to either static or initial:
.box {
/* Revert to its default value, which is 'static' */
position: initial;
}Relative positioning
Of all the Positioned layout sub-genres, relative is the most subtle.
You can often apply position: relative on an element, and observe zero difference. It appears to have no effect! In fact, it does two things:
- Constrains certain children: It acts as an anchor for any children with
position: absolute. - Enables additional CSS properties: It allows you to use
top,left,right, andbottomto shift the element around.
With relative positioning, those directional values are relative to the element's natural position. For example, setting left: 10px pushes the element 10px to the right of where it would normally be.
Position vs Margin
The big difference is that position doesn't impact layout flow. While margin pushes sibling elements around, position is purely cosmetic. The browser acts like the element is still in its original spot, and siblings don't move.
Absolute positioning
When you use position: absolute, the element completely breaks away from the document flow. Other elements move up to fill the space it left behind, as if it never existed.
The element then positions itself relative to its nearest positioned ancestor (any parent with a position other than static). If it can't find one, it uses the <html> element.
Tip
This is why you'll often see position: relative on a parent container—just so a child with position: absolute knows exactly where to anchor itself.
Fixed positioning
fixed ignores the document flow and anchors itself relative to the browser window (viewport). No matter how much you scroll, it stays in the exact same spot on the screen. This is perfect for things like navigation bars, floating action buttons, or modal overlays.
Sticky positioning
sticky is a hybrid between relative and fixed. It behaves like relative until you scroll to a certain threshold (defined by top, left, etc.), and then it "sticks" to the screen like a fixed element. Once you scroll past its parent container, it unsticks and scrolls away.
A common use case is section headers that stick to the top of the viewport as you scroll through a long list.
Quick Summary
| Position | Leaves Flow? | Positioned Relative To... | Common Use Case |
|---|---|---|---|
| Static | No | Normal Flow | Default (not positioned) |
| Relative | No | Its original spot | Anchoring children, small nudges |
| Absolute | Yes | Nearest positioned ancestor | Tooltips, dropdowns, overlays |
| Fixed | Yes | Viewport | Nav bars, floating buttons |
| Sticky | No* | Parent container / Scroll | Section headers in lists |
Sticky behaves like relative until the scroll threshold is hit, then becomes fixed.
Interview Tip
A common interview question is: "What's the difference between position: relative and using margin to move an element?"
The key difference is that margin affects layout, it pushes other elements around. Relative positioning is cosmetic, the browser renders the element in a shifted location, but acts like it's still in its original spot. Sibling elements don't move at all.