Positioning in CSS

As a junior or new(ish) front‑end developer, there are obviously a lot of properties and quirks to get to grips with in CSS. However, one of the most important and foundational properties is the position property. Despite its importance, there are still times when a dodgy position declaration stumps even the most experienced of front‑end developers ‑ much like z-index, which I have covered previously.
There are five unique declarations for this rule, and each one acts very differently from the others, so let's do a quick run‑through of each.
Static
This is the default positioning of every element ‑ meaning if you haven't declared a position for any given element, it will be positioned statically. Static elements are predictable and work with the normal document flow, allowing text, images, and other pieces of hypermedia to flow as expected.
With position: static, inset properties such as top, left, bottom and right do not offset the element. There is an exception to the usual positioning advice for z-index: it also applies to flex and grid items even when their position remains static.
Relative
A relatively positioned element stays in normal flow, but inset properties can offset its rendered position. It also allows z-index to apply, though flex and grid items do not need this positioning change just to use z-index.
A parent with position: relative can establish the containing block for an absolutely positioned descendant. The descendant uses the nearest ancestor that establishes that containing block, so a more immediate ancestor can take precedence.
Relative positioning creates a stacking context only when its z-index is not auto. It can establish the containing block for absolutely positioned descendants without necessarily creating a new stacking context. Generally, you will want that relationship deliberately ‑ but definitely not always.
Absolute
Absolute positioning is where things start to get a bit more advanced. An absolutely positioned element is taken out of the document flow, meaning that other elements will act as though it is not even there: siblings will flow on top or behind it, and parents will act as though it's not there at all. Amongst other things, this means parents will lose any height they would have inherited from the position: absolute child.
An absolutely positioned element uses its containing block, usually established by the nearest ancestor with a non‑static position. Positioning is not the only trigger: an ancestor with transform other than none, for example, can establish the containing block even with position: static. This is the same sort of exception discussed for fixed positioning below. If no ancestor establishes one, the initial containing block is used.
Fixed
Fixed positioning is often used for sidebars, cookie notices, modal boxes or navigation. A position: fixed element is normally positioned against the viewport and does not move with document scrolling. However, an ancestor with a transform, perspective, filter or another containing‑block trigger can capture it, so it is not positioned against the document in every case.
Sticky
By this article's publication in February 2022, sticky positioning was broadly supported in current browsers. It combines normal‑flow participation with an offset relative to its nearest relevant scrolling ancestor and containing block; when the threshold is reached, it remains sticky within those bounds rather than becoming a fixed‑position element.
With sticky positioning, an inset such as top defines the threshold and offset within the sticky element's scroll container. A value of 0 keeps it at the top edge while its containing block permits. This is useful for navigation beneath a masthead, provided no ancestor's overflow or dimensions create an unintended scroll container.
The Wrap‑up
The final declaration for the positioning rule is inherit. By default, the positioning declaration doesn't flow from parents to children: a parent with position: absolute will have children with position: static unless defined otherwise. So, you can force it to inherit the property from the parent by using inherit.
Positioning is one of the most foundational things to learn as a developer, and with handy new declarations like sticky coming out, it is still evolving. Alongside display, positioning is one of the first CSS rules you should get to grips with as you will very likely have to use multiple positions on almost any project you work on.