🎨 Optimising CSS Delivery
Tags: css, webdev
Published: 2019-10-04 01:21:44

---
title: 🎨 Optimising CSS Delivery
published: true
description: The Critical point on Critical CSS Delivery
tags: css, webdev
series: A split second later 
cover_image:  https://thepracticaldev.s3.amazonaws.com/i/th6z1vf3u66kjf3pb03u.jpg
---
What would you say, if I told you - delivering JS is a super simple task while delivering CSS is way, WAY MORE COMPLEX? And I've just said it!

# CSS
How many ways to define styles you know? I could name 3:
- `inline styles`. Basic and most __inefficient__ way.
- inlined `<style>`s. The HTML way to define CSS. Better, although not cacheable.
- external `.css` files. The HTTP way to define to deliver styles for the page, and the only one cache-friendly one.

## CSS-in-JS
But the first two options do not require a separate `.css` file to work - they could be delivered to the page using `.js` as transport. 
***
This is what  `CSS-in-JS` is - `css`, defined and delivered in `js`.
***
Even the third option does not require `.css` file - the link to the `blob url`(which is URL) could be generated from JavaScript. So - what does makes CSS-in-JS so special, and so _delightfull_? A __Critical Style Extraction__!

Let me be completely honest - CSS-in-JS usually sucks from the "speed" point of view - JS has a significant cost, and delivering the same styles via plain CSS would be much more efficient and should be preferred at all times if you are looking for the best user experience.
> However keep in mind - some __modern `css-in-js` solutions__( [linaria](https://github.com/callstack/linaria), [astroturf](https://github.com/4Catalyzer/astroturf), [treat](https://github.com/seek-oss/treat)) are becoming pure CSS after the build step.

However, there are two moments, where "real" CSS-in-JS just shines:
- complex auto-generated styles(like dark mode). As long you can autogenerate them in-place, not create 100500 different styles using SASS loop (or your own hands). Sometimes, rarely but still, `css-in-js` might be much much more compact than a pure `css`.
- SSR. Where you can __inline styles__ next to their usage and, actually, creation (in terms if StyledComponents). As a result, you will be able to render a page before fetching real style files(that would take a while). And even more - before parsing all styles on the page(better say - downloading), as long as styles will be _interleaved_ with HTML in a most efficient way.

It's like - defining styles for `header` just before `header`, as well as defining styles `footer` just before `footer` - so you don't have to load anything "extra" to display the next block of HTML. That's makes (HTML) rendering process more streamlined and efficient on slow connections. I mean FAR more efficient, and that's matters! First load matter!

![First load](https://thepracticaldev.s3.amazonaws.com/i/3ll22so2m6x04ugfp2fz.jpg)


> And we need the same goodness for a "normal" CSS

# Optimizing CSS delivery

CSS is a very nasty thing - while we are loading our scripts as `async` or `defer` - __CSS is always sync__. And thus always the highest possible network priority.

As long as without proper CSS you can't properly display HTML - everything, just everything would wait for it to load first. Let me cite one image from [Defer non-critical CSS](https://web.dev/defer-non-critical-css) google article:

![CSS blocking render](https://thepracticaldev.s3.amazonaws.com/i/bomoj0liym7hiyo0iq6p.png)

And there is two way to make this situation better:
- code split CSS files, so you will need less CSS to download here and now, and could spend less time in networking. Always working, but has some limitations, which might prevent this variant from being adopted in your project. Like it does not worth it.
- inline "used" or "critical" CSS, which is usually just a few (dozen) selectors required to display content above the fold.

### The problem with code-splitting
The problem with CSS and code-splitting is not code-splitting, but CSS. I hope you know what is "rule specificity", when a selector defined "later" has more power than a selector defined before.
Everything was simpler with one big `styles.css`, but one you shred it into 5 different files - they could be assembled in an absolutely random order, causing all "css related issues" you ever heard about.

> to use CSS and code splitting you have to be ready handle your CSS code more responsible, and never rely on the correct rule declaration order between different files.

However - keep in mind - CSS code is usually quite compact, comparing to JS, and does not require much time to download and parse. Code splitting for CSS might not be needed

{% twitter 1178798570314448897 %}

***

### Critical CSS and CSS
Is something we want. Is something very, well, delightfull? And is yet another problem. To be more concrete - Google Web Fundamentals Guides, in their [Inlining critical CSS](https://developers.google.com/web/tools/lighthouse/audits/unused-css), are not proposing any _feasible_ solution. Let's move on

According to the `Inlining critical CSS` there are 3 node libraries, which could help you "extract" a `Critical CSS` for a given HTML:
- [penthouse](https://github.com/pocketjoso/penthouse)
- [critical](https://github.com/addyosmani/critical)
- [inline-critical](https://github.com/bezoerb/inline-critical)
- plus [modpagespeed](https://www.modpagespeed.com/doc/filter-css-inline) for your server to do some "optimizations". Which ones?

##### penthouse
For given URL and CSS - produce "critical" CSS. Have no idea how I could use it with JAM stack or for SSR.

Uses puppeteer to detect window size, and thus very slow.

#### critical
A bit more complicated version. But works in the same way.

While both approaches could provide very fine results - their targets are mostly static sites, as long as there is no way you could use them in runtime.

#### inline-critical and modpagespeed
However, these guys could handle runtime. However, they could just inline `.css` you will point finger on. That's not a Critical CSS, and, of course, not "extraction".

> Ensure that the CSS you are planning to inline is genuinely critical to your web page and __you are not inlining everything__. [source](https://www.sitepoint.com/how-and-why-you-should-inline-your-critical-css/)

# Used-styles
So - how to obtain the `CSS-in-JS` level of __critical style extraction__, but for normal CSS? The thing you will also need for all those `css-in-js`, which ends in `.css`, and which I would gently recommend you to use?
Just check which styles were used.

{% github theKashey/used-styles %}

`used-styles` are working quite simple - you are giving them you `dist` directory, they scan it using `PostCSS`, and thus creating the database of styles might use.

Then you are giving them a piece of HTML - `string` or `stream` - and they would tell you which style, from which file, was used. And in which order you shall declare them.

Relax, I am joking - of course, the library would handle everything out of the box, including duplicate prevention. And in case if using React's `renderToStream` - the result would be interleaved with HTML (however correct rule order would not be guaranteed in this case).

Everything works out of the box, except a few tricky moments...

## Tricky moment #1
You still have to load `.css` files. As long you _inlined_ only a small part of all styles, which might be required just after the page start.

Critical CSS is good for FCP(First Content Paint), but might be bad for the application as a whole.

> the inlined CSS will result in some extra page weight every time a user loads your website. For example, if there is 30kB of inline CSS on every page of your website then 10 page views by a single user will cost the user 300kB. It may not sound like a big deal but data is expensive in some parts of the world (and on some 3G/4G data plans). [source](https://www.sitepoint.com/how-and-why-you-should-inline-your-critical-css/)

## Tricky moment #2
Loading these  "missing" CSS would be triggered by your bundler automatically, especially in case of code splitting. And those styles would be loaded at maximal network priority, as long as they are CSS, delaying JS start and making hydrating death valley deeper - you have to manually disable, usually by creating a `<style data-href="real-style.css" />` to indicate that you handled external style manually.

> `used-styles` would tell you which CSS files was used

## Tricky moment #3
Critical CSS is required only for the FIRST visit. Inlining styles second time is a waste of time. You already loaded "real" `.css` files, and their _reloading_ would not consume any time - everything is cached.
In the ideal situation, you have to track (on SSR) which files you already send to the client, and handle them in the "old" way.

> you can control which files should be inlined and which should not

However, this is not so easy and might require some server infrastructure, especially shared cache. (and cookies, at least session cookies)

# Would it help much?
That's a great question! 
- Critical CSS Extraction would work only if you have HTML, so you have to have SSR
- just one file inlining would work any SPA, but it might be not a great idea to inline big files into your HTML - big files are better be cached, as well as inlining small files - they might not change anything - reducing TTFB might have more impact in this case.

Need an example? [the urge](https://theurge.com) uses `used-styles` to make your experience better, however not covering some tricky cases I've listed above.


## More to read
- https://web.dev/extract-critical-css
- https://developers.google.com/web/tools/lighthouse/audits/unused-css
- https://developers.google.com/speed/pagespeed/service/PrioritizeCriticalCSS
- https://github.com/theKashey/used-styles

and of course 👇