Why It Happens
The default value of align-items is stretch. This makes all flex children fill the container's cross-axis (height in a row layout). It's intentional — equal-height columns are a useful default — but often unexpected.
.container {
display: flex;
/* align-items: stretch; ← this is the hidden default */
}
.child {
/* Height is determined by the tallest sibling, not by content */
}
The Fix
/* Override the default */
.container {
display: flex;
align-items: flex-start; /* items align to top, use their natural height */
}
/* Other align-items values */
align-items: flex-end; /* align to bottom */
align-items: center; /* vertically centered */
align-items: baseline; /* align text baselines */
align-items: stretch; /* default — fill cross-axis */
Per-Item Fix with align-self
/* Override for a specific item only */
.container {
display: flex;
align-items: stretch; /* most items stretch */
}
.special-item {
align-self: flex-start; /* this one doesn't */
}
/* Equal height cards but with align-self on inner content */
.card {
display: flex;
flex-direction: column;
}
.card-footer {
margin-top: auto; /* pushes footer to bottom of card */
}
Height & Flex Gotchas
/* Images stretching in flex containers */
.gallery { display: flex; gap: 8px; }
.gallery img {
/* ❌ Image is stretched because of align-items: stretch */
/* ✅ Fix 1: */
align-self: flex-start;
/* ✅ Fix 2: */
object-fit: cover;
height: 200px; /* fixed height */
}
/* Or on container */
.gallery { display: flex; align-items: flex-start; }
/* 100% height children in a flex container */
.container { display: flex; height: 500px; }
.child { flex: 1; } /* flex: 1 makes it fill available width */
/* Height fills automatically because of align-items: stretch */
💡 Equal height columns: The default
align-items: stretch is actually perfect for card grids where you want all cards the same height. Keep the default and use flex-direction: column on the card itself to push the footer down.