Prathamesh Gharat
Prathamesh Gharat

Reputation: 146

Defer unused CSS

I have a critcal CSS process in place that prevents a flash-of-unstyled-content (FOUC) on above-the-fold content of a page.

I'm stuck on 'defer unused CSS' point that's being highlighted by Google PageSpeed insights (lighthouse) and/or Chrome's Performance Audit.

I've gone through other articles but they do not work.

To summarize I've tried so far.

Ref: CSS delivery optimization: How to defer css loading?

If I delay loading the script via setTimeout by a fixed time of 3 seconds the 'defer unused CSS' issue goes away. 3 seconds is what's needed for Google PageSpeed Insights test (mobile) as they are slower devices but 3 seconds is a lot for desktops which generally has more processing power (note, not always true, hence excluding user-agent based logic).

So the question boils down to how do I delay loading the CSS by the least amount of time irrespective of the device type or specs.

Feel free to throw any rough ideas, I'll try them out and report back, if your idea works, we'll update the code and mark your answer has the chosen one.

Next on my list to try is requestAnimationFrame + small fixed delay.

Upvotes: 2

Views: 1912

Answers (1)

Prathamesh Gharat
Prathamesh Gharat

Reputation: 146

Manually loading a CSS based on two triggers, whichever occurs first.

  • [setTimeout of 2500ms]
  • [Scroll event]
<script>
    var raf = requestAnimationFrame || mozRequestAnimationFrame ||
    webkitRequestAnimationFrame || msRequestAnimationFrame;
    var app_css_loaded = false;
    /* console.log(performance.now() + ' - ' + '1. async css script init'); */
    var loadAppCss = function(){
        if(!app_css_loaded) {
            app_css_loaded = true;
            var l = document.createElement('link'); l.rel = 'stylesheet';
            l.href = 'YOUR_COMBINED_AND_MINIFIED_CSS_HERE.css';
            var h = document.getElementsByTagName('head')[0]; h.parentNode.insertBefore(l, h);
            /* console.log(performance.now() + ' - ' + '5. script injected'); */
        }
    };
    var cb = function() {
        /* console.log(performance.now() + ' - ' + '3. cb called'); */
        setTimeout(function(){
            /* console.log(performance.now() + ' - ' + '4. timeout start'); */
            loadAppCss();
            /* console.log(performance.now() + ' - ' + '6. timeout end'); */
        }, 3000);
    };

    window.addEventListener('load', function(){
        /* console.log(performance.now() + ' - ' + '2. triggering cb directly'); */
        if(raf) { raf(cb); } else { cb(); };
    });
    var loadAppCssOnScroll = function(){
        /* console.log(performance.now() + ' - ' + '### triggering cb on scroll'); */
        window.removeEventListener('scroll', loadAppCssOnScroll);
        if(raf) { raf(loadAppCss); } else { loadAppCss() };
    };
    window.addEventListener('scroll', loadAppCssOnScroll);
</script>

This makes the PageSpeed insights recommendation regarding defer unused CSS go away.

requestAnimationFrame, if available, will stall the CSS file from loading if the tab has opened in the background in most browsers. You could remove it from the above code if it does not meet your requirements. Ref

console.log() is not available in all browsers. Do not use it in production. Ref

Upvotes: 1

Related Questions