Skip to main content

Watch Out for Layout Shifts with ‘ch’ Units

By Paul Hebert

Published on May 31st, 2023

Topics

We recently worked with Cloudinary to rebuild their blog. There was a big focus on performance throughout the process, especially passing Core Web Vitals. However, we recently started seeing poor Cumulative Layout Shift scores on a number of posts. I set out to investigate.

The text "ch" overlaid over itself in two different fonts. The top font is semi-transparent and wider than the bottom font.

Cumulative Layout Shift is a metric that tracks how much content on the page shifts while the user interacts with it. These layout shifts can be a real pain for people trying to use your site:

Have you ever been reading an article online when something suddenly changes on the page? Without warning, the text moves, and you’ve lost your place. Or even worse: you’re about to tap a link or a button, but in the instant before your finger lands—BOOM—the link moves, and you end up clicking something else!

web.dev

Our Real User Metrics showed that desktop users were often experiencing unacceptable levels of layout shifts.

To better understand the types of layout shifts our users were experiencing, I used the dev tools to throttle my connection and highlight layout shifts. With page loading slowed down, I could see and understand the layout shifts:

I could see that the overall layout was shifting during the page load. The width of the main post container shifted a couple of times, causing the whole page to re-render.

After some debugging, I realized a couple of seemingly unrelated choices were combining to trigger these layout shifts:

The ch unit is equivalent to the width of the 0 character in the currently selected font. This makes it really helpful for typographic fine-tuning. For example, you can use it to apply a max-width to your prose content to cap the overall line length to improve readability.

When using a web font, the browser needs to decide what to do while the font is loading. By default, the browser will not display the relevant text until the font has loaded. This is called a “Flash of Invisible Text,” and it means that visitors can’t start reading your content until the web font has loaded, which can make the page feel slower.

Luckily, there are other options. We were optimizing for a “Flash of Unstyled Text.” This means that the browser immediately displays our text in a fallback font that’s already loaded on the visitor’s computer. When our font loads, it then gets swapped in to replace the fallback.

This ensures that visitors can start reading content sooner, but when the font swaps in, it can cause layout shifts. I thought this might be contributing to our Cumulative Layout Shift, but it didn’t account for the intensity of layout shifts we were seeing.

In our case, we were achieving this using async font loading, but it can also be achieved using font-display: swap.

In our case, we were using ch units to define our page layout. This meant that our post content was equal to 50ch units (or the width of fifty 0 characters all lined up in a row).

But the width of the 0 character differs from font to font. So when our web font was swapped, the width of 1ch changed, which impacted our layout:

  1. The page loads and displays using fallback fonts. ch is equal to the width of the 0 character in the fallback font.
  2. We asynchronously load our web font (in this case, Inter) and swap it in.
  3. Now the ch unit is equal to the width of the 0 character in our web font.
  4. Since the post content is set using ch units, and ch units base their size on the 0 character in the current font, the post layout shifts with the font change.

Here’s a CodePen showing the issue. The font is swapped every two seconds. Since the post content is set using ch units, it changes too.

To fix the issue, I swapped out my ch units for rem units, which stay consistent regardless of font. This small change resolved our layout shift issue without affecting the overall layout.

We will also want to look into using tools like the Fallback Font Generator and CSS rules like size-adjust to adjust our fallback font to be sized more closely to our web font. But, for now, this quick fix avoids severe layout shifts for our users.

ch units are really neat! But watch out for layout shifts when using them.

Comments