CSS is Render Blocking
I like that CSS is what you’d call “render blocking”. If it wasn’t, the web would either be very jerky-looking all the time, with extreme “Flashes of Unstyled Content” (FOUC). But knowing that it is, doesn’t it make sense that we try to load as little of it as we can, especially upfront?
Lots of tools attempt to help with this. This is the whole mission of what we call “Critical CSS”, where the only CSS that loads is that which is needed for that very first paint, and the rest is deferred. Even to the point where ideally that little chunk of CSS is in the first network packet that comes across the wire! This very site is a WordPress site, and uses the free plugin Jetpack Boost to do it, which is impressive.
Blocking JS execution is bad. In today’s JS-rich apps a delay like this is a life/death situation. If it was a “progressive enhancement” JS that makes a readable article even more enjoyable, fine. But an app not showing your email message you’ve beeen eagerly awaiting just because of a network packet hiccup in CSS… that sucks.
So what can we consider here? Well what if we made CSS “asynchronous”? Meaning it would stop blocking any other resources. Turns out this is trivially easy, as Scott Jehl noted in The Simplest Way to Load CSS Asynchronously:
defer on the
It will execute as soon as the browser sees it, not waiting for the CSS to load. Weird trick. Probably not trivially easy to take advantage of. But good to know when you absolutely need it.
Using Less CSS
Knowing that CSS is a blocking resource has led people down other performance paths. Stoyan wrote another article this year introducing a quick little bookmarklet to test not loading some stylesheets at all. Certainly, yes, if you have junk stylesheets that do nothing for you, those need to get gone. But what about just loading less CSS in general? Certainly, you’ll want to minify it and serve it as compressed as possible, that helps. You’ll want to make sure it’s cached so subsequent page loads pluck it out of cache. Those are just classics of web performance work. Removing unused CSS is also another path here, albeit an extremely tricky one.
Another player here is this whole world of Atomic CSS. I’ve never hide the fact that I don’t really like the idea of styling elements through HTML classes (or other attributes). But that’s just me, the proof is out there that lots of web developers really like it. I’m talking about the approach of Tailwind or Windi CSS, and before them, something like Tachyons, and before that, something like Atomizer. They all share this concept where you make styling decisions with HTML classes, and with most of them, minimal CSS can be generated that covers all the things that those HTML classes have asked for. The end result is CSS that is almost always far smaller than CSS you’d hand author.
Performance isn’t even one of the things these frameworks tout as a benefit of them. It’s usually more about “speed” or “maintainability”. I’m not convinced on those terms, but smaller CSS can’t really be argued against and has very clear benefits.
What about CSS in JS?
You might be wondering how all this CSS-in-JS stuff factors into CSS web performance. Imagine a major player like styled-components where you aren’t authoring CSS in a
You’d think all this might come out in the wash, but the data that I’ve seen suggests that CSS-in-JS is almost certainly a slower approach. Tomas Pustelnik:
TLDR: Don’t use runtime CSS-in-JS if you care about the load performance of your site. Simply less JS = Faster Site.
I believe we (developers) should think more about the impact of the tools we choose for our projects. The next time I will start a new project, I will not use runtime CSS-in-JS anymore. I will either use good old CSS or use some build-time CSS-in-JS alternative to get my styles out of JS bundles.
But note that Tomas was testing styled-components against another library that I would think many people still think of as a CSS-in-JS library: Linaria. In fact, it looks quite a bit like styled-components looks when authoring. But the major difference is that Linaria spits out
*.css files that you load in the traditional way. They call that “zero-runtime” in CSS-in-JS circles.
It’s taken for granted at this point that when it comes to CSS, the best performance is… CSS. Just as little of it as is reasonably possible.