What does position do?
This is where you take control. position takes an element out of the normal
flow (or not) and enables the offsets top, right, bottom and
left to move it wherever you like. There are five values, and each one plays
by its own rules.
static (default)
position: static is the normal behavior: the element follows the flow and
the offsets have no effect.
relative
position: relative keeps the element in its place in the flow (it still
occupies its original slot), but now top/left/etc. move it relative to that
starting position. Its other big use, maybe the most important one: turning it
into the reference ancestor for absolute children. Remember that, because
it comes back right away.
.moved {
position: relative;
top: 10px; /* moves down 10px from where it was */
left: 20px; /* shifts 20px to the right */
}
absolute
position: absolute takes the element out of the flow (it stops reserving a
slot) and places it relative to the nearest positioned ancestor: the first
one, going up the tree, that has a position other than static. If there is
none, it is positioned relative to the document.
⚠️ CLASSIC TRAP: relative to whom does an absolute element position
itself? Not to its direct parent, but to the positioned ancestor. If your
badge ends up in the corner of the page instead of the corner of its card, you
almost certainly forgot a position: relative on that card.
.container { position: relative; } /* reference ancestor */
.badge {
position: absolute;
top: 8px;
right: 8px; /* top-right corner of the container */
}
This relative + absolute pattern is your bread and butter for placing badges, icons or close buttons exactly where you want them inside a box.
fixed
position: fixed also leaves the flow, but anchors to the browser window
(viewport): it does not move when scrolling. It is the trick behind that
bar that stays pinned at the top, or that floating button that follows you all
over the page.
.floating-button {
position: fixed;
bottom: 20px;
right: 20px;
}
sticky
position: sticky is the chameleon: the element flows normally until it
reaches the threshold you set (e.g. top: 0) while scrolling; at that point
it "sticks" and stays fixed as long as its container is on screen.
Perfect for those section headers that stay at the top while you read the section
and then leave with it.
.header {
position: sticky;
top: 0; /* sticks to the top edge when scrolling */
}
Summary:
relativemoves and references;absolutepositions inside the ancestor;fixedanchors to the viewport;stickysticks when scrolling.
Examples
A badge in the corner with relative + absolute
<style>
.box {
position: relative;
width: 160px;
height: 90px;
background: #e2e8f0;
}
.badge {
position: absolute;
top: 6px;
right: 6px;
background: #ef4444;
color: white;
padding: 2px 8px;
border-radius: 999px;
}
</style>
<div class="box">
<span class="badge">New</span>
Product
</div>