Responsive menu (mmenu) cause high CLS

Viewed 1009

I am using mmenu as responsive menu on my website. I noticed recently that in Googles search console I have errors due to high CLS (Cumulative Layout Shift). I checked and it's true, when I try to open my page in "slow" mode for a half sec I see the original menu structure, then mmenu loads (after jQuery is ready etc) and the page is showing correctly.

My simplified page structure is:

    $(document).ready(function() {
        $("#menu").mmenu({
            "extensions": ["pageshadow"],
            "header": {
                "title": "Menu",
                "add": true,
                "update": true
            }
        }, {
            // config
            offCanvas: {
                pageSelector: "#container"
            }
        });
    });
    <html>
    <head>
    </head>
    <body>
    <nav id="menu">
        <ul>
            
            <li><a>Categories</a>
            <ul>
                <li>
                    <a href="https://example.com/1">Link 1</a>
                </li>
                <li>
                    <a href="https://example.com/2">Link 2</a>
                </li>
                <li>
                    <a href="https://example.com/3">Link 3</a>
                </li>
            </ul>
        </nav>
        <div class="content">This is content</div>
    </body>
    </html>

What do you think, is it possible to apply any quick fix here which will fix my CLS issue?

4 Answers

Without any experience with mmenu, shouldn't it be sufficient to hide #menu using CSS and only display it once the menu is initialized?

This seems to work for me:

<html>
<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jQuery.mmenu/8.5.20/mmenu.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jQuery.mmenu/8.5.20/mmenu.min.css" />
</head>
<script type="text/javascript" data-no-instant>
$(document).ready(function() {
    $("#menu").mmenu({
        "extensions": ["pageshadow"],
        "header": {
            "title": "Menu",
            "add": true,
            "update": true
        }
    }, {
        // config
        offCanvas: {
            pageSelector: "#container"
        }
    }).css("display", "");
});
</script>
</head>
<body>
    <nav id="menu" style="display: none">
      <!-- <nav> content from your example -->
    </nav>
    <a href="#menu">open menu</a>
    <div class="content">This is content</div>
</body>
</html>

It's hard to answer without seeing the actual code, but to not have to wait for the entire page to be ready you could position your scripts in such a way that you don't need to use the ready call of jQuery.

Try the following:
1 - Load jQuery locally instead from a CDN
2 - Place jQuery script tag before your actual Body html data and place that mmenu call right after the body's html code, that way the content won't be shown before everything has loaded

Another alterantive is to have your body to display a loading animation until jQuery and other cdns have loaded, so you'll be able to fetch everything, run that mmenu call and only then display the content to the user, this method is a little more user-friendly then what I suggested because instead of a blank screen it'll actually show some feedback that the content is being loaded for users with a slower connection.

The way I would handle this is to have a dummy element that has the same size/shape/color of your problem element to act as a placeholder while having the problem element hidden. After jQuery is loaded, I would then remove/hide the dummy element and show the problem one.

To resolve such issue, you would require to change some code structure and ordering of java script and CSS and that would require some efforts/testing.

But you can try by showing a loader/progress bar until "mmenu" is loaded and that might resolve your issue.

Related