Position and layout flow
The position property is one of CSS’s most powerful and frequently misunderstood features. It controls whether an element participates in the normal document flow, and if so, how it can be offset or pinned. Mastering it unlocks overlays, sticky headers, fixed CTAs, and many other common UI patterns.
static — the default
Every element is position: static unless you change it. Static elements appear in the normal document flow — stacked top to bottom in source order. The offset properties (top, right, bottom, left) and z-index have no effect on static elements.
You rarely need to set position: static explicitly, but it is useful for resetting a positioned element back to normal flow.
relative — offset without leaving flow
position: relative keeps the element in the document flow — the space it would normally occupy is preserved. However, you can now use top, right, bottom, and left to visually shift it away from that position.
More importantly, relative creates a positioning context for absolutely positioned child elements. This is its most common use: not to move the element itself, but to act as an anchor for an absolutely positioned child.
.card { position: relative; }
.card__badge { position: absolute; top: 12px; right: 12px; }
absolute — removed from flow, anchored to parent
position: absolute removes the element from the document flow entirely — surrounding elements act as if it does not exist. The element is positioned relative to its nearest positioned ancestor (any ancestor with position other than static).
If no positioned ancestor exists, the element is positioned relative to the initial containing block (the viewport in most cases).
Common use cases:
- Badge or label overlaid on a card image
- Close button in the corner of a modal
- Tooltip or dropdown menu positioned relative to a trigger button
- Decorative graphic overlapping a section boundary
fixed — anchored to the viewport
position: fixed removes the element from normal flow and pins it to the viewport. It does not scroll with the page. top: 0; left: 0; width: 100% is the classic sticky navigation bar.
Common use cases:
- Sticky navigation bar at the top of the screen
- Fixed sidebar for a dashboard layout
- Persistent call-to-action button in the corner
- Cookie consent banner at the bottom of the screen
Fixed elements are positioned relative to the viewport, not any parent element. Parent positioning has no effect on fixed children.
sticky — hybrid scroll behavior
position: sticky is a hybrid: the element scrolls normally with the page until it reaches a defined scroll threshold (set with top, bottom, etc.), at which point it sticks like a fixed element until the parent element leaves the viewport.
.section-header {
position: sticky;
top: 64px; /* sticks 64px from the top of the viewport */
}
Common use cases:
- Section headings that stick while you scroll through a long section
- Table headers that stay visible while scrolling a long table
- Side navigation that sticks as you read a long article
z-index and stacking order
z-index controls which element appears in front when two elements overlap. Higher values appear in front of lower values.
z-index only works on positioned elements (relative, absolute, fixed, sticky). Setting z-index on a static element has no effect.
In Site Designer, the position controls in the Style pane include a z-index field. Common conventions: use values like 10, 100, 1000 for layers (navigation, modals, tooltips) so you have room to insert values between them later.
Common patterns
Fixed header:
.site-header { position: fixed; top: 0; left: 0; width: 100%; z-index: 100; }
Sticky sidebar:
.sidebar { position: sticky; top: 80px; align-self: start; }
Absolute overlay text on image:
.card { position: relative; }
.card__overlay { position: absolute; inset: 0; display: flex; align-items: flex-end; }
(inset: 0 is shorthand for top: 0; right: 0; bottom: 0; left: 0 — it stretches the overlay to fill the parent.)