position: absolute in one example
An absolutely positioned element is lifted out of the normal flow and placed with top, right, bottom and left. Those offsets are measured from the nearest ancestor that has a position other than static, which is why the parent gets position: relative:
Delete position: relative from .card and the badge jumps to the top right of the whole page, because it no longer has a positioned ancestor. That one line explains most "position absolute not working" questions.
Things to know about absolute elements:
- They take no space. The heading and paragraph are laid out as if the badge did not exist.
- Their width shrinks to fit their content, unless you set
widthor bothleftandright. - Offsets are measured to the padding edge of the containing block, inside its border.
The five position values
| Value | In the flow? | Offsets measured from | Typical use |
|---|---|---|---|
static (default) | Yes | Offsets are ignored | Normal elements |
relative | Yes, its space is kept | Its own normal position | Anchor for absolute children, small nudges |
absolute | No | Nearest positioned ancestor (or the page) | Badges, tooltips, overlays, close buttons |
fixed | No | The viewport | Headers, chat buttons, cookie bars |
sticky | Yes | Its scroll container, once it reaches the offset | Table headers, section titles, sidebars |
position: relative
A relatively positioned element stays where it was in the flow. Offsets move where it is drawn, but its original space stays reserved, so nothing around it moves:
Box 2 is drawn 20px down and 20px to the right, overlapping box 3, but box 3 did not move: it still leaves room for box 2 at its original spot. On its own relative is rarely used for moving things; its main job is to be the reference box for absolute children.
Offsets and inset
top, right, bottom and left accept lengths, percentages (of the containing block) and auto. The inset shorthand sets all four in the same order as margin:
.overlay {
position: absolute;
inset: 0; /* top: 0; right: 0; bottom: 0; left: 0; */
}
.corner {
position: absolute;
inset: auto 16px 16px auto; /* bottom right corner, 16px in */
}
Setting opposite sides stretches the element: left: 0; right: 0 makes it as wide as the containing block. inset: 0 on an absolute child is the standard way to cover a card with an overlay.
Centering with absolute and transform
top: 50%; left: 50% puts the element's top left corner at the center. translate(-50%, -50%) then moves it back by half its own size:
Flexbox and grid center more simply when the element can stay in the flow; the center a div page compares every method.
position: fixed
A fixed element is placed relative to the viewport and stays there while the page scrolls:
.chat-button {
position: fixed;
bottom: 16px;
right: 16px;
}
Two gotchas. A fixed element takes no space, so a fixed header covers the top of the page unless you add padding-top to the body. And if any ancestor has a transform, filter or perspective, that ancestor becomes the reference box instead of the viewport, so the element scrolls with it.
position: sticky
A sticky element scrolls normally until it reaches its offset, then sticks there until the end of its parent scrolls past. Scroll the box below:
Each letter sticks to the top of the scroll box while its section is visible, then is pushed away by the next one, because a sticky element never leaves its parent.
When sticky does not stick, check these:
- No offset.
position: stickydoes nothing withouttop,bottom,leftorright. - An ancestor with
overflow: hidden,autoorscroll. It becomes the scroll container, and if it does not actually scroll, nothing sticks. Useoverflow: clipif you only need to hide overflow. - A parent that is no taller than the sticky element. There is no room to stick inside it.
- A flex or grid parent stretching it. In a flex row, add
align-self: flex-startto the sticky sidebar.
Common mistakes
- Forgetting
position: relativeon the parent of an absolute element. - Using absolute for page layout. Absolute elements ignore each other and the content, so text overlaps on smaller screens. Use flexbox or grid for layout and absolute for small decorations.
- Offsets on a static element.
top: 10pxdoes nothing without aposition. - Fighting over which element is on top. Overlapping positioned elements are ordered by z-index.
- A fixed header hiding content. Add padding to the page, or
scroll-padding-topso anchor links land below it.
Frequently Asked Questions
What does position: absolute do?
It takes the element out of the normal flow (other elements act as if it were not there) and places it with top, right, bottom and left, measured from its containing block: the nearest ancestor whose position is not static.
How do I position an element absolutely relative to its parent?
Give the parent position: relative; and the child position: absolute; with offsets such as top: 0; right: 0;. Without a positioned parent, the child is placed relative to the page.
What is the difference between relative and absolute position?
relative keeps the element in the flow and only shifts where it is drawn, leaving its original space behind. absolute removes it from the flow and places it relative to its positioned ancestor.
Why is position: sticky not working?
Usually one of three things: no top (or other offset) is set, an ancestor has overflow: hidden or auto and becomes the scroll container, or the sticky element's parent is no taller than the element, so there is no room to stick.
What is the difference between fixed and sticky?
fixed is removed from the flow and pinned to the viewport (unless an ancestor has a transform or filter). sticky stays in the flow and scrolls normally until it reaches its offset, then sticks while its parent is still on screen.