CSS course menu
CSS position: static, relative, absolute, fixed and sticky Explained
Learn CSS positioning with live examples: static, relative, absolute (and the containing block), fixed and sticky, the top, right, bottom, left and inset properties, and common patterns such as badges, overlays and sticky headers.
Normally the browser places elements one after another in normal flow. The position property lets you move elements from where they would normally be, or take them out of the flow entirely.
The offsets are set with top, right, bottom and left, or the shorthand inset (inset: 0 means all four are 0).
relative#
.box { display: inline-block; width: 90px; padding: 16px 0; text-align: center; background: #cfe3ff; margin: 4px; }
.moved { position: relative; top: 20px; left: 30px; background: #ffd34d; }<div class="box">1</div>
<div class="box moved">2 (moved)</div>
<div class="box">3</div>Box 2 moves 20px down and 30px right, but its original space stays reserved: box 3 does not move into it. On its own, relative is mostly used for small nudges, but it has a much more important job: making an element the reference point for absolutely positioned children.
absolute#
An absolutely positioned element is removed from the normal flow (other elements act as if it is not there) and placed relative to its nearest ancestor whose position is not static:
.card {
position: relative; /* the reference point */
width: 220px;
padding: 16px;
border: 1px solid #ccc;
border-radius: 10px;
}
.badge {
position: absolute;
top: -10px;
right: -10px;
background: crimson;
color: white;
padding: 2px 8px;
border-radius: 999px;
font-size: 13px;
}<div class="card">
<span class="badge">New</span>
<h3>CSS Grid course</h3>
<p>Learn two-dimensional layouts.</p>
</div>Without position: relative on .card, the badge would be positioned relative to the whole page. This relative parent, absolute child pattern is used for badges, close buttons, captions on images and dropdown menus.
Covering a parent#
inset: 0 stretches an absolute element over its positioned parent, which is the standard way to make an overlay:
.photo {
position: relative;
width: 300px;
height: 160px;
background: url("/lesson-assets/landscape-600.svg") center / cover;
}
.overlay {
position: absolute;
inset: 0;
background: rgb(0 0 0 / 0.45);
color: white;
display: grid;
place-items: center;
font: 600 20px system-ui, sans-serif;
}<div class="photo"><div class="overlay">Sold out</div></div>fixed#
A fixed element is positioned relative to the viewport and stays in place when the page scrolls, which is useful for chat buttons, cookie banners and "back to top" links:
.chat-button {
position: fixed;
right: 20px;
bottom: 20px;
}Fixed elements cover whatever scrolls beneath them, so make sure they never hide important content, especially on small screens.
sticky#
A sticky element behaves normally until it would scroll past the offset you set; then it sticks there, but only while its parent container is still visible:
body { margin: 0; font-family: system-ui, sans-serif; }
h3 {
position: sticky;
top: 0;
margin: 0;
padding: 8px 12px;
background: #1d3b4f;
color: white;
}
p { margin: 0; padding: 8px 12px; height: 120px; }<section><h3>A</h3><p>Asha, Arjun, Anil...</p></section>
<section><h3>B</h3><p>Bhavna, Bala...</p></section>
<section><h3>C</h3><p>Chitra, Chetan...</p></section>Scroll inside the result: each letter heading sticks to the top until its section ends and the next heading pushes it away. Sticky needs a threshold (top, bottom and so on), and it stops working if an ancestor between it and the scrolling area has overflow: hidden.
Practice#
Practice exercise
Create a product image card (use /lesson-assets/landscape-300.svg) with a "−20%" label in the top-left corner, 8px from each edge, and a heart button in the top-right corner, 8px from each edge.
Show solution
.product { position: relative; width: 300px; }
.product img { display: block; width: 100%; height: auto; border-radius: 10px; }
.discount {
position: absolute; top: 8px; left: 8px;
background: #2f9e44; color: white; padding: 2px 8px; border-radius: 6px; font-weight: bold;
}
.like {
position: absolute; top: 8px; right: 8px;
width: 36px; height: 36px; border: none; border-radius: 50%; background: white; font-size: 18px;
}<div class="product">
<img src="/lesson-assets/landscape-300.svg" alt="Framed landscape print" width="300" height="200">
<span class="discount">−20%</span>
<button class="like" type="button" aria-label="Add to wishlist">♡</button>
</div>Key takeaway#
Finished this lesson?