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.