The homepage heading sits high, then drops a line after a second. Search Console lists Cumulative Layout Shift (CLS). The filmstrip shows the brand font arriving late.
That jump is not a broken template. It is a fallback face and a web font that do not occupy the same space.
This post is how to stop that shift. Wrapping Tag Manager in a delay, covered in how to delay third-party scripts without breaking tracking, is a different leak.
The swap still shifts when the text was invisible
web.dev's CLS guidance names two font patterns. Flash of Unstyled Text (FOUT) shows the fallback, then swaps the web font. Flash of Invisible Text (FOIT) hides the letters until the file arrives.
Both can move the page. Invisible text is still laid out with the fallback metrics. When the web font loads, the block and everything under it shift the same way a visible swap would.
Chromium and Firefox, by default, can hold text for up to three seconds. Safari can hold it until the file arrives.
That wait does not reserve the final height. It reserves the fallback height.
Name a fallback that is close, then tune the metrics
A stack that lists only the brand family falls back to the browser default. On Chrome that default is Times, a serif, which is a worse match than a generic sans-serif for most marketing heads.
Put a generic family after the brand name so the first paint is at least the same class of type. Then shrink the remaining gap with font-face descriptors. web.dev points to size-adjust, plus ascent, descent, and line-gap overrides, so the fallback box matches the web font box.
Do this on the fallback face you actually show, not as a guess in a screenshot. Load both faces in DevTools, compare line count on the real H1, and change the overrides until the heading no longer grows a line on swap.
Icon fonts fail this harder than body type. The fallback character is not the same icon, and the shift is large.
Replace those with SVG where you can. A late icon font is a layout problem, not brand polish.
Pick font-display for stability, not for a guaranteed brand face
The font best-practices guide treats font-display as a tradeoff between First Contentful Paint, Largest Contentful Paint, and layout stability. It is not a brand toggle.
Optional uses the web font only if it is ready in about 100 milliseconds. There is no swap period after that on this visit. The file can still cache for the next navigation.
Some first-time visitors never see the brand face. They also do not get the jump.
Swap shows fallback text immediately and will swap whenever the file arrives. That is the usual FOUT.
If metrics still differ, CLS remains. Deliver the file early, or stop using swap on body copy.
Block hides text, then can still shift when the face arrives, because the reserved space was the fallback. Fallback (the display value) is a short block, then a limited swap window. Neither is a free pass on metrics.
A mixed policy is allowed. Swap on a short logo word where the face is the product. Optional on long body copy where a jump under a form costs more than a system sans on the first view.
Discover the file before first paint
A font-face rule does not download the file by itself. The browser waits until some styled text on the page actually uses that family. If the rule lives in a late stylesheet, the download starts late, and the swap happens after paint.
Inlining the critical font-face rules in the document head lets the browser see them without waiting on that extra CSS file. Preload can also start the woff2 early, including for self-hosted files, and fonts need a cross-origin fetch even on your own origin.
Preload is a blunt tool. It ignores unicode-range negotiation and should be one format, usually woff2. It also spends bandwidth that other critical files want.
Prefer inlining the faces you actually use. Preload only the heading file when the CSS is still external.
Third-party hosts need an early connection. For Google Fonts that is a preconnect to the stylesheet origin and a separate cross-origin preconnect to the file origin. Self-hosting on a CDN with HTTP/2 removes that extra handshake, but only if the files are subset and cached.
Serve woff2 only for modern browsers. Extra legacy formats create double downloads.
Unused weights are extra swaps. A page that requests thin, regular, medium, and bold when it only paints regular and bold is paying four chances to shift.
These setups still move the heading
Fix the pair you can measure on the live URL. A lab filmstrip that never waits on a slow font will hide the jump your field CLS still records.
- font-display is swap, and the fallback is Times because no generic family was listed.
- Body copy uses swap while the woff2 still arrives after the first paint.
- Four weights load for a page that only paints regular and bold headings.
- The font-face rules sit in a footer stylesheet, so discovery starts after render.
- An icon font still ships for nav glyphs that should have been SVG.
- size-adjust was copied from another site and never checked against this H1.
Unlike a full web development and martech build, this post covers only font-driven layout shift. For a look at whether the live heading still jumps after the face arrives, start with Get Free Assessment.
If this post is wrong, outdated, or you would take a different path
I write from work I have done on real sites. Search products change, and a step that was right when I published can go stale. I can also be wrong about the method.
If you disagree with the approach, the facts, or the outcome, I want the detail. Tell me what is off, what you would do instead, and where you saw it. I use that to correct the post so the next reader is not stuck.
This is not a comment thread. Use Contact me so the note is tied to this post and I can reply.
You are sending feedback for
Stop layout shifts caused by custom web fonts
Web Development & Martech
https://test.hammadshk.com/blog/stop-layout-shifts-caused-by-custom-web-fonts