Deep understanding of line-height and vertical-align

Deep understanding of line-height and vertical-align

Several concepts

  • Line box: A box that wraps an inline box. One or more line boxes are stacked to support an HTML element.
  • inline(-level) box: It can be a box wrapped by an inline element or an anonymous box containing only text.
  • content area: For non-replaced elements, the range of the content area is determined by the font-size and the font itself; for replaced elements, it is determined by the element's own width and height.
  • baseline: The position of an element's baseline is determined by the position of the bottom of the letter x within the element. Of course, the position of the baseline will be different for different fonts.

You can understand it through a piece of code:

div {
  background-color: #ccc;
  font-size: 20px;
  color: #fff;
}
span {
  color: red;
}
<div>Text 1<span>Text 2</span>Text 3</div> 

The white text is an anonymous inline box, and the red text is an inline box wrapped by span . These three inline boxes form a line box, which can be understood as the gray area, because in this example div is expanded by a line box. If there are multiple lines of text, there will be multiple line boxes.

Regarding content area, W3C has this explanation:

CSS 2.1 does not define what the content area of ​​an inline box is (see 10.6.1 above) and thus different UAs may draw the backgrounds and borders in different places.

This article defines the content area of ​​a non-replaced element as its own width and height plus margin, padding, and border. I think the content area should be understood as the content box.

Line box height

The browser calculates the height of each inline box within the line box, and the calculation method is different for different inline boxes:

If it is a replaced element (such as img , input ), an inline-* element, or a child element in flexbox, the height is determined by its margin box;

inline-block elements:

div {
  background-color: #ccc;
  color: #fff;
}
span {
  display: inline-block;
  height: 30px;
  margin: 10px;
  background: #fff;
  color: red;
}
<div>xxx<span>xxx</span>xxx</div> 

Here the height of span inline box is height + margin 2 . If the value of height is auto, the height is equal to line-height + margin 2.

If it is a non-replaced element, the height is determined by its line-height, not the content area, although it sometimes looks like the content area stretches the height of the line box.

div {
  background-color: #ccc;
  font-size: 20px;
  color: #fff;
  font-family: Sana;
}
span {
  background: #fff;
  color: red;
}
<div>xxx<span>xxx</span>xxx</div> 

This picture clearly shows that it is the line-height, not the content area, that stretches the line box.

This article uses virtual-area height to represent the height of line-height, and my understanding is actually the height of the inline box.

The highest and lowest points of all inline boxes in the line box determine its height (this calculation includes the height of the strut, which will be mentioned later).

The margin, padding, and border of non-replaced elements do not affect the calculation of the line box height. When the line-height of an inline-level box is smaller than the content area, the height of the line box will be smaller than the content area. At this time, the background and padding of the element will overflow outside the line box.

The following code illustrates this problem:

div {
    background: #eee;
    border: 1px solid #000;
    box-sizing: border-box;
    font-size: 50px;
    line-height: 10px;
}
span {
    background: red;
    margin: 10px;
    padding: 10px;
}
<div><span>xxx</span></div> 

leading:

The difference between the height of the content area and the height of the inline box is the leading. This leading will be added equally to the top and bottom of the content area, so the content area is always in the middle of the inline box (vertically centered).

strut:

The browser assumes that at the beginning of each line box there is an anonymous inline box with a width of 0 and no characters, called a strut. This strut inherits the line-height from the parent element, so its height affects the calculation of the height of the entire line box.

An example

div { background: #eee; border: 1px solid #000; box-sizing: border-box; }
<div><img src="./image.png" alt=""></div>

In the picture, you can see that there is a gap between img and the outer div , which is caused by the strut mentioned above.

In this example, by default the bottom edge of img is aligned to the parent element's baseline ( img { vertical-align: baseline } ), which is actually where the strut baseline is located. As shown in the following figure:

The strut is actually equivalent to an invisible letter x. As mentioned above, the strut itself has line-height, so there is an extra gap at the bottom of the image.

To summarize the reasons for the gap:

  • strut has line-height
  • vertical-align default value is baseline

The corresponding solution:

  • Modify the line-height of strut. Since the line-height of strut cannot be set directly, you need to set the line-height of the parent element and then let strut inherit it, or modify the font-size.
  • Set vertical-align to some other value than line-height

The W3C explains line-height as follows:

On a block container element whose content is composed of inline-level elements, 'line-height' specifies the minimal height of line boxes within the element. The minimum height consists of a minimum height above the baseline and a minimum depth below it, exactly as if each line box starts with a zero-width inline box with the element's font and line height properties. We call that imaginary box a "strut."

My simple understanding is that for block-level elements composed of inline elements, line-height determines the minimum height of the line box. The browser assumes that each line box starts with an inline box (strut) with a width of 0, and this strut inherits font and line-height from the parent element.

  • Normal is the default value of line-height, and W3C does not have a clear definition for it. Normal will take the content area as a calculation factor.
  • Line-height is not the distance between two baselines.
  • It is recommended to use numerical values ​​for line-height instead of em units, because em units calculate line height based on font-size inherited from the parent element.

vertical-align

W3C defines baseline and middle as follows:

baseline: Align the baseline of the box with the baseline of the parent box. If the box does not have a baseline, align the bottom margin edge with the parent's baseline.

The element baseline is aligned with the parent element baseline. If the element has no baseline, such as img , the margin bottom edge is aligned with the parent element baseline.

middle: Align the vertical midpoint of the box with the baseline of the parent box plus half the x-height of the parent.

The vertical midpoint of the element is aligned to the baseline of the parent element plus half the x-height.

refer to

Deep dive CSS: font metrics, line-height and vertical-align
https://meyerweb.com/eric/css/inline-format.html
https://www.zhangxinxu.com/wordpress/2015/08/css-deep-understand-vertical-align-and-line-height/
https://www.w3.org/TR/CSS2/visudet.html#inline-box-height

<<:  JavaScript manual implementation of instanceof method

>>:  URL representation in HTML web pages

Recommend

Detailed explanation of memory management of MySQL InnoDB storage engine

Table of contents Storage Engine Memory Managemen...

Some tips on using the HTML title attribute correctly

If you want to hide content from users of phones, ...

WeChat applet implements the snake game

This article shares the specific code of the WeCh...

Detailed deployment of docker+gitlab+gitlab-runner

environment Server: centos7 Client: window Deploy...

A record of the pitfalls of the WeChat applet component life cycle

The component lifecycle is usually where our busi...

Implementation of Docker deployment of SQL Server 2019 Always On cluster

Table of contents Docker deployment Always on clu...

Summary of basic usage of CSS3 @media

//grammar: @media mediatype and | not | only (med...

Example code for implementing a QR code scanning box with CSS

We usually have a scanning box when we open the c...

Vue+element ui realizes anchor positioning

This article example shares the specific code of ...

Solution to the MySQL server has gone away error

MySQL server has gone away issue in PHP 1. Backgr...

Sample code for nginx to achieve dynamic and static separation

1. Simple configuration of nginx's dynamic an...

How to deploy MySQL and Redis services using Docker

Table of contents How to deploy MySQL service usi...

How to disable foreign key constraint checking in MySQL child tables

Prepare: Define a teacher table and a student tab...

CSS3 flexible box flex to achieve three-column layout

As the title says: The height is known, the width...