How does positioning work in CSS?

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:

  1. Constrains certain children: It acts as an anchor for any children with position: absolute.
  2. Enables additional CSS properties: It allows you to use top, left, right, and bottom to 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

PositionLeaves Flow?Positioned Relative To...Common Use Case
StaticNoNormal FlowDefault (not positioned)
RelativeNoIts original spotAnchoring children, small nudges
AbsoluteYesNearest positioned ancestorTooltips, dropdowns, overlays
FixedYesViewportNav bars, floating buttons
StickyNo*Parent container / ScrollSection 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.

00:00