Web browsers and optical type sizing perils

15/8/2021 • 5 min • web design

Back in the metal typesetting days, fonts were crafted by hand. While limited to a subset of standardized sizes, one could also adjust the design across the line. Smaller fonts could be optimized for legibility with thicker and lower contrast strokes, larger and more open counters, ink traps, and more generous tracking. Larger fonts gave more freedom for ornament and detail with tighter tracking and higher contrast stroke width. Digital typefaces with separate text and display fonts have existed for a while, but until recently, point-level design adjustments was a relic mostly left to metal type. [1]

With the advent of OpenType Variable Fonts, this feature is now widely available, including in recent web browsers (with compatible font files). In fact, loading a Variable Font will automatically set its Optical Size to scale with the font-size using the on-by-default font-optical-sizing: auto. Unfortunately, this browser-set optical size is not ideal.

points vs pixels

The issue lies in the difference between the point ( pt ) system used for print applications versus the “pixel” ( px ) system used for CSS.

There are many standards for sizing things in print, but for typography, the world has standardized on the point system, in which 1 pt is equivalent to 1/72 of an inch. The OpenType specification also refers the Optical Size set in Variable Fonts to use this exact measurement.

On the other hand, the web uses a “pixel” based sizing system, which—confusingly—has nothing to do with the pixels on the screen. The W3C group defines one CSS pixel to be the equivalent of 1/96 of an inch at a distance from the reader’s arm length. However, in practice, the physical size of one CSS pixel can vary across browser, device, screen, OS, and the person (their eyesight, and particularly their limbs).

When web browsers render the Optical Size, they take the font-size in CSS pixel units, and—without conversion—input that number as the Optical Size.

/* how browsers calculate optical size */
p {
  font-size: 16px;
  font-variation-settings: 'opsz' 16;

As the physical size of CSS pixels are often larger than that of Print points, the optical size will be incorrect, relative to its intended design. [2]

Approximating Print Points

To address this, optical sizing will need to be handled manually. The calc() function can be a helpful method to render the optical size at a more sane size. To roughly approximate print points, multiply by 0.75.

p {
  font-size: 16px;
  font-variation-settings: 'opsz' calc(16 * 0.75);

font-variation-settings is particularly annoying in that individual settings don't stack. If you want to adjust one setting, you must redefine all of them.

p {
  font-size: 16px;
  font-variation-settings: "opsz" calc(16 * 0.75);
#article p {
  font-size: 16px;
  font-variation-settings: "wght" 300;
/* this will set the weight
   to 300, but the optical size
   will be reset to default */
#article p {
  font-size: 16px;
  font-variation-settings: "wght" 300,
                           "opsz" calc(16 * 0.75);
  /* corrected code */

Update (August 15, 2022)  •  But you should really be using CSS variables to make this easier and more DRY. Do note that you have to use a raw number value for any font-variation-settings. Every other CSS units such as: 16px,20pt, 1rem, 50%, and so on, won't work. Any invalid values will also render the entire font-variation-settings rule invalid.

/* Insert your default/fallback values here*/
:root {
   --wght: 400;
   --opsz: 16;
/* You must use the global * selector,
   body or html does not work. Annoyingly,
   CSS variable fallbacks also do not work */
* {
   font-variation-settings: "wght" var(--wght),
                            "opsz" calc(0.75 * var(--opsz));
   font-weight: var(--wght);
/* Defining the weight axis
   in both places to be safe. */
html {
   font-family: 'Your Variable Font';
p {
   font-size: 16px;
/* --wght and --opsz will be
   inherited from :root */
h1 {
   font-size: 24px;
   --wght: 800;
   --opsz: 24;
/* --wght and --opsz
   are overwritten */

Method Limitations

If units outside px are used, it can tricky, if not downright impossible to calculate and apply them trough CSS alone. Units such as em and rem could be calculated trough an additional multiplication step; but most other units such as percentages, vh, vw, ex, and fancy clamp() calculations are ruled out altogether without the use of Javascript, and can only be used with the built-in font-optical-sizing: auto.

The further complication is that CSS px to Print pt conversion will, for all practical purposes, always be imperfect due to the fact that there is no such thing as a CSS absolute unit. That applies to CSS pt units as well (which shouldn't be used for digital application anyway.)

the larger discussion

Optical Sizing for the web is still a very green technology, and the manner in which browsers scale a font's Optical Size is a heated debate. In developing this website, I emailed David Jonathan Ross, the type designer of the Forma Variable typeface used here. [3] He helped clarify the complicated issues surrounding Optical Sizing on the web, but also made the case that exactly matching the Optical Size of print shouldn't necessarily be an ideal either:

“The implementation of optical sizes is flawed, but it’s somewhat okay because optical sizing is not an exact science. Plus, some optical size adjustment is better than none… even if font-optical-sizing: auto does not generate the same outlines that you’d get matching font size in InDesign, it is at least a step in the right direction.

In the pre-variable days, Forma’s sizes were provided in ranges (Micro, Text, Deck, Display, Banner) rather than for specific point sizes, and in the end it was up to the designer if they wanted to lean in one direction or the other. So I encourage you to trust your eye and use the value(s) that feels the best for your design in the environments that you care about most. Even with the high-resolution screens we have today, I’d argue that there is still a reading difference between print and screen, and you can use this value to account for that rather than to match the print exactly.”

Make of it how you will.

— Laurens Spangenberg


  • [1] Technically, variable fonts were available much ealier, albeit in a rare and more archaic format. The 90s brought Adobe Multi Master Typefaces and TrueType GX. Check out Matthew Carter’s Skia demo running on… Mac OS X Snow Leopard.
  • [2] A few exceptions to this rule are any variable fonts made by Apple, such as their SF font family, which seems to have its optical size optimized for digital applications first. By this logic, it can easily be assumed that their (2019) New York font family also follows this rule. Worth mentioning is that Safari has a 1:1 CSS px font-size to Optical Size method, and they seem to be stubborn in keeping it so.
  • [3] Like all type designers I've interacted with to date, he's a super chill dude and helpfully wrote a lenghty informative email response to all my questions. Thank you David!