What is CSS position: absolute?
position: absolute takes an element out of the normal document flow and positions it using
offset properties like top, right, bottom, left (or the shorthand
inset).
“Out of flow” is the big deal: other elements behave like the absolutely positioned element isn’t there. It no longer reserves space.
- It can overlap other elements.
- It can be pinned to edges.
- Its size can shrink-wrap (often) unless you explicitly size it.
.note {
position: absolute;
top: 14px;
right: 14px;
}
.note {
position: absolute;
bottom: 14px;
left: 14px;
}
.note {
position: absolute;
inset: 14px;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 980px;
padding: 18px;
font-family: system-ui, Arial, sans-serif;
display: grid;
gap: 12px;
}
.stage {
border: 3px solid #111;
border-radius: 18px;
background: #fff;
min-height: 220px;
padding: 18px;
position: relative;
box-shadow: 0 12px 0 #111;
}
.stage p {
margin: 0 0 10px;
max-width: 55ch;
}
.note {
border: 3px solid #111;
border-radius: 999px;
padding: 8px 12px;
background: #f6f6f6;
font-weight: 700;
display: grid;
place-content: center;
}
ABSOLUTENormal flow content still lays out like the badge isn’t taking up space.
Try each snippet and watch the badge jump around the container.
Notice we used position: relative on the container (.stage) in the default CSS. That’s not
decorative. That’s the “anchor” that the absolute element measures from. Let’s unpack that properly.
Absolute positioning uses offsets
When an element is absolutely positioned, offsets like top and left push it away from the
corresponding edges of its containing block.
-
topmoves it down from the top edge. -
rightmoves it left from the right edge. -
bottommoves it up from the bottom edge. -
leftmoves it right from the left edge.
You can also use inset, which is shorthand for all four.
.box {
position: absolute;
top: 18px;
left: 18px;
}
.box {
position: absolute;
right: 18px;
bottom: 18px;
}
.box {
position: absolute;
inset: 18px 28px 48px 18px;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 980px;
padding: 18px;
font-family: system-ui, Arial, sans-serif;
display: grid;
gap: 12px;
}
.stage {
border: 3px solid #111;
border-radius: 18px;
background: #fff;
min-height: 260px;
padding: 18px;
position: relative;
box-shadow: 0 12px 0 #111;
}
.hint {
margin: 0;
max-width: 62ch;
color: #222;
}
.box {
padding: 30px;
border: 3px solid #111;
border-radius: 14px;
background: #f6f6f6;
display: grid;
place-items: center;
font-weight: 800;
}
Offsets push the box away from edges. Try the third snippet to see inset set different values on each side.
BOX
CSS position: absolute vs position: relative
These two get compared a lot, but they serve different purposes:
-
position: relativekeeps the element in normal flow, but lets you nudge it with offsets. It also creates a positioning context for absolute children. -
position: absoluteremoves the element from flow and positions it using offsets.
In real projects, position: relative is often used less for “moving the element” and more for “becoming
the parent reference” for an absolute child.
.card {
position: relative;
top: 18px;
left: 18px;
}
.card {
position: absolute;
top: 18px;
left: 18px;
}
.card {
position: relative;
}
.badge {
position: absolute;
top: 12px;
right: 12px;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 980px;
padding: 18px;
font-family: system-ui, Arial, sans-serif;
display: grid;
gap: 12px;
}
.stage {
border: 3px solid #111;
border-radius: 18px;
background: #fff;
padding: 18px;
min-height: 300px;
position: relative;
box-shadow: 0 12px 0 #111;
}
.stack {
display: grid;
gap: 12px;
max-width: 520px;
}
.card {
border: 3px solid #111;
border-radius: 18px;
background: #f6f6f6;
padding: 14px;
}
.card p {
margin: 0;
max-width: 55ch;
}
.badge {
border: 3px solid #111;
border-radius: 999px;
padding: 6px 10px;
background: #fff;
font-weight: 800;
}
NEWThis card is part of the normal layout. Watch what changes between relative and absolute.
This second card helps you see flow changes. If the first card is absolute, this one will jump up.
The “tell” is the second card. When the first card becomes absolute, it no longer takes space, so the second card moves up as if the first one vanished.
Learn more about position: relative; in the CSS Position Relative Interactive
Tutorial.
CSS position absolute relative to parent
The classic question: “Why is my absolute element not staying inside its parent?”
An absolutely positioned element is positioned relative to its nearest positioned ancestor (an
ancestor whose position is not static), or if none exists, relative to the initial
containing block (often the viewport).
In practice: if you want an absolute child to use a specific parent as its reference, give that parent
position: relative.
.child {
position: absolute;
top: 12px;
left: 12px;
}
.parent {
position: relative;
}
.child {
position: absolute;
top: 12px;
left: 12px;
}
.parent {
position: relative;
}
.child {
position: absolute;
inset: 12px;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 980px;
padding: 18px;
font-family: system-ui, Arial, sans-serif;
display: grid;
gap: 12px;
}
.row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
@media (max-width: 780px) {
.row {
grid-template-columns: 1fr;
}
}
.parent {
border: 3px solid #111;
border-radius: 18px;
background: #fff;
padding: 16px;
min-height: 220px;
box-shadow: 0 12px 0 #111;
}
.parent h4 {
margin: 0 0 8px;
}
.parent p {
margin: 0;
max-width: 52ch;
}
.child {
width: 170px;
height: 80px;
border: 3px solid #111;
border-radius: 14px;
background: #f6f6f6;
display: grid;
place-items: center;
font-weight: 900;
}
.hint {
border: 2px dashed #111;
border-radius: 14px;
padding: 12px;
background: #fff;
}
Try snippet 1 first: the child may “escape” because there is no positioned ancestor.
Then try snippet 2: adding position: relative on the parent anchors it.Parent A
Intended anchor. Give me
position: relative.CHILDParent B
Just here for comparison.
CSS position: absolute vs position: fixed
Both take elements out of flow, but they attach to different “reference frames”.
-
absolutepositions relative to a containing block (often a positioned ancestor). -
fixedpositions relative to the viewport (so it stays put during scrolling).
That’s why fixed is great for “always visible” UI like floating help buttons, while absolute is great for “inside this card” UI like badges, tooltips, and close buttons.
.floater {
position: absolute;
right: 14px;
bottom: 14px;
}
.floater {
position: fixed;
right: 14px;
bottom: 14px;
}
.floater {
position: fixed;
inset: auto 14px 14px auto;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 980px;
padding: 18px;
font-family: system-ui, Arial, sans-serif;
display: grid;
gap: 12px;
}
.scroller {
height: 280px;
overflow: auto;
border: 3px solid #111;
border-radius: 18px;
background: #fff;
box-shadow: 0 12px 0 #111;
position: relative;
}
.content {
padding: 18px;
display: grid;
gap: 12px;
min-height: 680px;
}
.block {
border: 2px dashed #111;
border-radius: 14px;
padding: 12px;
background: #f6f6f6;
}
.floater {
border: 3px solid #111;
border-radius: 999px;
padding: 10px 12px;
background: #fff;
font-weight: 900;
}
Scroll inside this box. In fixed mode, the button hugs the viewport, not this scroller.More content…More content…More content…More content…HELP
Tip: position: fixed can behave differently if an ancestor creates a new containing block (for example
via transforms). If a fixed element seems “stuck inside a container,” check ancestors for things like
transform.
Learn more about position: fixed; in the CSS Position Fixed Interactive
Tutorial.
Overlap and z-index basics
Absolute elements often overlap other content. When overlap happens, the browser needs to decide which thing is on top.
A quick starter rule: if two positioned elements overlap, z-index can control the stacking order (when it
applies).
.a {
position: absolute;
top: 28px;
left: 28px;
z-index: 1;
}
.b {
position: absolute;
top: 58px;
left: 78px;
}
.a {
position: absolute;
top: 28px;
left: 28px;
}
.b {
position: absolute;
top: 58px;
left: 78px;
z-index: 2;
}
.a {
position: absolute;
top: 28px;
left: 28px;
z-index: 5;
}
.b {
position: absolute;
top: 58px;
left: 78px;
z-index: 6;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 980px;
padding: 18px;
font-family: system-ui, Arial, sans-serif;
}
.stage {
border: 3px solid #111;
border-radius: 18px;
background: #fff;
min-height: 240px;
position: relative;
box-shadow: 0 12px 0 #111;
}
.card {
width: 220px;
height: 140px;
border: 3px solid #111;
border-radius: 18px;
display: grid;
place-items: center;
font-weight: 900;
}
.a {
background: #f6f6f6;
}
.b {
background: #fff;
}
AB
If z-index ever feels like it’s being ignored, the usual culprit is stacking contexts. But for beginners,
this playground is enough to get your mental model started: higher z-index wins within the same
stacking context.
Learn more about z-index and stacking contexts in the CSS Z-Index Interactive Tutorial and the
CSS Stacking Context Interactive
Tutorial.
CSS position absolute bottom and align right
“Bottom” and “align right” are basically: use bottom and right. If you want a corner pin,
you often use two offsets (like bottom + right).
.badge {
position: absolute;
bottom: 14px;
left: 14px;
}
.badge {
position: absolute;
top: 14px;
right: 14px;
}
.badge {
position: absolute;
bottom: 14px;
right: 14px;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 980px;
padding: 18px;
font-family: system-ui, Arial, sans-serif;
display: grid;
gap: 12px;
}
.card {
border: 3px solid #111;
border-radius: 18px;
background: #fff;
padding: 18px;
min-height: 240px;
position: relative;
box-shadow: 0 12px 0 #111;
display: grid;
gap: 10px;
align-content: start;
}
.card p {
margin: 0;
max-width: 62ch;
}
.badge {
border: 3px solid #111;
border-radius: 999px;
padding: 8px 12px;
background: #f6f6f6;
font-weight: 900;
width: fit-content;
}
PIN MESame badge, different offsets.
Try each snippet to pin it to different corners.
CSS position absolute center
Centering an absolute element is a rite of passage. There are a few approaches, but two are the most common:
-
Classic transform trick: set
top: 50%andleft: 50%, then pull back by half the element’s size withtransform: translate(-50%, -50%). -
Inset + margin auto: set
inset: 0, give the element a size, then usemargin: auto.
.modal {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.modal {
position: absolute;
inset: 0;
margin: auto;
}
.modal {
position: absolute;
inset: 0;
margin: auto;
}
.stage {
padding: 22px;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 980px;
padding: 18px;
font-family: system-ui, Arial, sans-serif;
}
.stage {
border: 3px solid #111;
border-radius: 18px;
background: #fff;
min-height: 300px;
position: relative;
box-shadow: 0 12px 0 #111;
padding: 18px;
}
.stage p {
margin: 0 0 10px;
max-width: 60ch;
}
.modal {
width: min(360px, 86%);
height: 160px;
border: 3px solid #111;
border-radius: 18px;
background: #f6f6f6;
display: grid;
place-items: center;
font-weight: 900;
}
Two centering methods. The element has a defined size, so inset + margin:auto can work nicely.
CENTERED
Which should you use? The transform trick is super common and doesn’t require a fixed height, but it’s also “math-y.” The inset + margin method is clean, but it expects the element to have a size (otherwise it might stretch).
CSS position absolute center horizontal
To center horizontally, you usually set left: 50% and translate on the X axis only.
.pill {
position: absolute;
top: 16px;
left: 50%;
transform: translateX(-50%);
}
.pill {
position: absolute;
left: 0;
right: 0;
margin: 16px auto 0;
}
.pill {
position: absolute;
inset: 16px 0 auto 0;
margin: 0 auto;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 980px;
padding: 18px;
font-family: system-ui, Arial, sans-serif;
}
.stage {
border: 3px solid #111;
border-radius: 18px;
background: #fff;
min-height: 220px;
position: relative;
box-shadow: 0 12px 0 #111;
padding: 18px;
}
.stage p {
margin: 0;
max-width: 60ch;
}
.pill {
width: 260px;
border: 3px solid #111;
border-radius: 999px;
padding: 10px 12px;
background: #f6f6f6;
font-weight: 900;
text-align: center;
}
Horizontal centering: transform trick or auto margins.
HORIZONTALLY CENTERED
CSS position absolute center vertically
Vertical centering uses the same idea: set top: 50% and translate on the Y axis.
.tag {
position: absolute;
top: 50%;
left: 16px;
transform: translateY(-50%);
}
.tag {
position: absolute;
top: 0;
bottom: 0;
left: 16px;
margin: auto 0;
}
.tag {
position: absolute;
inset: 0 auto 0 16px;
margin: auto 0;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 980px;
padding: 18px;
font-family: system-ui, Arial, sans-serif;
}
.stage {
border: 3px solid #111;
border-radius: 18px;
background: #fff;
min-height: 260px;
position: relative;
box-shadow: 0 12px 0 #111;
padding: 18px;
}
.stage p {
margin: 0;
max-width: 60ch;
}
.tag {
height: 100px;
width: 220px;
border: 3px solid #111;
border-radius: 16px;
padding: 10px 12px;
background: #f6f6f6;
font-weight: 900;
display: grid;
place-items: center;
}
Vertical centering: same idea, different axis.
VERTICALLY CENTERED
Learn more about centering with CSS in the Centering With CSS Interactive Tutorial.
Absolute full-cover overlays
One of the most useful patterns is a full-cover overlay: put something over an element and stretch it to all edges.
The simplest way is inset: 0.
.overlay {
position: absolute;
inset: 0;
}
.overlay {
position: absolute;
inset: 12px;
}
.overlay {
position: absolute;
inset: 0;
}
.overlay {
opacity: 0.55;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
max-width: 980px;
padding: 18px;
font-family: system-ui, Arial, sans-serif;
}
.card {
border: 3px solid #111;
border-radius: 18px;
background: #fff;
min-height: 260px;
position: relative;
overflow: hidden;
box-shadow: 0 12px 0 #111;
}
.media {
position: absolute;
inset: 0;
background: url("https://picsum.photos/1200/700") center / cover no-repeat;
}
.content {
position: relative;
padding: 18px;
display: grid;
gap: 10px;
align-content: end;
min-height: 260px;
color: #111;
}
.content h4 {
margin: 0;
}
.content p {
margin: 0;
max-width: 55ch;
}
.overlay {
background: linear-gradient(180deg, rgba(255, 255, 255, 0.35), rgba(255, 255, 255, 0.95));
}
Overlay pattern
The overlay is absolute and stretches using
inset.
Common mistakes and debugging checklist
-
“My absolute child is positioned weirdly.”
Check if the intended parent has
position: relative(or another non-static value). Without it, the child may use a higher ancestor or the viewport. -
“My layout has a gap / overlap now.”
Remember: absolute elements are out of flow. If you used absolute for something that should still take space, consider flex/grid instead, or keep it in flow.
-
“My element won’t center with margin auto.”
The inset + margin method usually needs the element to have a size. If it stretches, define
widthand/orheight(or use the transform method). -
“My fixed element isn’t fixed.”
Look for ancestors that might create a containing block (commonly transforms). If something is “acting like absolute,” that’s a clue.
-
“z-index isn’t working.”
Ensure the element is positioned (or otherwise eligible) and consider stacking contexts. As a starter, try putting
position: relativeon siblings and then setz-index.
Quick cheat sheet: position absolute
-
Anchor to parent: parent
position: relative, childposition: absolute -
Pin bottom-right:
bottom: 0+right: 0 -
Full overlay:
inset: 0 -
Center (classic):
top: 50%,left: 50%,transform: translate(-50%, -50%) -
Center (inset + auto):
inset: 0,margin: auto, plus a size
