Imagine this: you're building a card that needs multiple elements stacked on each other. You instinctively reach for position: absolute, throw in some top: 0, left: 0, maybe a z-index or two. You get where I'm going with this.
While position: absolute does have its place and is useful when you want an element to defy the flow of the document, what if I told you there's a more elegant approach to stacking using CSS Grid?
Yeah, I know. Show me.
The Old Way: Position Absolute
Here's a typical card component built with position absolute:
HTML:
html
<div class="card-absolute">
<img
class="card-absolute__image"
src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4"
alt="Mountain landscape"
/>
<div class="card-absolute__overlay"></div>
<div class="card-absolute__content">
<h2>Mountain Adventures</h2>
<p>Explore breathtaking peaks and valleys</p>
</div>
<div class="card-absolute__badge">Featured</div>
</div>
CSS:
css
.card-absolute {
position: relative;
width: 400px;
height: 500px;
border-radius: 16px;
overflow: hidden;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}
.card-absolute__image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
z-index: 0;
}
.card-absolute__overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(
to bottom,
rgba(0, 0, 0, 0.2),
rgba(0, 0, 0, 0.8)
);
z-index: 1;
}
.card-absolute__content {
position: absolute;
bottom: 32px;
left: 32px;
right: 32px;
z-index: 2;
color: white;
}
.card-absolute__content h2 {
margin: 0 0 12px 0;
font-size: 28px;
font-weight: 700;
}
.card-absolute__content p {
margin: 0;
font-size: 16px;
opacity: 0.9;
}
.card-absolute__badge {
position: absolute;
top: 24px;
right: 24px;
background: rgba(255, 255, 255, 0.95);
padding: 8px 16px;
border-radius: 24px;
font-size: 14px;
font-weight: 600;
z-index: 3;
}
This works, but notice the problems:
- Repetitive positioning: Every element needs position: absolute, top: 0, left: 0, width: 100%, height: 100%
- Z-index management: You have to manually track which layer goes where
- No semantic structure: The HTML doesn't communicate that these elements are stacked
- Verbose code: So much boilerplate for what should be simple
The Better Way: CSS Grid
Now let's see the same card using CSS Grid:
HTML:
html
<div class="card-grid">
<img
class="card-grid__image"
src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4"
alt="Mountain landscape"
/>
<div class="card-grid__overlay"></div>
<div class="card-grid__content">
<h2>Mountain Adventures</h2>
<p>Explore breathtaking peaks and valleys</p>
</div>
<div class="card-grid__badge">Featured</div>
</div>CSS:
css
.card-grid {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
width: 400px;
height: 500px;
border-radius: 16px;
overflow: hidden;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}
/* All children stack in the same grid cell */
.card-grid > * {
grid-column: 1;
grid-row: 1;
}
.card-grid__image {
width: 100%;
height: 100%;
object-fit: cover;
}
.card-grid__overlay {
background: linear-gradient(
to bottom,
rgba(0, 0, 0, 0.2),
rgba(0, 0, 0, 0.8)
);
}
.card-grid__content {
align-self: end;
padding: 32px;
color: white;
}
.card-grid__content h2 {
margin: 0 0 12px 0;
font-size: 28px;
font-weight: 700;
}
.card-grid__content p {
margin: 0;
font-size: 16px;
opacity: 0.9;
}
.card-grid__badge {
justify-self: end;
align-self: start;
background: rgba(255, 255, 255, 0.95);
padding: 8px 16px;
border-radius: 24px;
font-size: 14px;
font-weight: 600;
margin: 24px;
}
Much cleaner! But how does it actually work?
How It Works
The magic is surprisingly simple:
1. Create a Single-Cell Grid
css
.card {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
}
This creates a grid with exactly one column and one row. That single cell will be the size of the container.
2. Place All Children in the Same Cell
css
.card > * {
grid-column: 1;
grid-row: 1;
}
By placing all children in column 1, row 1, they naturally stack on top of each other. The stacking order follows the DOM order—later elements appear on top.
3. Use Grid Alignment Instead of Positioning
Here's where it gets really nice:
css
/* Position at bottom */
.content {
align-self: end;
}
/* Position at top-right */
.badge {
justify-self: end;
align-self: start;
}
/* Center something */
.overlay-icon {
justify-self: center;
align-self: center;
}
No more calculating pixel positions. Just tell Grid where you want it aligned.
Why CSS Grid Wins
1. Less Boilerplate
No more repetitive position: absolute, top: 0, left: 0, width: 100%, height: 100% on every element.
2. No Z-Index Wrestling
Stacking order follows document order. Want something on top? Put it later in the HTML. Simple.
3. Better Alignment
Use justify-self and align-self instead of pixel-pushing with top/left/right/bottom values.
4. More Semantic
The grid structure communicates intent: "these elements are meant to stack."
5. Responsive Friendly
Grid's alignment properties adapt to different container sizes without recalculating positions.
6. Stays in Flow
Elements remain in the document flow, which plays nicer with accessibility tools and makes the structure more predictable.
When to Still Use Position Absolute
To be fair, position: absolute still has its place:
- Breaking out of containers: When you need an element to overflow its parent
- Complex positioning: When you need precise pixel control relative to multiple reference points
- Tooltips and popovers: Elements that need to float above the layout
- Animations: When you need to animate elements out of flow
But for basic stacking? Grid is your friend.
Real-World Example: A Hero Section
Here's a more complex example showing how Grid stacking shines in a hero section:
HTML:
html
<section class="hero">
<video class="hero__video" autoplay loop muted playsinline>
<source src="/hero-video.mp4" type="video/mp4">
</video>
<div class="hero__overlay"></div>
<div class="hero__content">
<h1>Build Something Amazing</h1>
<p>The modern approach to web development</p>
<button class="hero__cta">Get Started</button>
</div>
<div class="hero__decoration"></div>
</section>CSS:
css
.hero {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
min-height: 600px;
}
/* Stack all children in the same cell */
.hero > * {
grid-column: 1;
grid-row: 1;
}
.hero__video {
width: 100%;
height: 100%;
object-fit: cover;
}
.hero__overlay {
background: rgba(0, 0, 0, 0.4);
}
.hero__content {
align-self: center;
justify-self: center;
text-align: center;
color: white;
max-width: 800px;
padding: 0 32px;
}
.hero__content h1 {
font-size: clamp(40px, 8vw, 72px);
font-weight: 800;
margin: 0 0 24px 0;
line-height: 1.1;
}
.hero__content p {
font-size: 20px;
margin: 0 0 40px 0;
opacity: 0.95;
}
.hero__cta {
padding: 16px 48px;
font-size: 18px;
font-weight: 600;
background: white;
color: #000;
border: none;
border-radius: 12px;
cursor: pointer;
}
.hero__decoration {
justify-self: start;
align-self: end;
width: 200px;
height: 200px;
background: linear-gradient(
135deg,
rgba(255, 255, 255, 0.1),
rgba(255, 255, 255, 0)
);
border-radius: 50%;
margin: 40px;
filter: blur(40px);
}Clean, readable, and easy to adjust. No position absolute in sight.
The Bottom Line
Next time you need to stack elements, ask yourself: "Am I stacking in place, or breaking out of the layout?"
- Stacking in place? Use CSS Grid
- Breaking out? Use position absolute
Your code will thank you. Your future self will thank you. And honestly, Grid is just more fun to work with.
Now go forth and stack beautifully. 🎨
What's your favorite CSS trick that feels like a superpower? Let me know in the comments!
