30

I am trying to find what the value set in the font-size CSS property is corresponding to.

To give the context, I want to get in CSS the size in em of parts of the font (above the capital height and under the baseline) that I know from its OS/2 metrics. The em unit is relative to the given font-size and the OS/2 metrics are relative to the em-square.

What I expect

My expectations are based on the following references. I did not found anything more clear or precise.

  1. According to the W3C reference for font-size in CSS2.1, and as quoted in all the Stack Overflow questions I found on the topic (here, here and here):

    The font size corresponds to the em square, a concept used in typography. Note that certain glyphs may bleed outside their em squares.

  2. Following the few knowledges I have in typography, the em square is the entire square of font metrics in which ascending, descending, gaps, (etc...) lines are defined. In OS/2 metrics, the em square is the size of the font itself (often 1000 or 2048 UPM).

    Letter metrics
    (source: microsoft.com)

    The only explanation I found from W3C is in an old reference from 1997 for CSS1, and it is coherent with the modern digital definition of em square I use:

    Certain values, such as width metrics, are expressed in units that are relative to an abstract square whose height is the intended distance between lines of type in the same type size. This square is called the EM square. (...) Common values are 250 (Intellifont), 1000 (Type 1) and 2048 (TrueType).

So if I understand these references correctly, the value specified in font-size should be used to generate the entire em square of the font, and we should be able to calculate the size of a part of the font from the font's size and metrics.

For example, with...

.my-letter {
    font-family: 'Helvetica Neue';
    font-size: 100px;
    text-transform: uppercase;
}

... we should have an em square of 100px, and because Helvetica Neue has a Capital Height of 714 / 1000 (sCapHeight in the OS/2 table), a capital height of 71.4px.

Expected Letter

What actually happens.

The generated em square is bigger than font-size (tested on the latest versions of Chrome, Firefox and Safari for Mac). At first, I thought that the browser had an other definition of em square and was making a part of the letter equal to font-size, but I did not found any OS/2 metrics (with or without ascender, descender, gaps...) that matches with it.

Rendered Letter

You can also see this CodePen. Please note that I use line-height: 1; to highlight the expected size, but my problem is with font-size (the "rendered ink") and not line-height (the "collision box"). This is something I have to precise because I have already been misunderstood several times. line-height is not the problem.


So I have three questions:

  • Did I understood correctly the W3C references, or I am assuming things that these references did not said?
  • If not, why does the generated font have an em-square greater than font-size?
  • The most important: How could I know the size of the rendered em-square (relatively to the font-size) ?

Thank you for your help.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
ncoden
  • 869
  • 9
  • 24
  • 1
    related: https://stackoverflow.com/q/55978130/8620333 – Temani Afif Dec 14 '20 at 22:42
  • 1
    There is an interesting (non-CSS specific, but still related) question on graphicdesign.stackexchange.com: [What does the size of the font translate to exactly?](https://graphicdesign.stackexchange.com/q/4035/155159) – bluenote10 Mar 25 '21 at 10:36

2 Answers2

9

Your understanding of the W3C references is correct, but your understanding of the red box is not.

The red box does not depict the em-square. Its height is the sum of the ascent and descent from the metrics.

Alohci
  • 78,296
  • 16
  • 112
  • 156
  • You are right. So it means that: **1:** Ascent and descend are out of the em square. **2:** x-height and capital height are in fact unchanged. **3:** I can deduct the distance between the top/bottom of the collision box and the capital top/baseline. **4:** There is no metrics in the font (at least for Helvetica Neue) that I could use to know the real ascent (top of lowercase 'l' or 'h' for example). I am right ? – ncoden Feb 04 '17 at 11:29
  • @ncoden - More or less yes. Ascent and descent are *independent* of the em-square. That is, for any given font, their sum may be greater than, equal to, or less than the em-square, so they're not necessarily "out of" the em-square, although it does seem commonplace for the sum to be greater than the em-square – Alohci Feb 04 '17 at 12:05
  • It's worth noting that although the font metrics contain an ascent, descent and capital height, the individual glyphs need not comply with those metrics - for examples, an actual capital "A" might be taller or shorter than the capital height, and a lower case "o" lowest point may be drawn above or below the baseline. – Alohci Feb 04 '17 at 12:13
  • 1
    I found more informations [here](https://grahamwideman.wikispaces.com/Font+Vertical+Metrics). Yes, each letter has its own ascender and descender, but the `TypoAscender` and `TypoDescender ` metrics are intended to be the "global" asc/desc, usable on lines of characters. But for `Helvetica Neue` and some other fonts, these metrics are equal to `WinAscender` and `WinDescender` and describes the "maximum" asc/desc. – ncoden Feb 04 '17 at 12:40
2

The article (that had been shared in a now deleted answer) explains it very well. This is my attempt to turn it into a stand-alone answer.

Let's assume we have a <span> styled with the font-family: Roboto and font-size: 48px and we want to answer the seemingly simple question: What is the effective height of the span? Spoiler: It is 65px. This is how you could derive it:

First you need to know some metrics about the font. If you are on Linux you could inspect the font with FontForge like so:

$ fc-list | grep Roboto
$ fontforge /usr/share/fonts/truetype/roboto/hinted/Roboto-Regular.ttf

Under Element => Font Info... => General you can get the Em Size which is kind of like a unitless base unit of the font:

enter image description here

Under Element => Font Info... => OS/2 => Metrics you can find the ascent/descent, which are the largest extensions of the font:

enter image description here

What the browser does is to match the em size (2048) with the specified font size (48px). Based on that, it computes how big the area covered by the ascent/descent (2146, -555) is in relation to the em size. So the formula is roughly:

result_size = (ascent + |descent|) / em_size * font_size

In this example:

(2146 + 555) / 2048 * 48px = 63.375px

The remaining question is why the browser actually arrives at 65px instead. My assumption is that the ascent and descent get rounded up individually. Applying the formula individually gives 50.30px => 51px for the ascent and 13.01px => 14px for the descent, resulting in exactly 65px.

bluenote10
  • 23,414
  • 14
  • 122
  • 178