I wrote a PostCSS plugin that allows you to annotate your CSS with comments to indicate what’s to be considered critical CSS and what is not.
It’s 2016. By now, web standards are deeply engraved in everyone’s mind, it’s ridiculous to even bring them up. SEO is more of an extra while it once used to be the main focus of your development cycle. Responsive design is so common, it’s actually become a boring subject. The thing that is cool these days is ‘mobile-first‘. And while people right and left are using this term (without the slightest clue as to what it actually means), only a hand full of people/companies have nailed ‘mobile-first‘.
- In the following article, I refer to mobile first as the development workflow, not the design strategy (yes, they are very different things).
- In terms of development strategy, I think ‘mobile-first‘ is a load of bullshit. What it basically means is ‘speed-first‘ or ‘performance-first‘. Think about it.
About critical CSS
One of the tricks to optimize your website’s performance -and thus the (perceived) speed- is Critical CSS: You inline the critical CSS code into the ‘<head>‘ tag of your page and load the other CSS styles asynchronously. This allows for a non-blocking webpage rendering experience. In human terms this means: Your HTML gets rendered faster by the browser. To the user it looks like the site is ‘ready’ blazingly fast while in actuality we’re still loading some more stuff and doing more magic. I’ll write more about Critical CSS in the future but for now, if you want to know more about it: Google it. Tons of great articles out there.
Current critical CSS techniques
I have been using this approach and technique for several months now and I noticed that basically nobody has come up with a solid workflow to make and maintain their critical CSS. If you search for some time, you’ll come across the craziest approaches.
For example: there are services like this one where you can paste your CSS-code and submit the link to your website. The service will then detect which styles are critical. Not the kind of automation I was looking for but fairly simple. Great for small-scale projects that done’t require frequent maintenance.
Other approaches use Gulp tasks that will automate the above task by running your webpage through several browser window sizes. However, the problem is that this automation is far from perfect as the task is performaned by a computer that doesn’t have eyes. So it detects DOM elements that are not visible to the human eye but visible to the browser, so it copies all the relevant (but not required) styles in the critical CSS.
And then there’s task of making sure that dynamic template changes are taken into account when automating this. If the user can change the fold’s look (possible in many WordPress themes for example), the critical CSS can heavily change depending on which layout is currently active. In order to manage this, you need to run the process on all variations of the templates.
Of course there’s the elephant in the room that nobody wants to talk about: For this approach to work, you first have to build your site, then load it into a browser and then… build it again. Sounds backwards.
Last but not least: You need to manually insert every URL that needs to be critical-validated. Basically what this means is that the ‘automation’ is done for you, but you have to verify the generated code, not forget about all possible alterations of your potential layouts, think of the relevant browser sizes and maintain a list of URL’s.
So instead of actually automating the critical CSS workflow, you have now automated the workflow at the cost of maintaining a human-error-prone list of options that can not be automated once again.
My take on Critical CSS: PostCSS-Critical-Split
Whenever I worked on an HTML/CSS template, I immediately knew which parts would be considered critical and which ones wouldn’t be. Sometimes a CSS rule that had 20 declarations would be entirely non-critical except for that 1 single line. Any of the above approaches would have grabbled al 20 declarations while 1 would have sufficed.
I also know which blocks might show up above the fold based on the sites template options. Therefor, I know they would be (or any part of it) critical. This allowed me for a fast development cycle with high accuracy. Before building my own PostCSS plugin, I would write 2 separate CSS files: One ‘late’-CSS and one critical-CSS. However this became really messy and unmaintainable really fast.
I quickly came to the conclusion that -as a developer- knew which CSS rules and declarations were critical and which ones weren’t. I could open a CSS file and point to those declarations and say ‘this must go into the critical CSS‘. So I built a PostCSS plugin around this human thinking: Just point out in the CSS file what is critical and what isn’t and let the computer do the rest.
To accomplish this, I write comments in my CSS files and then I let a PostCSS task check the file for these comments and PostCSS does as it is told: It moves the critical CSS into a separate CSS file which you can then inline in the <head> of your webpage.
I hear you thinking: “Dude, that’s not automation at all! I gotta do all the work myself“! WelL.. Yea. Whenever you write CSS you have to decide whether something is critical or not. That is literally ALL you have to do while PostCSS does the actual work… you know, like going over your 2000 lines of CSS upon every save and splitting up your CSS into 2 files and copying all the selectors and declarations and removing them from the original file in the exact order you want…
If you include this workflow right from the start of your project, this will create little to no overhead at all. Ever.
If you decide to implement this workflow in your existing 500-layouts-website, then yes: there’s a bit of manual labour involved going over all the styles. Although I’m fairly sure, if your CSS is well written, you could probably manage to accomplish this in an afternoon’s work.
How does it work exactly?
Well, I use a Gulp-setup which watches all my SCSS files. Upon SCSS changes, the full CSS file is generated. Then I run the PostCSS Critical Split task that effectively splits the one file up into 2 separate files: a late-CSS file and a critical-CSS file. Then I run my tasks to further clean up these files (autoprefixer, minify, remove comments, etc) and then I inline the generated CSS into the HTML template file that later gets added into the other HTML files. Below is an example of what an annotated CSS file looks like.
Not too bad, right? The cool thing about this is that doesn’t break your CSS if you decide to no longer use the PostCSS Critical Split plugin. The comments that remain in place are valid CSS comments. Not breaking 😉
There are 2 types of critical-tag comments currently supported:
- BlockTags that go in any rule and absorb that rule completely into the critical CSS file.
- Start- and stop-tags that indicate a starting and ending point in your CSS. All CSS between these 2 points is carried over to the the critical CSS file.
If you want to see more actual code examples, you should check out my Critical CSS example on Github.