vertical-align in layout
vertical-align is one of CSS's most misunderstood properties. It only works on inline and inline-block elements (not block elements), and it aligns elements relative to the text baseline of their line. For block-level layout, use flexbox or grid instead. Vertical-align is useful for aligning icons with text, images in text, and inline-block elements on the same line.
What vertical-align does (and doesn't)
Works on | Does NOT work on | Aligns relative to |
|---|---|---|
Inline elements | Block elements | Text baseline of line |
Inline-block elements | Floats | Text baseline of line |
Table cells | Positioned elements | Cell content area |
(for table-cell display only) |
/* vertical-align WORKS on inline/inline-block */
span {
display: inline;
vertical-align: middle; /* works */
}
button {
display: inline-block;
vertical-align: top; /* works */
}
/* vertical-align DOESN'T work on block */
div {
display: block;
vertical-align: middle; /* ignored */
}
/* Use flexbox for block alignment instead */
div {
display: flex;
align-items: center; /* this is how to vertically center blocks */
}Baseline, top, middle, bottom
These are the main vertical-align values. They position the element relative to the line it's on.
<!-- Text line with different vertical alignments -->
Some text <span class="baseline">baseline</span> more text
Some text <span class="top">top</span> more text
Some text <span class="middle">middle</span> more text
Some text <span class="bottom">bottom</span> more text
/* Baseline — aligns to baseline of text (default) */
.baseline {
display: inline;
vertical-align: baseline;
/* Aligned to bottom of lowercase letters */
}
/* Top — aligns top of element to top of line */
.top {
display: inline;
vertical-align: top;
/* Element sits at the top of the line */
}
/* Middle — aligns to middle of line */
.middle {
display: inline;
vertical-align: middle;
/* Roughly centers vertically (not exact) */
}
/* Bottom — aligns bottom to baseline */
.bottom {
display: inline;
vertical-align: bottom;
/* Element bottom touches the baseline */
}The baseline mystery
Baseline alignment causes gaps under images and inline elements. This is because images (like text) align to the baseline of the line, not the bottom of the line.
<!-- Image in text creates gap -->
<p>
Text <img src="icon.png" alt="icon"> more text
</p>
img {
/* Default: vertical-align: baseline */
/* Image baseline aligns with text baseline */
/* Extra space below image (the descender space) */
}
<!-- Visual -->
[Text] [Image] [More text]
[gap here]
<!-- Solutions -->
/* Solution 1: Change vertical-align */
img {
vertical-align: middle; /* or top, bottom */
}
/* Solution 2: Make image block */
img {
display: block;
/* No longer inline, doesn't align to baseline */
}
/* Solution 3: Remove line-height */
p {
line-height: 0;
}
/* Solution 4: Negative margin */
img {
margin-bottom: -4px; /* move image down */
}Inline-block alignment
Inline-block elements align to the baseline by default. When multiple inline-block elements are on the same line, use vertical-align to align them.
<!-- Multiple inline-block elements -->
<button>Button 1</button>
<button>Button 2</button>
<button>Button 3</button>
.button {
display: inline-block;
/* Default: vertical-align: baseline */
/* Buttons sit on same baseline */
}
<!-- Alignment options -->
.button {
display: inline-block;
vertical-align: top; /* all sit at top of line */
}
/* or */
.button {
display: inline-block;
vertical-align: middle; /* roughly centered */
}
<!-- Better for buttons: use flex -->
.button-group {
display: flex;
gap: 10px;
}
.button {
display: inline-block;
/* flex handles alignment */
}Icons aligned with text
A common use case: align an icon next to text.
<!-- Icon and text -->
<a href="#">
<svg class="icon"><!-- icon --></svg>
Link text
</a>
<!-- Problem: icon sits on baseline -->
[Icon] Link text
[gap]
<!-- Solution: vertical-align -->
.icon {
display: inline-block;
vertical-align: middle;
/* or use top, depending on preference */
margin-right: 8px;
}
Result:
[Icon] Link text (roughly centered)
<!-- Modern solution: flex -->
a {
display: flex;
align-items: center;
gap: 8px;
}
.icon {
width: 16px;
height: 16px;
/* flex handles alignment */
}Table-cell alignment (display: table-cell)
When you set display: table-cell, vertical-align works to center content within the cell's height.
<!-- Vertically centered with table-cell (legacy approach) -->
<div class="centered">Centered content</div>
.centered {
display: table-cell;
width: 200px;
height: 200px;
vertical-align: middle;
text-align: center;
/* Content is vertically centered */
}
Result:
[─────────────────]
[ Centered ]
[ content ]
[─────────────────]
<!-- Modern solution: flex (better) -->
.centered {
display: flex;
align-items: center;
justify-content: center;
width: 200px;
height: 200px;
/* Content is vertically and horizontally centered */
/* Better browser support and more flexible */
}When to use vertical-align
<!-- GOOD: Icon aligned with inline text -->
.icon-button {
display: inline-block;
vertical-align: middle;
}
<!-- GOOD: Inline elements on same baseline -->
.pill-badge {
display: inline-block;
vertical-align: top;
}
<!-- BAD: Use flex instead -->
.header {
display: block;
vertical-align: center; /* doesn't work, use flex */
}
/* Better */
.header {
display: flex;
align-items: center;
}
<!-- BAD: Use grid/flex instead -->
.container {
height: 300px;
vertical-align: middle; /* doesn't work on blocks */
}
/* Better */
.container {
height: 300px;
display: flex;
align-items: center;
}
/* or */
.container {
height: 300px;
display: grid;
place-items: center;
}Numeric values with vertical-align
You can use pixel or percentage values to fine-tune alignment relative to the baseline.
/* Pixel offset */
.shift-up {
display: inline-block;
vertical-align: -5px; /* move up 5px */
}
.shift-down {
display: inline-block;
vertical-align: 5px; /* move down 5px */
}
/* Percentage of line-height */
.shift-percent {
display: inline-block;
vertical-align: 25%; /* 25% of line-height up */
}
<!-- Common use: shift superscript/subscript -->
<span>x<sup class="superscript">2</sup></span>
.superscript {
display: inline-block;
vertical-align: 0.5em;
font-size: 0.8em;
}