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;
}
  
ABSOLUTE

Normal 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.

  • top moves it down from the top edge.
  • right moves it left from the right edge.
  • bottom moves it up from the bottom edge.
  • left moves 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: relative keeps the element in normal flow, but lets you nudge it with offsets. It also creates a positioning context for absolute children.
  • position: absolute removes 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;
}
  
NEW

This 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.

CHILD

Parent B

Just here for comparison.

CSS position: absolute vs position: fixed

Both take elements out of flow, but they attach to different “reference frames”.

  • absolute positions relative to a containing block (often a positioned ancestor).
  • fixed positions 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;
}
  
A
B

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 ME

Same 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% and left: 50%, then pull back by half the element’s size with transform: translate(-50%, -50%).
  • Inset + margin auto: set inset: 0, give the element a size, then use margin: 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.

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 width and/or height (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: relative on siblings and then set z-index.

Quick cheat sheet: position absolute

  • Anchor to parent: parent position: relative, child position: 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