← All posts

Inline your CSS until it hurts

One request is faster than two. The interesting question is where the pain starts.

·5 months ago ·3 min read ·556 words

An external stylesheet is a render-blocking request. The browser finds the <link>, stops painting, fetches the file, parses it, and only then puts pixels on screen. On a fast connection this is invisible. On a slow one it is the entire perceived load time of your page, and you paid for it to save a few kilobytes you could have simply included.

So: inline it. Put the CSS in the document, inside a <style> block, and the render-blocking request disappears because there is nothing left to block on. One round trip instead of two, and the first response contains everything needed to draw the page.

This advice comes with an obvious objection, and the objection is correct.

The cache argument, with actual numbers

An external stylesheet is cached once and reused on every subsequent page. Inlined CSS is re-sent with every document. If your CSS is 8 kB compressed and a reader views five pages, inlining costs 40 kB against the external file's 8 kB plus one extra round trip.

Which is worse depends entirely on the shape of your traffic, so work it out rather than guessing:

  • Cost of inlining = CSS size × pages viewed per visit.
  • Cost of linking = CSS size + one extra round trip on the first page, and on every page for readers arriving with a cold cache.

Now plug in real values. Most content sites see a large majority of visits land on one page from a search engine or a link, read it, and leave. For those readers there is no second page and the cache never pays out. Meanwhile the round trip they saved is worth 100–300 ms on mobile. If your whole stylesheet is under about 10 kB compressed, inlining wins for that traffic and it is not close.

Invert the numbers and the answer inverts too. A documentation site where people read fifteen pages per session, with 60 kB of CSS, should absolutely link an external file and let the cache do its job.

Where it starts to hurt

The reason to say "until it hurts" rather than "always" is that there are three real limits, and you will meet them in this order.

Size. Once the inlined CSS is pushing the top of your document past that first fourteen-kilobyte window, it has stopped buying speed and started spending it.

Duplication across pages. If every page carries the styles for every component on the site, you are re-sending a design system to someone reading one article. The fix is to inline only what the page needs, which means knowing what the page needs, which means either discipline or tooling.

Maintenance. Styles inlined by hand into a dozen templates will drift. Styles inlined from one shared partial will not. This site keeps its entire stylesheet in a single PHP include; every page emits the same block, and there is exactly one place to change a colour.

A reasonable middle

Inline the critical CSS — everything needed to paint what is above the fold — and load the rest asynchronously so it never blocks:

<style>/* critical, inlined */</style>
<link rel="stylesheet" href="/rest.css" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="/rest.css"></noscript>

That pattern is well worn and it works. It is also machinery, and machinery has to be justified. If your entire stylesheet is smaller than the average hero image, skip the machinery and inline the lot.

Related reading