Skip to content

Instantly share code, notes, and snippets.

@matt-bailey
Last active March 17, 2021 22:09
Show Gist options
  • Save matt-bailey/602b40c77a5d3381ff26 to your computer and use it in GitHub Desktop.
Save matt-bailey/602b40c77a5d3381ff26 to your computer and use it in GitHub Desktop.
A simple script (based on one by Google) for loading CSS files asynchronously and conditionally based on body tag classes
<html>
<head>
<!-- Inlined critical styles -->
<style>.blue{color:blue;}</style>
<!-- CSS loader -->
<script>
/* ==========================================================================
Load CSS asynchronously and conditionally after initial painting
========================================================================== */
/**
* Modified function based on: https://developers.google.com/speed/docs/insights/OptimizeCSSDelivery
*/
/* Settings */
// Pass in a string containing your body tag classes here
// Your CMS will usually have a template function you can use for this purpose
var bodyClasses = 'class-name-one misc-class awesome-class';
// Define the class names and CSS files to match up with them
var pagetypeCssData = [
{
test: '', // Leaving this blank will load the files below on every page
files: ['file-one.min.css', 'file-two.min.css']
}, {
test: 'class-name-one',
files: ['file-three.min.css', 'file-four.min.css']
}, {
test: 'class-name-two',
files: ['file-five.min.css', 'file-six.min.css']
}
];
// You can reverse the array so the files are processed in reverse order if you wish
// pagetypeCssData.reverse();
/* Function to test if (body tag classes) string contains some text */
function stringHasText(string, text) {
if(string.indexOf(text) >= 0) {
return true;
} else {
return false;
}
}
var cb = function() {
/* Function to set media type to all */
function setMedia(element) {
setTimeout(function() {
element.media = 'all';
});
}
/* Loop through pagetypeCssData[] and process the results */
for (var prop in pagetypeCssData) {
if (stringHasText(bodyClasses, pagetypeCssData[prop].test)) {
for (var i = 0, l = pagetypeCssData[prop].files.length; i < l; i++) {
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = '/path/to/css/directory/' + pagetypeCssData[prop].files[i];
// Set media type to something non-matching so it doesn't block the render
// Reference: https://github.com/filamentgroup/loadCSS/blob/master/loadCSS.js
link.media = 'only x';
var firstScriptTag = document.getElementsByTagName('script')[0];
// Insert CSS file before first script tag
firstScriptTag.parentNode.insertBefore(link, firstScriptTag);
// Set the media type back to all
setMedia(link);
}
}
}
};
var raf = requestAnimationFrame || mozRequestAnimationFrame || webkitRequestAnimationFrame || msRequestAnimationFrame;
if (raf) {
raf(cb);
} else {
window.addEventListener('load', cb);
}
</script>
</head>
<body class="class-name-one misc-class awesome-class">
<div class="blue">Hello, world!</div>
</body>
</html>
@matt-bailey
Copy link
Author

I wanted a way to be able to asynchronously and conditionally load CSS files based on 'pagetype', so I modified a script by Google, found here: https://developers.google.com/speed/docs/insights/OptimizeCSSDelivery

@matt-bailey
Copy link
Author

It has come to my attention that requestAnimationFrame is not supported by IE 9<, iOS 5<, and Android.

If you need to support these browsers/OSs you can easily fix it by using a polyfill. Here's a gist by Paul Irish for just that purpose.

@lookfirst
Copy link

indexOf is also ie9+ and your function can be written more cleanly...

function stringHasText(string, text) {
    return string.indexOf(text) !== -1;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment