Ref: https://www.w3.org/TR/CSS2/visudet.html#line-height
To understand this you need to first consider the definition of text-top
:
The following values only have meaning with respect to a parent inline element, or to the strut of a parent block container element.
In the following definitions, for inline non-replaced elements, the box used for alignment is the box whose height is the 'line-height' (containing the box's glyphs and the half-leading on each side, see above).
Then
text-top
Align the top of the box with the top of the parent's content area
So we need to identify the top of the box and the top of the parent's content area
If we add some decorations, we can easily identify them
body {
font-family: sans-serif;
font-size: 30px;
}
p {
background: yellow;
line-height: 50px;
background:
linear-gradient(blue,blue) 0 7px/100% 2px no-repeat
yellow;
}
p span {
background:green;
}
.three {
vertical-align: text-top;
background:red;
}
.block {
display: inline-block;
width: 20px;
height: 20px;
background: pink;
border: 2px solid black;
vertical-align: text-top;
}
<div>
<p><span class="one">I'm</span> <span class="two">on the</span> <span class="three">yellow</span> <span>background</span> <span class="block"></span></p>
</div>
The green coloration define the content area and we can clearly see that the square is aligned with that top. Until now it's trivial.
The tricky case is the text because we see that the red doesn't align with the green. This is due to the line-height
. In the above it's said that we consider the box whose height is the line-height
and we know that line-height
is inherited so our span (the red one) will inherit the 50px line-height and this is our reference for the alignment.
Which is more tricky is that even if we change the line-height, the content area doesn't change (the red coloration will always stay the same)
The 'height' property does not apply. The height of the content area should be based on the font
and
The vertical padding, border and margin of an inline, non-replaced box start at the top and bottom of the content area, and has nothing to do with the 'line-height'. But only the 'line-height' is used when calculating the height of the line box.
To make it easy, imagine the text inside an invisible box with a height equal to 50px
and this box is aligned at the top of the parent content area then inside that box you have your text and the background coloration will only cover the content area whataver the line-height.
If you use a line-height
equal to the content area you will have a perfect alignment:
body {
font-family: sans-serif;
font-size: 30px;
}
p {
background: yellow;
line-height: 50px;
background:
linear-gradient(blue,blue) 0 7px/100% 2px no-repeat
yellow;
}
p span {
background:green;
}
.three {
vertical-align: text-top;
background:red;
line-height:33px;
}
.block {
display: inline-block;
width: 20px;
height: 20px;
background: pink;
border: 2px solid black;
vertical-align: text-top;
}
<div>
<p><span class="one">I'm</span> <span class="two">on the</span> <span class="three">yellow</span> <span>background</span> <span class="block"></span></p>
</div>
Increase the line-height
and you will have a bigger invisible box and the text will move more down:
body {
font-family: sans-serif;
font-size: 30px;
}
p {
background: yellow;
line-height: 50px;
background:
linear-gradient(blue,blue) 0 7px/100% 2px no-repeat
yellow;
}
p span {
background:green;
}
.three {
vertical-align: text-top;
background:red;
line-height:100px;
}
.block {
display: inline-block;
width: 20px;
height: 20px;
background: pink;
border: 2px solid black;
vertical-align: text-top;
}
<div>
<p><span class="one">I'm</span> <span class="two">on the</span> <span class="three">yellow</span> <span>background</span> <span class="block"></span></p>
</div>
And logically with a small line-height, it will go up:
body {
font-family: sans-serif;
font-size: 30px;
}
p {
background: yellow;
line-height: 50px;
background:
linear-gradient(blue,blue) 0 7px/100% 2px no-repeat
yellow;
}
p span {
background:green;
}
.three {
vertical-align: text-top;
background:red;
line-height:1px;
}
.block {
display: inline-block;
width: 20px;
height: 20px;
background: pink;
border: 2px solid black;
vertical-align: text-top;
}
<div>
<p><span class="one">I'm</span> <span class="two">on the</span> <span class="three">yellow</span> <span>background</span> <span class="block"></span></p>
</div>
If you change the display to inline-block
you will better see the issue because the coloration will cover the whole area defined by line-height
body {
font-family: sans-serif;
font-size: 30px;
}
p {
background: yellow;
line-height: 50px;
background:
linear-gradient(blue,blue) 0 7px/100% 2px no-repeat
yellow;
}
p span {
background:green;
}
.three {
vertical-align: text-top;
background:red;
display:inline-block;
}
.block {
display: inline-block;
width: 20px;
height: 20px;
background: pink;
border: 2px solid black;
vertical-align: text-top;
}
<div>
<p><span class="one">I'm</span> <span class="two">on the</span> <span class="three">yellow</span> <span>background</span> <span class="block"></span></p>
</div>
And with more element we can better illustrate our invisible box:
body {
font-family: sans-serif;
font-size: 30px;
}
p {
background: yellow;
line-height: 50px;
background:
linear-gradient(blue,blue) 0 7px/100% 2px no-repeat
yellow;
}
p span {
background:green;
}
.three {
vertical-align: text-top;
outline:1px solid blue;
background:transparent;
display:inline-block;
}
.three > span {
background:red;
}
.block {
display: inline-block;
width: 20px;
height: 20px;
background: pink;
border: 2px solid black;
vertical-align: text-top;
}
<div>
<p><span class="one">I'm</span> <span class="two">on the</span> <span class="three"><span>yellow</span></span> <span>background</span> <span class="block"></span></p>
</div>
<div>
<p><span class="one">I'm</span> <span class="two">on the</span> <span class="three" style="line-height:100px"><span>yellow</span></span> <span>background</span> <span class="block"></span></p>
</div>
<div>
<p><span class="one">I'm</span> <span class="two">on the</span> <span class="three" style="line-height:1px"><span>yellow</span></span> <span>background</span> <span class="block"></span></p>
</div>
vertical-align: text-top;
Aligns the top of the element with the top of the parent element's font. – Rob Moll