[Resolved] Cumulative layout shift using local fonts.

Home Forums Support [Resolved] Cumulative layout shift using local fonts.

Home Forums Support Cumulative layout shift using local fonts.

Viewing 15 posts - 1 through 15 (of 17 total)
  • Author
  • #1616592


    I am loading local fonts using @font-face and turning off Google fonts in perfmatters.

    I am also declaring directly in “Additional CSS” font ‘Alex Brush’ for “h1,h2,h3,h4,h5,h6” and font ‘Alegreya’ in font-weight:400 & 700 for “body”

    Everything works and the fonts are getting served locally. I also added preloading in perfmatters so fonts are loaded first and that also works.

    Alex Brush is a handwriting font. To have it displayed in a decent size for headings in desktop the font size that I use for H1 is 58px. If I use font-display:swap; in my @font-face declaration a system font is getting loaded at 58px & then Alex Brush at 58px. It results in a heavy duty mega cumulative layout shift.

    To better illustrate, I found this tool developed by a Google employee https://meowni.ca/font-style-matcher/

    Essentially when using font-display:swap; the initial system font is huge then when Alex Brush is finished downloading it’s about half the size. Mega CLS.

    In an effort to fix this I did my best to find two similar fallback web safe fonts and modified the “h1,h2,h3,h4,h5,h6” font declaration the two backup fonts are “cursive” and Alex Brush is “handwriting” beurk. No idea how to declare that! What is the right way of doing that if needed?

    font-display:block; Is my previous setup & it only partially solves the problem in different ways on different pages. There is no logic in the end result.

    I figured I could use Georgia as a fallback font with the modifications done by the tool https://meowni.ca/font-style-matcher/ to minimize cumulative layout shifts. To match Alex Brush at 50px (maximum font size of tool) to Georgia the CSS is:

    font-family: Georgia
    font-size: 36px
    line-height: 1.8
    color: red
    font-weight: 400
    letter-spacing: 0px
    word-spacing: 0px;

    1- Is there a way to apply this CSS for the fall-back font.

    2- I’m not even certain if my code is ok can you please verify:

    /* Alex-Brush-regular headings backup Bradly Hand & Brush Script MT - Google Fonts off in perfmatters plugin */
    @font-face {
      font-family: 'Alex Brush';
      font-style: normal;
      font-weight: 400;
    	font-display: block;
      src: local('Alex Brush'), local('Alex-Brush'), local('Alex Brush Regular'), local('Alex-Brush-Regular'),
           url('/fonts/alex-brush-v12-latin-regular.woff2') format('woff2'), 
           url('/fonts/alex-brush-v12-latin-regular.woff') format('woff');
    h1,h2,h3,h4,h5,h6 {font-family:'Alex Brush', Bradley Hand, Brush Script MT, handwriting;}
    /* END alex-brush-regular */

    3- System fonts & web safe fonts are all mumbo jumbo for me. To my understanding Georgia or the two fall-back fonts that I chose are not system fonts on Android. And the list goes on… What would be the best fall-back font ?

    4- I did a typo in my @font-face declaration of headings. A huge system font displayed. I tested all pages in all languages. Cumulative layout shift was zero not 0.012 zero-0 for mobile & desktop. All my theories for hooks and changing layouts in the header fell to pieces. I finally found the culprit of cumulative Layout Shift. Fonts!

    Please advise

    Customer Support

    Hi there,

    you specify your fallback font in your CSS, not the @font-face eg.

    p {
       font-family: MyWebFont, fallbackFont, fallbackFont2, fallbackFontX;


    It is in my CSS at the bottom after @font-face declaration. The issue is headings not body text. To my knowledge the CSS that you supplied above should start with “body” not “p”.

    h1,h2,h3,h4,h5,h6 {font-family:'Alex Brush', Bradley Hand, Brush Script MT, cursive;}

    What the rule is saying to the browser is:

    1- I’d like to use the “Alex Brush” font here from your font cache, please.
    If you don’t have that, try “Bradley Hand” next. WEB SAFE FONT
    If you don’t have that, try “Brush Script MT”. WEB SAFE FONT
    All else fails, use whatever you’ve got for the generic keyword “cursive”
    If you dont have “Alex Brush” in your cache start painting the page with any of those fonts since in @font-face I specified font-display: swap;
    Then download “Alex Brush” locally in the specified url or in woff or woff2
    I did ask you to preload the fonts in the head in perfmatters.
    It generates a flash of unstyled text or FOUT as explained in the beginning of support request.

    I modified the last one from “handwriting” to “cursive” as it has nothing to do with the first font like I thought. Don’t think that there is system or web safe fonts that are “handwriting”.

    It did make some improvements not 100% I have two completed pages in both languages. The home page and the other one in services.

    Home page in English Mega CLS in desktop negligeable in mobile.
    Three other pages OK

    I did find this article that was written by a font obsessed guru https://www.zachleat.com/web/comprehensive-webfonts/ applying “Critical Flash Of Formatted Text FOFT with data URI” https://www.zachleat.com/web/comprehensive-webfonts/#critical-foft-with-data-uri It is above my knowledge on how it can be done in WordPress and it seems to apply some github PHP.

    Just doing my best to solve this & move on.

    Any insights and help would be appreciated.



    I came to the conclusion that web fonts are always going to induce cumulative layout shift unless I get a doctorate in them and apply https://www.zachleat.com/web/comprehensive-webfonts/#critical-foft-with-data-uri

    After two days of doing all sorts of tests including changing to another web font I deleted my @font-face declaration & switched to a system font directly in typography of GeneratePress Premium.

    Google doesn’t want us to use cute or nice fonts on WordPress.

    The website doesn’t look as good and as a compensation it was already lightning fast. Now it’s blistering fast since I’m not loading any fonts. Under 200ms for Pingdom Website Speed Test 🙂

    Customer Support

    Cursive/handwriting ( as well as lot of other display ) fonts have very few options when it comes to fallback fonts. Which generally means you have to take the hit on performance by preloading them or deal with the impact of font swapping ( aka CLS ).

    Of course, as you have decided, the better option is to not use them…. which seems to be the chosen path for many as demonstrated by the generally vanilla look of the majority websites we see today.

    Glad to hear you came to a conclusion 🙂



    After looking at the “vanilla look” of system fonts in the headings compared to what it was I came to a solution to put back the previous heading font 🙂

    I used the tool https://meowni.ca/font-style-matcher/ entered my web safe script font “Brush Script MT” on the left & “Alex Brush” on the right. Modified on the right letter spacing & word spacing till I got a happy medium between the line of text on top & paragraph at the bottom.

    In typography of GeneratePress premium made certain that the line height for the headings was the same as the one declared in @font-face 1.2em in my situation.

    The resulting code is as follows:

    /* Alex-Brush-regular headings backup Brush Script MT - Google Fonts off in perfmatters plugin */
    @font-face {
    font-family: 'Alex Brush';
    font-style: normal;
    line-height: 1.2em;
    letter-spacing: 0.3px;
    word-spacing: 0.65px;
    font-weight: 400;
    font-display: swap;
    src: local('Alex Brush'), local('Alex-Brush'), local('Alex Brush Regular'), local('Alex-Brush-Regular'), url('/fonts/alex-brush-v12-latin-regular.woff2') format('woff2'), url('/fonts/alex-brush-v12-latin-regular.woff') format('woff');
    h1,h2,h3,h4,h5,h6 {font-family:'Alex Brush', Brush Script MT, cursive;}
    /* END alex-brush-regular */

    All pages have a cumulative layout shift under control except the home page in French that has a high cumulative layout shift in desktop. I am in the process of troubleshooting that as there is no reason for it to be different then the English version. Possibly by modifying the letter spacing and word spacing values I can come to a happy medium. Or it’s something with the actual page and the GenerateBlocks settings. Or it’s a bug with GenerateBlocks on that page.

    Sometimes it pays off to be persistant & determined 🙂


    Forgot I’m preloading only the woff2 font in the head in perfmatters.

    <link rel="preload" as="font" href="/fonts/alex-brush-v12-latin-regular.woff2" type="font/woff2" crossorigin="anonymous">

    Sometimes happiness & satisfaction comes from oh so little things…

    Customer Support

    Thats great 🙂 So you fixed the French Issue ?



    I don’t know, just a blob & sure beats me.

    On Google PageSpeed Insights the French desktop home page as a layout shift of 0.550 for

    Any insight or solution would be appreciated.

    P.S. Imagine you will be able to fix your cumulative layout shift of 0.170 caused by your custom font on generatepress.com using my solution 😉



    Watched a video of the page loading. Noticed that a web safe script font wasn’t loaded prior to the desired font “Alex Brush”


    h1,h2,h3,h4,h5,h6 {font-family:'Alex Brush', Brush Script MT, cursive;}


    h1,h2,h3,h4,h5,h6 {font-family:'Alex Brush', Brush Script MT, script;}

    Cursive or handwriting are the wrong designations for the type of font I am using SCRIPT is the right one.

    No more cumulative layout shift 🙂


    I was having mixed results.

    Found out that the API generating the critical path CSS in WP-Rocket was overloaded at times and not generating the critical path CSS. I noticed that in Google PageSpeed Insights when I was getting the two messages “Eliminate render-blocking Ressources” & “Remove unused CSS” I did not have the cumulative layout shift in desktop on the front home page.

    The “Optimize CSS delivery” function in WP Rocket creates a critical path CSS for above the fold content and eliminates the two messages in Google PageSpeed Insights.

    I was doing tests and sometimes the critical path CSS was generated and sometimes not. So I came to wrong conclusions on the font-family:

    After research, the right way of describing a last resort generic fallback script font if all else fails is “cursive” & best practice is to put fonts with several words in parentheses. The right line of code is:

    h1,h2,h3,h4,h5,h6 {font-family:"Alex Brush", "Brush Script MT", cursive;}

    I’m continuing my research to see if I deactivate “Cache dynamic CSS” in GeneratePress Customize > General will solve the issue. If not, I will contact WP Rocket support as it’s not a theme related issue.

    All the above code & solution works for matching a custom font with the first fallback web safe font eliminating cumulative layout shift when the font gets swapped. Hope it helps others.

    Lead Developer
    Lead Developer

    Thanks for posting the process of figuring it out here – very helpful!

    The “Cache Dynamic CSS” option in GP simply saves the generated CSS from the theme into the database and serves it from there instead of generating it on each page load. If you’re using WP Rocket, you can likely just deactivate that option as they should be doing most of the heavy lifting anyways 🙂


    Hi Tom,

    When it comes to custom fonts it’s just a matter of finding the closest web safe font then slightly modifying the custom font to avoid cumulative layout shift.

    I tried turning off “Cache Dynamic CSS” in GeneratePress it didn’t help to be able to activate “Optimize CSS delivery” in WP-Rocket that generates critical path CSS.

    There is a “Fallback critical CSS” Box “Provides a fallback if auto-generated critical path CSS is incomplete.”

    I will eventually figure it out as I am quite persistant.

    I did change a few things on the original website using Elementor Pro. When I turned off “Optimize CSS Delivery” in WP Rocket the performance test results were catastrophic. Fail on everything. I wonder what Elementor is going to do.

    Being that I was working with a tool that was so bloated to start with that is why I learned to optimize the crap out of everything inluding server.

    I do understand why the tool is so popular. It’s really convivial, easy to use with tons of step by step guides no CSS or HTML knowledge needed…

    I’m still fighting with the header to display properly & with the layout I want, to get it sticky with a semi-transparent layout on all devices after 15 days of installing the GeneratePress theme & Premium add-on.

    If it wouldn’t be for the stellar performance of test results, above and beyond support I would of dropped this a long time ago…

    Frankly, if there was a WordPress visual web site developing tool that is easy to use, well documented & does everything right I would buy it on the spot…

    Lead Developer
    Lead Developer

    It can certainly be difficult to achieve custom results without hiring a web developer to build it for you (which can be very expensive). We’re quite lucky at the number of tools available today that allow us to get good results, even if they aren’t perfect yet.

    Something to look at for the future is our GenerateBlocks plugin: https://generateblocks.com

    It’s certainly not as feature-packed as Elementor, but it certainly wins when it comes to performance 🙂



    I installed the Gutenberg plugin to have access to the navigation block. The block needs a lot of work to have it up to par with anything available now. The Gutenberg team does not deem it to be necessary since menus are taken care by themes or visual builders. Therefore, they did not include it yet in WordPress core even though they were supposed to do it 2 or 3 major versions ago. For the same reasons there is very limited options to actually make it look good.

    You can add a complete fully featured Gutenberg navigation block to GenerateBlocks Premium to be able to build custom headers using GeneratePress premium “Sections” or was it “Elements” Still lost with the premium features of GeneratePress 🙂

Viewing 15 posts - 1 through 15 (of 17 total)
  • You must be logged in to reply to this topic.