Image source: unsplash.com/photos/Gkin…

Author: Feng Hao

1. The introduction

Introduction to vertical center is basically a CSS must grasp the problem, we must all seen in all kinds of tutorial “CSS centered vertically N method”, in general, these methods already can satisfy all sorts of use scenario, however, when we met need to use some special fonts are mixed, or make the text alignment icon, You might find that no matter which vertically centered method you use, it always feels like the text is shifted a few pixels up or down, and you have to specifically shift them. Why is this?

2. Common vertical middle method

Below is a use of various common vertical centered approach to center text example, which involves different fonts are mixed, you can see, although it took several common vertical centered approach, but in the actual look and feel these words are not just the vertical center, some words look more centered, some words have offset badly.

View online: CodePen (Font file directly references Google fonts, if there is no effect need to pay attention to the network situation)

Font-size: 16px; font-size: 16px; vertical-align:middle 0, vertical-align:middle aligns the child element’s midpoint with the parent element’s baseline + x-height / 2, and sets the font size to 0 to ensure that the lines align at the midpoint.

If we select the text with the mouse, we can see that the selected area is indeed vertically centered in the parent container, so why the text is higher and lower? Here comes the construction of the font itself and the associated metrics.

3. Font construction and measurement

Here’s a question: when we set font size to the text in the CSS, what properties of the font are actually set to this value?

The following figure shows an example where the label of the text is span, and the text of each font is set with a red outline for observation, and line-height: normal is set. As you can see from the image, although the font size is 40px, they are all different in width and height, so the font size does not set the actual size of the text.

To answer this question, we need to have a deeper understanding of fonts. Here are some concepts related to fonts in Western Language. First of all, a font has EM Square (also known as UPM, EM, EM Size) [4]. This value was originally used in typography to represent the width of a font with a capital M. This value forms a Square, so that all letters can be accommodated, and this value actually reflects the height of the font container. In metal type, the container is the metal block for each character, and in a type, they are all uniform in height, so that each type can be placed into a printing tool and printed. In digital typography, em is a square that has been sized. The units of measurement are relative units that scale according to the actual font size. For example, 1000 units of font with 16pt font size would be 16pt. Em is typically 1000 in OpenType fonts and 1024 or 2048 (a power of 2) in TrueType fonts.

Metal type, pictures from designwithfontforge.com/en-US/The_E…

3.1 Font Measurement

There are many concepts and metrics of fonts themselves. Here are a few common concepts, using this image from Wikipedia (the following measures are in relative units based on EM) :

  • Baseline: Baseline is the level at which letters are placed.
  • X height: x height represents the height of the lowercase letter X on the baseline.
  • Capital height: Capital height indicates the height of a capital letter on the baseline.
  • Ascender/ascent: Ascender (ascending part) denotes the stem of a lowercase letter that exceeds the height of the x. Ascender may be a bit higher than capital height for identification purposes. Ascent represents the distance from the top of the text to the baseline.

  • Descender/descent: Descender is the descender stem of a lower-case letter extended below the baseline, such as the bottom of the j or G. Descent: The distance from the bottom of a text to the baseline.
  • Line Gap: Line gap represents the distance from the bottom of Descent to the top of the next line ascent. I have not found a suitable Chinese translation for this word, it should be noted that this value is not leading, which means the distance between the baselines of two lines of text.

Let’s take a look at these values in FontForge, using Arial as an example:

As can be seen from the figure, in the General menu, The em size of Arial is 2048, the ascent of font is 1638, and descent is 410. In the Metrics information of OS/2 menu, Capital height is 1467, x height is 1062, and line gap is 67.

Note here, however, that although we get ascent and Descent values in the General menu, these values should only be used for font design, and their sum is always em size; The computer calculates the rendering according to the corresponding value in OS/2 menu. General operating systems use HHead Ascent and HHead Descent of Horizontal Header Table (HHEA), but Windows is a special case. Use Win Ascent and Win Descent. Generally, the actual ascent and Descent values for rendering are larger than those for font design because the extra area is usually reserved for phonetic symbols or used to control line spacing, as shown below. The horizontal line at the top of the letter is the ascent height 1638 in the first image. And zhuyin symbols are beyond this area. According to the source [5], in some software text content is truncated if it exceeds ascent and Descent, which are used for rendering, However, when I tried it in the browser, I found that the browser didn’t do this truncation (Edge 86.0.608.0 Canary (64-bit), MacOS 10.15.6).

In this article, we consider both ascent and Descent to be ascent and Descent values read in OS/2 for rendering, and we call the ascent + Descent value content-Area.

In theory a font should be rendered the same on Windows and MacOS, i.e. ascent and Descent should be the same on each system, however some fonts are designed for unknown reasons and do behave differently on both systems. Here’s an example of Roboto:

Differences between Win and HHead metrics cause the font to be rendered differently on Windows vs. iOS (or Mac I assume) · Issue #267 · googlefonts/roboto

The size of the font em size is the same as the size of the font em size. When line-height: normal is set, the line height is content-area + line-gap, which is the actual height of the text.

Arial font: line-height: normal; font: size: The height at 100px is (1854 + 434 + 67) / 2048 * 100px = 115px.

In the experiment, it is found that for an in-line element, the selection height is the element value with the highest line-height in the current row. For block elements, the selection height is line-height if the value of line-height is greater than content-Area, and the selection height is the height of Content-Area if the value of line-height is less than or equal to content-Area.

3.2 Verify the impact of metrics on text rendering

Here’s a question in the middle. We’ve all used line-height to center text vertically, so what part of the font is it actually calculated at? To verify this, I created a new “design” font, set em size to 1000, Ascent to 800, and Descent to 200, and set normal and exaggerating metrics for them:

The text size is 100px. The four letters are vertically centered in the parent flex layout. The line-height of the four letters is 0, 1em, normal and 3em, respectively. The red border is the outline of the element, and the yellow background is the background selected by the mouse. As can be seen from the above two figures, font metrics have a great influence on text rendering position. At the same time, it can be seen that when line-height is set, although line gap participates in supporting the space with the value of normal, it does not participate in the calculation of the vertical center of the text, that is, the midpoint of the vertical center is always the midpoint of the Content-Area.

We also tweaked the font to offset its ascent so that the 1em line height outline is right in the middle, so we can conclude that em Square is always vertically centered relative to Content-Area when the browser renders.

Having said the font structure, we go back to the question in the previous section. Why are the characters of different fonts vertically centered when they are mixed?

In this paper, we come to a conclusion that the midpoints of the Content-Area are not consistent with the visual midpoints in vertical centering layout because of the difference in the measurement values of different fonts. As a result, the actual position appears to be offset. The following figure shows several midline positions of Arial fonts:

As you can see from the figure, the visual center line of uppercase and lowercase letters is somewhat offset from the center line of the entire character. I haven’t found a definitive conclusion about typography, but in my opinion, the center line of uppercase letters may look more comfortable (especially when mixed with content without lowercase letters).

It should be noted that Arial is a font with fewer offsets, so the overall feel of the font is still middle. This does not mean that other fonts are the same.

3.3 Chinese Fonts

For Chinese fonts, there is no base line, rising part, falling part, etc., and each character is in a square box. However, the concept of Western font is also used to some extent when it is displayed on the computer. Generally speaking, the bottom of the square box Chinese font is between the baseline and Descender, and the top is a little beyond ascender, while punctuation marks are just above the baseline.

4. CSS solution

Now that we know about fonts, how do we solve the offset problem when using fonts?

As can be seen from the above content, the offset of the text display is mainly caused by the inconsistency between the visual midpoint and the rendering midpoint, so we just need to correct this inconsistency, we can achieve the visual center.

To do this, we can use the vertical-align attribute. When vertical-align is set to a value, it indicates the distance between the child element’s base line and the parent element’s base line. The positive value is upward and the negative value is downward.

The scheme introduced here is to set the value offset of vertical-align for the text under a font through calculation, so that the visual midpoint of the capital letters coincides with the point used for calculating the vertical center, so that the attributes of the font itself will not affect the calculation of the center.

We will obtain the details through the following calculation methods: First of all, we need to know the em-size, ascent, Descent, capital height values of the current font (if we do not know em-size, we can also provide the ratio of other values to em-size). The following uses Arial as an example:

const emSize = 2048;
const ascent = 1854;
const descent = 434;
const capitalHeight = 1467;

// We need to know the given font size before computing
const fontSize = FONT_SIZE;

// Get the offset of the text according to the text size
const verticalAlign = ((ascent - descent - capitalHeight) / emSize) * fontSize;

return (
	<span style={{ fontFamily: FONT_FAMILY.fontSize}} >
		<span style={{ verticalAlign}} >TEXT</span>
	</span>
)
Copy the code

When set to this, the outer span behaves like a normal replaceable element participating in the inline layout, somewhat ignoring differences in font metrics, which can be vertically centered using a variety of methods.

Because this solution has fixed computational steps, it can be packaged as a component, processed with CSS custom properties, or processed with CSS preprocessors, depending on your specific development needs, to correct the vertical offset of the text by passing in font information.

5. Limitations of the solution

Although the above solution can solve the problem of vertical center of text to a certain extent, there is still some inconvenience in practical use. We need to know the metrics of the font before using the font. In the case of a small number of customized fonts, developers can manually use FontForge and other tools to check. However, when there are many fonts, it is more troublesome to look at them one by one.

At present, one idea is that we can use Canvas to obtain font information. For example, there is an open source library FontMetrics. Its core idea is to use Canvas to render the text corresponding to the font, and then use getImageData to analyze the rendered content. If in a real project, this scenario could lead to potential performance problems; In addition, the results obtained in this way are rendered. Some font authors did not strictly correspond the metrics of the design to the characters when constructing the font, which also led to the inaccurate metrics obtained.

Another idea is to parse the font file directly and get metrics for the font, as in the opentype.js project. This is not lightweight enough to be used in a real run, but consider automating the process during packaging.

In addition, the current solution is more of a theoretical approach. When the text size is small, the browser may not be able to render as expected, and the text will have an offset of 1px according to the DOM environment [9].

6. CSS Houdini is a possible future solution

CSS Houdini proposed a draft of Font Metrics [6], which can adjust Font Metrics for text rendering. From the current design, it is possible to adjust the baseline position, the EM size of the font, and the boundary size (content-area) of the font to address typesetting problems caused by font attributes.

[Exposed=Window]
interface FontMetrics {
  readonly attribute double width;
  readonly attribute FrozenArray<double> advances;

  readonly attribute double boundingBoxLeft;
  readonly attribute double boundingBoxRight;

  readonly attribute double height;
  readonly attribute double emHeightAscent;
  readonly attribute double emHeightDescent;
  readonly attribute double boundingBoxAscent;
  readonly attribute double boundingBoxDescent;
  readonly attribute double fontBoundingBoxAscent;
  readonly attribute double fontBoundingBoxDescent;

  readonly attribute Baseline dominantBaseline;
  readonly attribute FrozenArray<Baseline> baselines;
  readonly attribute FrozenArray<Font> fonts;
};
Copy the code

Font Metrics is still in the proposal stage. It’s not clear what the API will be, or if it will even exist in the future.

7. To summarize

Text vertical center problem has always been the most common problem in CSS, but it is difficult to attract attention, I personally think because we commonly used Microsoft yahei, Apple fonts themselves in the design of the more standard, in most cases are more centered. But when a font is not “standard”, traditional methods seem to be a bit ineffective.

This paper analyzes the factors leading to the deviation of the text and gives a scheme to find the vertical center position of the text.

As the problems related to IFC themselves are very complicated [7], various tips for centering inline elements with line-height and vertical-align are not strongly related to this article, so they are not mentioned in this article. If you are interested in these contents, You can also find some introductions in the resources below.

The relevant data

  • Deep dive CSS: font metrics, line-height and vertical-align – Vincent De Oliveira
  • The role and story of the letter ‘x’ in the CSS world
  • CSS provides an in-depth understanding of vertical-align and line-height relationships
  • EM Square
  • Win Ascent / Win Descent
  • Font Metrics API Level 1
  • Inline formatting model
  • FontForge OS/2 Metrics
  • How do ICONS align text

This article is published from netease Cloud Music big front end team, the article is prohibited to be reproduced in any form without authorization. Grp.music – Fe (at) Corp.Netease.com We recruit front-end, iOS and Android all year long. If you are ready to change your job and you like cloud music, join us!