EN FR

Documentation

How No More Font Shift works, why it was built, and a complete guide to every parameter.

The CLS problem caused by fonts

Cumulative Layout Shift (CLS) is one of Google's Core Web Vitals metrics. It measures unexpected visual shifts during page load. A high CLS hurts user experience and can negatively impact search rankings.

One of the most common — and most invisible — causes of CLS is web font loading. Here's what happens:

  1. The browser initially renders text using a system fallback font (Arial, Georgia, etc.).
  2. The custom web font (Poppins, Inter, Playfair Display…) finishes loading.
  3. The browser swaps the fallback for the final font.
  4. Because the two fonts have different metrics (character width, line height, spacing…), the text reflows and the layout shifts.

This shift is measured as CLS — even if users don't consciously notice it. Lighthouse and Google Search Console will catch it.

How No More Font Shift solves it

CSS provides @font-face descriptors that let you override the metrics of a fallback font to make it behave like your custom font. The trick: adjust the fallback font, not the main font.

@font-face {
  font-family: 'Poppins-arial-fallback';
  src: local('Arial');
  size-adjust: 103.24%;
  ascent-override: 94.00%;
  descent-override: normal;
  line-gap-override: normal;
}

body {
  font-family: 'Poppins', 'Poppins-arial-fallback', sans-serif;
}

No More Font Shift provides a visual editor to find these values: upload your font, compare the two overlaid text layers (original font in blue, fallback in orange), and adjust sliders until they align perfectly.

The 6-step wizard

The configurator is organised as a guided flow. You can only move forward after completing the prerequisites of each step, but you can freely revisit any step you've already passed.

  1. File — upload your font (drag-drop or click). .woff2 is the recommended format. The font name is auto-detected from the file's OpenType name table (TTF, OTF, WOFF). For WOFF2 (Brotli compression) we fall back to the file name.
  2. Name & stack — confirm the auto-detected name and pick the matching fallback stack (Sans / Serif / Condensed).
  3. Fallback 1 — calibrate the 4 metrics for the first system font (Arial, Times New Roman or Impact, depending on your stack).
  4. Fallback 2 — same for the second system font (Roboto, Roboto Serif or Roboto Condensed).
  5. A/B test — simulate the real font load to visualise and measure the layout shift (CLS) with and without your tuned fallback.
  6. CSS — copy or download the final CSS, and save it to the database if you're signed in.

Anonymous viewers of an existing font in the database can only access steps 3 to 6 (the file and name are locked). Editors and admins have access to all steps.

Interface guide

Fallback stack

Choose which group of system fonts to use as fallback:

  • Sans-Serif — Arial + Roboto: for sans-serif fonts (Inter, Poppins, Open Sans, Nunito…).
  • Serif — Times New Roman + Roboto Serif: for serif fonts (Playfair Display, Lora, Merriweather…).
  • Condensed — Impact + Roboto Condensed: for condensed or display fonts.

Each stack generates two @font-face declarations — one per system font — and inserts both into the final font-family stack.

Why Arial and Roboto?

Arial ships on virtually every system: Windows since 1992, macOS, iOS, and the vast majority of Linux distributions. It is the most universally available sans-serif font on desktop and iOS — but it is not available on Android.

Roboto has been the default system font on Android since version 4.0 (Ice Cream Sandwich, 2011). This coverage extends to its variants: Roboto Serif and Roboto Condensed.

This choice is directly tied to the Core Web Vitals measured by Google through CrUX (Chrome User Experience Report). CrUX collects real-world performance data from Chrome users worldwide. Android accounts for roughly 70% of global mobile traffic. If your fallback font is not calibrated for Roboto, your real-world CLS scores in CrUX will be degraded for the majority of mobile users — which directly affects your Google search ranking.

By targeting both Arial (desktop + iOS) and Roboto (Android), you cover the vast majority of the global device landscape and ensure strong CLS scores in Google's real-user data.

Technical note: metric-compatible substitutes for Arial and Times New Roman

Arial and Times New Roman are Microsoft proprietary fonts, licensed with Windows and bundled into macOS and iOS for historical reasons. We are not allowed to redistribute them in this tool. On Linux systems without the msttcorefonts package (the majority), both fonts are simply not installed.

To keep the preview and A/B test working on those systems, we bundle their free equivalents (Apache 2.0) designed by Google to be metrically identical to the originals:

Proprietary fontBundled substitute
ArialArimo (/fonts/arimo/Arimo-Regular.woff2)
Times New RomanTinos (/fonts/tinos/Tinos-Regular.woff2)

Properties of the metric equivalence:

  • Each glyph's advance width: identical to the pixel
  • Intrinsic line height, ascent, descent: identical
  • Paragraph line breaks at a given width: identical
  • Letterform shapes: subtly different (a graphic designer will spot the variations on "a", "e", "g", "R", serifs, terminations)

Concretely, the CSS injected for the preview does for example:

src: local('Arial'), url('/fonts/arimo/Arimo-Regular.woff2') format('woff2');

→ Users with the original font installed (Windows, macOS, iOS) load their real font. Users without (Linux desktop, browsers with restricted font lists) silently load our substitute, which has identical metrics.

The CSS exported for your site contains only the local() calls — we don't include the Arimo/Tinos URLs. On your visitors' sites, the vast majority has Arial / Times New Roman (Windows, macOS, iOS), and Android users fall through to the Roboto second fallback (or Roboto Serif). You therefore have no additional file to bundle.

For metric calibration (the purpose of this tool), the pairs produce numerically identical values of size-adjust, ascent-override, etc. Your tuning result is valid against either the original or the substitute.

Note: Impact (used in the Condensed stack) has no strictly metric-compatible OSS equivalent. Linux visitors without Impact will see the second fallback (Roboto Condensed) until your real font loads. This doesn't affect calibration for Windows/macOS/iOS/Android visitors, who make up the vast majority of your traffic.

Preview text

Seven preset content types, each designed to expose different aspects of font metrics:

  • Paragraphs: plain prose text. Represents ~80% of real-world web content. This is the most important case to calibrate first.
  • Uppercase: reveals differences in cap-height between fonts.
  • Bold & italic: the browser synthesizes bold from the Regular fallback, producing different metrics. Critical if your layout has bold text above the fold.
  • Bullet list: line-height differences accumulate. A 10-item list with 1 px difference per line = 10 px total shift.
  • Headings h2/h3: headings are at the top of content and load first. Large text visually amplifies any difference.
  • Table: the most complex case. Each cell is an independent container with its own height calculation.
  • Glyph coverage: each character repeated 30 times. Reveals individual glyphs that behave differently.
  • Custom: enter your own text or HTML to test with your actual content. Saved in localStorage.

size-adjust 50% – 150%, default: 100%

The most impactful parameter. It scales all glyphs of the fallback font proportionally, affecting character width and therefore line breaks.

How to use it: start by adjusting this slider until the line breaks match between the two layers. If your custom font is narrower than Arial, a value below 100% will shrink the fallback characters to get closer.

For fonts close to system standards, this is often the only parameter you need. The others allow fine-tuning of vertical text positioning.

ascent-override 0% – 200%, or "normal"

Controls the space allocated above the baseline. The "normal" value uses the fallback font's native metric.

When to change it: when, even after adjusting size-adjust, the text blocks are at different vertical positions between the two layers. Typically visible when headings or the top of text blocks don't align.

descent-override 0% – 100%, or "normal"

Controls the space allocated below the baseline. The "normal" value uses the native metric.

When to change it: when the bottom of text blocks doesn't align, particularly visible on the last line of a paragraph or in total block height.

line-gap-override 0% – 100%, or "normal"

Controls the extra vertical spacing between lines (line gap). This is distinct from CSS line-height — it's a font-intrinsic metric.

When to change it: when the total height of a text block still differs between the two layers after calibrating size-adjust, ascent-override, and descent-override.

The line-height gotcha

Important CSS spec subtlety: line-gap-override (along with ascent-override and descent-override) only takes effect when the rendering uses line-height: normal. If the page sets a numeric line-height (1.5, 24px, etc.), the browser uses that value and completely ignores the metric overrides.

Since virtually every production site sets an explicit line-height, line-gap-override typically has no visible effect in production. That's why we recommend leaving it at normal in 99% of cases.

The tool's automatic behaviour

To make metric overrides pedagogical, the preview uses a numeric line-height of 1.35 by default (typical of a production site). The two layers stack cleanly and you calibrate size-adjust, ascent-override and descent-override in realistic conditions.

As soon as you uncheck "normal" on any line-gap-override (Fallback 1 or 2, any stack), the preview automatically switches to line-height: normal so your tuning is visible. An amber warning appears under the slider as a reminder that this override probably won't have any effect in production.

Preview modes

Blink

Alternates between showing the original font and the fallback every 500 ms. When the text doesn't move during blinking, the fallback is perfectly calibrated. This is the definitive test.

Lines

Adds typographic reference lines (underline + overline) to every text element. Makes it easy to compare baseline and x-height alignment between the two layers without relying solely on colour.

Layer colours

In light mode, both layers use mix-blend-mode: multiply on a white background:

  • Where the two layers overlap perfectly, the colours mix into a dark neutral.
  • Where there's a shift, you see each layer in its own colour.

In dark mode, mix-blend-mode: screen is used with lighter colours, producing the same inverse effect on a dark background.

Click the palette icon next to each font name to customise its colour. The choice is saved per theme in localStorage.

A/B test step

This step simulates the actual font load with a configurable delay, and visually compares the result in two panels:

  • Without tuned fallback — the browser only has the generic font (sans-serif/serif). When the real font arrives, this panel jumps (red pulsed effect) — that's the CLS we're trying to eliminate.
  • With tuned fallback — the browser uses your @font-face overrides. If your metrics are well-calibrated, this panel stays put.

Network speed: pick from Wi-Fi (300 ms), Fast 3G (1.5 s), Slow 3G (4 s), or a custom delay via the modal (100 ms to 10 s).

Sample text: pick the same content type as in the preview (paragraph, headings, list, table…).

Font size: 14–36 px slider, shared with the Fallback 1/2 preview (the value is saved to localStorage).

The pixel delta between before and after the swap is measured and shown to the right of each panel when a shift is detected.

Using the generated CSS

Once the values are calibrated, copy the generated CSS and add it to your stylesheet before your main font's @font-face declaration.

The font-family stack places both fallback fonts between your main font and the generic family:

font-family: 'YourFont', 'YourFont-arial-fallback', 'YourFont-roboto-fallback', sans-serif;

While the main font hasn't loaded yet, the browser uses YourFont-arial-fallback or YourFont-roboto-fallback depending on availability — regular system fonts whose metrics you've adjusted to match your font.

Once the main font loads, it replaces the fallbacks with no visible shift.

About

No More Font Shift was designed and built by Agence Web Performance, a web performance optimization agency based in France.

The tool was born out of a recurring need: during CLS audits and performance optimization projects, we needed to manually find the right @font-face values for each client's custom fonts. This repetitive process led us to build an internal tool, and then to make it publicly available so the whole web community could benefit.

The public database centralizes configurations already established for the most common fonts. If you're using a font that's already in the database, you can simply copy the CSS — the work is already done.