Line-height and Vertical-align are simple CSS properties, so that most people think they know how these two properties work. But in fact these two properties are very complex, perhaps the most difficult two properties of CSS, because these two properties and CSS in a little-known feature is closely Related: inline format context (IFC), this article and you share CSS Line-height and The use of vertical-align, hope to help everyone.
For example, the value of line-height can be a length or a number, and its default value is normal. So, what is normal? We often interpret normal as 1, or 1.2, even if the CSS specification does not refer to this issue. We know that the value of Line-height is a number, which is expressed as a multiple of font-size, but the problem is that the font-size:100px corresponding text in different font height is not the same! So will the line-height change with the size of the text? Does normal mean 1 or 1.2? How is vertical-align influenced by line-height?
Let's take a closer look at a less simple CSS mechanism.
Font-size
Here is a simple HTML code, a P tag containing 3 span tags, each with a font-family:
<p> <span class= "a" >Ba</span> <span class= "B" >Ba</span> <span class= "C" >Ba</span></p>
P {font-size:100px}.a {font-family:helvetica}.b {Font-family:gruppo }.c {Font-family:catamaran}
(Translator Note: These fonts may not be on your computer)
Font-size the same, font-family different, the height of the resulting span element is also different:
Why can't font-size:100px get the same height elements? I measured the height of each span: Helvetica 115px,gruppo 97px,catamaran 164px.
At first glance it's strange, but think about it and it makes sense. The reason is the font itself, which is the principle of the font:
A word experience defines a em-square, which is a metal container used to hold characters. This em-square is generally set to a width of 1000 relative units, but can also be 1024, 2048 relative units.
Font metrics are set based on this relative unit, including Ascender, descender, capital height, x-height, and so on. Note that the value in this area is allowed relative to the Em-square bleed (Bleed Outside) (the translator note: Presumably can be understood as exceeding Em-square)
We put the catamaran font in the FontForge and analyzed its font metrics:
Em-square is 1000.
Ascender is 1100,descender is 540. The tests found that browsers on MacOS used Hhead Ascent and Hhead descent values, and the browser on Windows used win Ascent and win descent (and the values on the two platforms were different). We also see that the capital height is 680,x height is 485.
This means that the catamaran font occupies 1100 + 540 relative units, although its em-square has only 1000 relative units, so when we set font-size:100px, the text height in this font is 164PX. This calculated height determines the Content-area (content area) of the HTML element, and I'll talk about Content-area later. You can think of Content-area as the area where background function.
We can also see that the height of the capital letter is 68px, and the lowercase letter height (x-height) is 49px. So 1ex = 49px,1em = 100px, not 164px. (It's good that EM is based on font-size, not calculated height)
Before you go any further, say something about the relevant knowledge. When the P element appears on the screen, it may contain multiple lines of content, each consisting of multiple inline elements (inline tags or anonymous inline elements that contain text), and each line is called a line-box. the height of the line-box is calculated by the height of all its child elements . The browser calculates the height of each child element in the line, and then the height of the Line-box (specifically, from the highest point of the child element to the height of the lowest), so by default, a Line-box always has enough height to accommodate its child elements.
each HTML element is actually a container of multiple line-box, and if you know the height of each line-box, then you know the height of the entire element.
If we modify the original HTML code:
<p> Good design would be better. <span class= "A" >Ba</span> <span class= "B" >Ba</span> <span class= "C" >ba</ Span> We get to make a consequence.</p>
Then you will get 3 line-box (fixed width):
We see clearly that the second line-box is a little higher than the other two. Because the child element in the second line has a span that uses the catamaran font.
The difficulty with Line-box is that we can't see it, and we can't control it with CSS. Even if we use: First-line to add a background color to the first line, we don't see the height of the first line-box.
Line-height
At the moment I have mentioned two concepts: Content-area and Line-box. If you look closely, you will find that I say that the height of the line-box is calculated from the height of the child element, not the height of the content-area of the child element. This is a big difference.
The next thing that sounds strange: an inline element has two heights: Content-area height and Virtual-area (actual area?). ) Height (Virtual-area is my own invention of the word, it means that the height of the human being effective, you can not see the word in other places).
The height of the content-area is defined by the font metrics (see above)
The height of the Vitual-area is Line-height, which is used to calculate the height of the Line-box
This, in this way, breaks a long-standing rumor: Line-height represents the distance between two baseline. In CSS, this is not the case.
The difference between Virtual-area and Content-area height is called leading. Half of the leading will be added to the top of the Content-area and the other half will be added to the bottom. So Content-area is always in the middle of Virtual-area.
The calculated Line-height (that is, the height of the Virtual-area) can be equal to, greater than, or less than Content-area. If Virtual-area is less than Content-area, then leading is negative, so line-box looks shorter than content.
There are some other kinds of inline elements:
Replaceable inline elements, such as Img/input/svg
The Inline-block element, and all the display values that begin with inline-, such as Inline-table/inline-flex
Inline elements in a particular formatting context, such as child elements in the Flexbox element, are in the Flex formatting context (elastic formatting contexts), and the display values of those child elements are "blockified"
This type of inline element, whose height is based on height, margin, and border properties (Translator Note: Seems to have leaked padding). If you set its height to auto, the value of its altitude is line-height, and its Content-area value is line-height.
We are still not explaining what line-height:normal means. To answer this question, we have to go back to the Content-area height calculation, the answer to the question is in the font metric.
We go back to Fontforge,catamaran's em-square height is 1000, and we also see a lot of other ascender/descender values:
The general Ascent/descent:ascender is 770,descender is 230, which is used to render characters.
Specification Ascent/descent:ascender is 1100,descender is 540. Used to calculate the height of the Content-area
Spec line Gap: Used to calculate line-height:normal.
In catamaran this font, the value of line Gap is 0, then the line-height:normal result is the same as the height of Content-area, is 1640 relative units.
In order to compare, we look at the Arial font, its em-square is 2048,ascender is 1854,descender is 434,line Gap is 67. So when font-size:100px,
The height of its content-area is 100/2048* (1854+434) = 111.72, about 112px;
The result of its line-height:normal is that 100/2048* (67+1854+434) is about 115px.
All of these values are set by the font designer.
So, line-height:1 is a bad practice. Remember, when the value of Line-height is a number, it is actually a multiple of the relative font-size, not relative to Content-area. So line-height:1 is likely to make virtual-area shorter than Content-area, causing a lot of other problems.
Not only line-height:1 have problems, my computer on the 1117 fonts, about 1059 fonts line-height than 1, the lowest is 0.618, the highest is 3.378. You're not mistaken, it's 3.378!
Some details of the Line-box calculation:
For inline elements, padding and border increase the background area, but do not increase the content-area (not the height of the Line-box). Generally you can no longer see content-area on the screen. Margin-top and Margin-bottom have no effect on either of them.
For replaceable inline elements (replaced inline elements), inline-block elements, and blockified inline elements, padding, margin, and border increase the height (translator Note: note margin), So it affects the heights of Content-area and Line-box.
Vertical-align
I haven't mentioned it yet. Vertical-align property, which is also one of the important factors in calculating line-box height. We can even say that vertical-align is the most important attribute in the inline formatting context (IFC).
Its default value is baseline. Remember the Ascender and descender in the font metrics? These two values determine the location of the baseline. Few have
The ratio of Ascender and Descender is 1:1, so we often see some unexpected phenomena, here is an example.
The code is as follows:
<p> <span>Ba</span> <span>Ba</span></p>
p { Font-family:catamaran; font-size:100px; line-height:200px;}
A P tag has two span tags, and span inherits the line-height of Font-family, Font-size, and 200px. At this time the baseline of two spans is equal, and the height of Line-box is the line-height of span.
What if the font-size of the second span becomes smaller?
span:last-child { font-size:50px;}
We will find a very strange phenomenon, the height of the Line-box has become higher! As shown in. To remind you, the height of the Line-box is an example from the highest to lowest point of the child element.
This example can be used as an argument for "line-height values should be written as numbers," but sometimes we have to write line-height as a fixed value in order to make good typography.
But let me tell you the truth, whether you put Line-height
What you write, you'll get into trouble when aligning the inline elements.
Let's look at another example. The P tag has a line-height:200px and contains a span,span that inherits the P Line-height.
<p> <span>Ba</span></p>
p { line-height:200px;} span { Font-family:catamaran; font-size:100px;}
What is the height of the line-box at this time? It looks like 200px, but it's not really. The problem you don't consider here is that P has its own font-family, and the default value is serif. P's baseline and span have different baseline positions, so the final line-box is a little higher than we expected. This problem occurs because the browser considers each Line-box to have a character with a width of 0 (which the CSS document calls strut) and incorporates it into the calculation of the height of the line-box.
Invisible
character, visible influence.
To illustrate the problem, let's draw a picture to explain the problem.
Using baseline to align is puzzling, if we use vertical-align:middle will be better? Reading a CSS document you will find that middle means "to align the midpoint in the vertical direction of the current element with the parent element baseline height plus half the height of x-height in the parent element." The height of the baseline is related to the font, the height of the x-height is also related to the font, so middle alignment is not reliable. Worse, in general, middle is not centered at all! The alignment of inline elements is affected by too many factors, so it is not possible to implement them in CSS.
By the way, the other 4 values of vertical-align may be somewhat used:
Vertical-align:top/bottom, indicating the top or bottom alignment with the Line-box
Vertical-align:text-top/text-bottom, indicating the top or bottom alignment with the Content-area
But you still have to be careful, in most cases, the alignment is Virtual-area, which is an invisible height. Take a look at the following example with Vertical-align:top:
Finally, the value of the vertical-align can also be a number, indicating that according to baseline rise or fall, less than the last resort or not to use the number bar.
CSS is awesome
We discussed line-height and vertical-align if they interact with each other, now the problem is: can CSS control font metrics? In short, the answer is: No. I also want to use CSS to control the font. Anyway, I'd like to try it. Font metrics are just a few fixed values, and we should be able to do something around it.
For example, we want a piece of text to use the catamaran font, and the height of the uppercase letter is exactly 100px, it seems to be possible, we only need some mathematical knowledge.
First we set all font metrics to CSS custom properties, and then we calculate a font-size, so that the height of the uppercase is exactly 100px.
p {/ * font metrics */ --font:catamaran; --fm-capitalheight:0.68; --fm-descender:0.54; --fm-ascender:1.1; --fm-linegap:0; /* Desired font-size for capital Height */ --capital-height:100; /* Apply font-family * /Font-family:var (--font); /* Compute font-size to get capital height equal desired font-size * /--computedfontsize: (Var (--capital-height)/VA R (--fm-capitalheight)); Font-size:calc (VAR (--computedfontsize) * 1px);}
It's not that complicated, is it? What if we want the text to be centered vertically? This means that the space above B is the same height as the space below. To do this, we have to calculate the vertical-align according to the ratio of ascender and descender.
First calculate the value of the line-height:normal and the height of the Content-area:
P { ... --lineheightnormal: (Var (--fm-ascender) + var (--fm-descender) + var (--fm-linegap)); --contentarea: (Var (--lineheightnormal) * VAR (--computedfontsize));}
Then we need to calculate:
Height of space under B
B height of Upper space
Like this:
P { ... --distancebottom: (Var (--fm-descender)); --distancetop: (Var (--fm-ascender)-VAR (--fm-capitalheight));}
Then we can calculate the value of the vertical-align.
P { ... --valign: ((Var (--distancebottom)-VAR (--distancetop)) * VAR (--computedfontsize));} span { Vertical-align:calc (var (--valign) * -1px);}
Finally, set the Line-height:
P { ... /* Desired line-height */ --line-height:3; Line-height:calc (((Var (--line-height) * VAR (--capital-height))-VAR (--valign)) * 1px);}
Adding an icon as high as B is easy:
Span::before { content: '; Display:inline-block; Width:calc (1px * VAR (--capital-height)); Height:calc (1px * VAR (--capital-height)); margin-right:10px; Background:url (' https://cdn.pbrd.co/images/yBAKn5bbv.png '); Background-size:cover;}
JSBin Effect Demo
Note that this is only for demonstration purposes, do not use this scenario in a production environment.
Conclusion
We know this: