13 September 2026

Inline CSS vs. External CSS: When Critical CSS Really Makes a Difference

Inline or external CSS stylesheet? A change of mindset is needed to truly understand the problem and approach Critical CSS.

Inline CSS VS External and Critical CSS

When it comes to web performance optimization, sooner or later we always come across the same question: is it better to insert CSS directly into the HTML page or load it through one or more external style sheets?

The seemingly most correct answer would seem simple: put the CSS in an external file, have the browser download it once, and let it cache. This will incur a small additional cost on the first page, but during subsequent browsing that file will already be available locally, and all other pages will be faster.

This is technically sound reasoning.

The problem is that it starts from an assumption that very often does not correspond to the way users actually use the Web:

that after the first page there necessarily exists a second.

Many visits begin on Google, a social network, a newsletter, an aggregator, or a link shared on WhatsApp. The user opens a page, reads what interests them, and leaves.

The “subsequent navigation,” the one for which we agreed to make the first load slightly slower in exchange for the cache advantage, simply doesn’t happen.

And this is where the way we should think about performance changes completely.

External CSS and its great advantage: caching

The classic way to include a style sheet in a page is this:

<link rel="stylesheet" href="/css/style.css">

It's a clean solution, simple to maintain, and most importantly, very efficient when the same CSS is used on many pages.

The browser downloads style.css and, if the HTTP caching headers are configured correctly, it can keep it in its own cache.

When the user opens a second page that uses the same file, it doesn't necessarily need to transfer all those bytes over the network again.

For a site with hundreds or thousands of pages, this represents a significant advantage.

A single stylesheet can contain rules for headers, footers, menus, articles, sidebars, forms, buttons, tables, e-commerce, and so on.

From a development point of view, it's also very convenient: you modify a file and the change is propagated to the entire site.

The problem with external CSS, however, is its role within the Critical Rendering Path.

Why an external CSS sheet can slow down the first rendering

When the browser receives the HTML document, it begins reading it from top to bottom.

When you encounter something like this:

<head>
    <link rel="stylesheet" href="/css/style.css">
</head>

finds that to display the page correctly it must also retrieve style.css.

The browser can continue to do other work, but the stylesheet is normally considered a render-blocking resource : before it can properly paint the content, it must download and parse the CSS needed to build the CSSOM.

The reason is perfectly logical.

Showing a completely blank page first and redrawing it half a second later would result in a terrible viewing experience.

remove-css

As a result, the browser prefers to wait.

On a fast connection this wait may seem insignificant.

And this is precisely where one of the most common biases in web development arises.

The site is very fast. Yes, from the office fiber optics.

Website developers spend much of their day connected to networks that are significantly better than those used by a significant portion of users.

FTTH fiber, business connections, fast Wi-Fi, 5G with excellent signal.

Under these conditions, an additional request to download 50, 100, or 200 KB of CSS seems almost irrelevant—a matter of 50 milliseconds. To the human eye, anything under 200 milliseconds is perceived as instantaneous. Usain Bolt, at the starting blocks, had a record-breaking reaction time of 146 milliseconds. Usain Bolt. The fastest man on earth.

Usain Bolt Blocks

In short, from the office fiber or from fast 5G, the page opens and everything appears immediately.

The problem arises when the same site is used under different conditions.

Imagine a smartphone connected to a 4G network with mediocre coverage, perhaps in a mountainous area of ​​the Apennines, inside a building with thick walls, or in a tourist resort far from major network infrastructure.

I personally remember similar situations very well during some summer holidays in Sardinia: all it took was moving to certain areas for a connection that on paper was 4G to suddenly become slow, unstable, and with a latency completely different from what we are used to in the city.

And latency is precisely one of the aspects that are most easily underestimated.

It's not just how many megabits per second the connection can theoretically transfer.

It measures the time between the discovery of the resource, the request to the server, and the arrival of the first data.

In the lab or on the office fiber optics, everything can seem instantaneous. On the move, in real-world conditions, every additional critical dependency can become much more apparent.

The “slightly slower front page” bias

The traditional reasoning is often this:

"Okay, on the first visit it has to download the CSS. It will be a little slower. But then the file remains cached and all subsequent pages will be very fast."

This is not a bad reasoning from a computer science point of view.

It is wrong when it is automatically transformed into a description of user behavior.

For many sessions, the first page is also the last.

A user searches on Google:

“How to set up Redis on WordPress?”

opens the result he's interested in, reads the article, finds the answer, and closes the tab.

It doesn't open the home page.

Do not visit the category.

He doesn't consult five other articles.

It never gets to that phantom second page where we would have recovered the initial cost thanks to the cache.

The same happens with advertising landing pages, editorial articles, product pages from Google Shopping, pages shared on social media, technical documentation, and many other types of content.

For this reason the goal should not only be:

“make navigation within the site quicker”.

It should be first of all:

“make the page the user has decided to open now very fast.”

So let's put all the CSS inline?

At this point it might seem natural to come to the opposite conclusion.

If the external CSS requires an additional resource, let's insert it directly into the HTML:

<head>
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cstyle%3E%0Abody%20%7B%0A%20%20%20%20margin%3A%200%3B%0A%20%20%20%20font-family%3A%20Arial%2C%20sans-serif%3B%0A%7D%0A%0A.header%20%7B%0Abackground%3A%20%23111%3B%0Acolor%3A%20%23fff%3B%0A%7D%0A%0A.article%20%7B%0Amax-width%3A%201200px%3B%0Amargin%3A%200%20auto%3B%0A%7D%20%3C%2Fstyle%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object mce-object-style" width="20" height="20" alt="&lt;style&gt;" />

</head>

This way the CSS rules arrive together with the HTML.

You don't have to wait for a separate request to get that stylesheet.

It looks perfect.

But even this solution, taken to the extreme, creates a problem.

The Inline CSS Problem: HTML Gets Huge

It's one thing to insert a few kilobytes of CSS into a page.

Another is to incorporate the entire stylesheet of a modern site.

On WordPress, WooCommerce, Magento, PrestaShop, or sites built with page builders and CSS frameworks, it's not uncommon to end up with hundreds of kilobytes of rules.

If we take all that CSS and insert it directly into each HTML document we've eliminated an external request, but we've created another problem:

We have greatly inflated the main document.

An HTML page that originally weighed 60 KB could end up weighing 250, 300, or 400 KB before even considering JavaScript, images, fonts, and other resources.

And HTML is a particularly important resource because it is the starting point for all loading.

The sooner the browser receives and parses the document, the sooner it can discover images, scripts, fonts, preloads, and all other dependencies.

Filling the document with hundreds of kilobytes of CSS therefore means increasing the amount of data that must arrive at the most delicate loading phase.

And we also lose one of the main advantages of caching

Then there is another substantial difference.

A file like:

<link rel="stylesheet" href="/css/style.min.css">

It can be stored separately from the browser and reused across hundreds of pages.

If, however, that same 150KB of CSS is inserted directly into the HTML, it is embedded in every document.

Page A contains those 150 KB.

Page B contains those 150 KB again.

Page C still contains those 150 KB.

Inline CSS cannot benefit from caching as a standalone resource.

Of course, the HTML document itself can be cached in various forms, but we no longer have that elegant separation where a shared resource is downloaded once and reused through different URLs.

We are therefore faced with a classic compromise.

External CSS vs. Inline CSS: Both are Right and Both are Wrong

External CSS offers:

  • excellent reusability;
  • HTML document-independent cache;
  • easier maintenance;
  • Lighter HTML;
  • a single file that can be shared across many pages.

But it can introduce a render-blocking network dependency right at the most important moment: the first load.

Inline CSS, on the other hand, eliminates the need for inline styles and makes the rules in the document immediately available to the browser.

But if we put too much of it:

  • let's inflate the HTML;
  • we repeat the same rules on different pages;
  • we lose some of the benefits of external CSS caching;
  • we increase the work of transferring and parsing the document;
  • We make it harder to manage and update code.

The solution, as often happens in performance optimization, does not lie in one of the two extremes.

The solution is called Critical CSS

Critical CSS starts from a very simple question:

How much CSS is really needed to immediately display what the user sees when they open the page?

Above The Fold

Not as much CSS as the entire site needs.

Not as much CSS as the footer needs, which is 6.000 pixels below.

Not as much CSS as the modal window that might open needs.

Not as much CSS as the checkout page needs while we're reading an article.

Only what is needed to correctly build the first viewport, the so-called above-the-fold content.

That small amount of CSS is inserted directly into the HTML document:

<head>
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cstyle%3E%0A%2F*%20Critical%20CSS%20*%2F%0Abody%20%7B%0A%20%20%20%20margin%3A%200%3B%0A%20%20%20%20font-family%3A%20system-ui%2C%20sans-serif%3B%0A%7D%0A%0A.site-header%20%7B%0Aheight%3A%2080px%3B%0Abackground%3A%20%23fff%3B%0A%7D%0A%0A.hero%20%7B%0Amax-width%3A%201200px%3B%0Amargin%3A%200%20auto%3B%0A%7D%0A%0A.article-title%20%7B%0Afont-size%3A%2042px%3B%0Aline-height%3A%201.1%3B%0A%7D%20%3C%2Fstyle%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object mce-object-style" width="20" height="20" alt="&lt;style&gt;" />

</head>

At this point the browser already has everything it needs to immediately display the initial part of the page.

The rest of the CSS continues to live in an external stylesheet.

This is the fundamental difference.

We're not inlining all CSS. We're inlining only critical CSS.

The rest of the CSS can come later

After immediately providing the essential styles for the first rendering, the complete sheet can continue to be downloaded separately.

Conceptually, architecture becomes:

Critical CSS Diagram

The browser can then quickly display the header, title, hero, main image, and initial content, while the non-critical CSS is fetched to complete the rest of the page.

In certain implementations, the non-critical sheet can be loaded in a non-blocking manner, for example through preload strategies and subsequent application of the stylesheet.

A historically used technique is conceptually similar to this:

<link rel="preload"
      href="/css/style.min.css"
      as="style"
      onload="this.onload=null;this.rel='stylesheet'">

<noscript>
    <link rel="stylesheet" href="/css/style.min.css">
</noscript>

This does not mean that this specific implementation should be used indiscriminately on every site: asynchronous CSS loading must be designed and, above all, tested, because there are implications related to Content Security Policy, compatibility, resource priority, and possible FOUC phenomena.

The principle, however, remains valid: make immediately available what is needed now and postpone what will be needed later.

Critical CSS doesn't just mean “small CSS”

A common mistake is to think that taking the first 200 lines of the stylesheet is enough.

It does not work like that.

Critical CSS depends on the content actually present in the first viewport.

A homepage may need hero styles.

An article page with the title, author, breadcrumb, and featured image styles.

A product sheet with price, gallery, availability and purchase button.

The ideal critical CSS can therefore be different between different templates.

Responsive design should also be considered.

What appears above the fold on a 1920×1080 desktop monitor doesn’t necessarily match what appears above the fold on a 390-pixel-wide smartphone.

For this reason, a good implementation of Critical CSS should be automated within the build, caching, or optimization process , rather than being manually maintained line by line.

Critical CSS must not become another inline monster

But there is a trap.

Some systems that promise to generate Critical CSS end up inserting huge amounts of CSS into the document “just in case”.

If Critical CSS reaches 100, 150, or 200 KB, we have lost much of the advantage.

The purpose is exactly the opposite:

Inline CSS should contain the bare minimum to properly render the first significant content.

Everything else should stay off the critical path.

It is therefore necessary to measure.

Chrome DevTools, Coverage, Performance panel, and network throttling tests are much more useful than just the feeling that “it opens right away on my computer.”

Test the site as a user with a poor connection would see it

This is probably the most important tip.

If you're developing a website connected to a hundreds-megabit FTTH connection, don't use your browsing experience as a benchmark.

Google Chrome Throttling

 

Simulate high latencies.

Limit bandwidth.

Try less powerful CPUs.

Watch what happens when every network request stops feeling free.

It is precisely under these conditions that the Critical Rendering Path becomes evident.

An external CSS file that arrives on your desktop almost instantly can become the reason why a user is left staring at a blank screen or incomplete content for hundreds of milliseconds longer.

On a single-page visit, those milliseconds will never be “recovered” from the cache during subsequent browsing.

The solution is not to choose between inline and external CSS

The real question, then, should not be:

“Inline CSS or external CSS?”

That's too simple a question for a problem of priorities and timing.

The correct question is:

“What CSS do we need now and what CSS can come later?”

The CSS you need immediately must be small, focused, and available without introducing additional critical dependencies.

The global, reusable, and less urgent CSS can instead remain external, benefit from caching, and serve the rest of the page and navigation.

Conclusion: Optimize the first page as if it were the last.

For years we have been thinking about web performance by imagining a fairly linear sequence:

Slightly slower first page, shared resource download, cache, very fast subsequent navigation.

From a technical point of view it is a perfectly valid model.

From the perspective of the modern user, however, it is often incomplete.

The front page may be the only page that user will visit.

We cannot therefore excessively sacrifice the initial loading in the hope of recovering the cost on a second navigation that may never happen.

At the same time, cramming hundreds of kilobytes of CSS directly into every HTML document isn't the solution: it means repeatedly transferring unnecessary rules, bloating the document, and giving up one of the main benefits of external style sheets: their ability to be cached and reused.

Critical CSS represents a much smarter compromise.

Very little inline CSS to immediately display what's important. External CSS for everything else.

It's an approach that doesn't just optimize the number of requests.

Above all, optimize the moment when those resources become necessary.

And this is, after all, one of the most important rules of modern web performance:

You don't necessarily need to download less. Above all, you should avoid waiting for things you don't yet need.

Because the user doesn't judge us on the theoretical speed of the fifth page visited.

It judges us the exact moment we tap a Google result, open our website, and wait for something to appear on the screen.

And in that moment we have only one chance to appear fast: to be fast right away.

Do you have doubts? Don't know where to start? Contact us!

We have all the answers to your questions to help you make the right choice.

Chat with us

Chat directly with our presales support.

0256569681

Contact us by phone during office hours 9:30 - 19:30

Contact us online

Open a request directly in the contact area.

DISCLAIMER, Legal Notes and Copyright. RedHat, Inc. holds the rights to Red Hat®, RHEL®, RedHat Linux®, and CentOS®; AlmaLinux™ is a trademark of the AlmaLinux OS Foundation; Rocky Linux® is a registered trademark of the Rocky Linux Foundation; SUSE® is a registered trademark of SUSE LLC; Canonical Ltd. holds the rights to Ubuntu®; Software in the Public Interest, Inc. holds the rights to Debian®; Linus Torvalds holds the rights to Linux®; FreeBSD® is a registered trademark of The FreeBSD Foundation; NetBSD® is a registered trademark of The NetBSD Foundation; OpenBSD® is a registered trademark of Theo de Raadt; Oracle Corporation holds the rights to Oracle®, MySQL®, MyRocks®, VirtualBox®, and ZFS®; Percona® is a registered trademark of Percona LLC; MariaDB® is a registered trademark of MariaDB Corporation Ab; PostgreSQL® is a registered trademark of PostgreSQL Global Development Group; SQLite® is a registered trademark of Hipp, Wyrick & Company, Inc.; KeyDB® is a registered trademark of EQ Alpha Technology Ltd.; Typesense® is a registered trademark of Typesense Inc.; REDIS® is a registered trademark of Redis Labs Ltd; F5 Networks, Inc. owns the rights to NGINX® and NGINX Plus®; Varnish® is a registered trademark of Varnish Software AB; HAProxy® is a registered trademark of HAProxy Technologies LLC; Traefik® is a registered trademark of Traefik Labs; Envoy® is a registered trademark of CNCF; Adobe Inc. owns the rights to Magento®; PrestaShop® is a registered trademark of PrestaShop SA; OpenCart® is a registered trademark of OpenCart Limited; Automattic Inc. holds the rights to WordPress®, WooCommerce®, and JetPack®; Open Source Matters, Inc. owns the rights to Joomla®; Dries Buytaert owns the rights to Drupal®; Shopify® is a registered trademark of Shopify Inc.; BigCommerce® is a registered trademark of BigCommerce Pty. Ltd.; TYPO3® is a registered trademark of the TYPO3 Association; Ghost® is a registered trademark of the Ghost Foundation; Amazon Web Services, Inc. owns the rights to AWS® and Amazon SES®; Google LLC owns the rights to Google Cloud™, Chrome™, and Google Kubernetes Engine™; Alibaba Cloud® is a registered trademark of Alibaba Group Holding Limited; DigitalOcean® is a registered trademark of DigitalOcean, LLC; Linode® is a registered trademark of Linode, LLC; Vultr® is a registered trademark of The Constant Company, LLC; Akamai® is a registered trademark of Akamai Technologies, Inc.; Fastly® is a registered trademark of Fastly, Inc.; Let's Encrypt® is a registered trademark of the Internet Security Research Group; Microsoft Corporation owns the rights to Microsoft®, Azure®, Windows®, Office®, and Internet Explorer®; Mozilla Foundation owns the rights to Firefox®; Apache® is a registered trademark of The Apache Software Foundation; Apache Tomcat® is a registered trademark of The Apache Software Foundation; PHP® is a registered trademark of the PHP Group; Docker® is a registered trademark of Docker, Inc.; Kubernetes® is a registered trademark of The Linux Foundation; OpenShift® is a registered trademark of Red Hat, Inc.; Podman® is a registered trademark of Red Hat, Inc.; Proxmox® is a registered trademark of Proxmox Server Solutions GmbH; VMware® is a registered trademark of Broadcom Inc.; CloudFlare® is a registered trademark of Cloudflare, Inc.; NETSCOUT® is a registered trademark of NETSCOUT Systems Inc.; ElasticSearch®, LogStash®, and Kibana® are registered trademarks of Elastic NV; Grafana® is a registered trademark of Grafana Labs; Prometheus® is a registered trademark of The Linux Foundation; Zabbix® is a registered trademark of Zabbix LLC; Datadog® is a registered trademark of Datadog, Inc.; Ceph® is a registered trademark of Red Hat, Inc.; MinIO® is a registered trademark of MinIO, Inc.; Mailgun® is a registered trademark of Mailgun Technologies, Inc.; SendGrid® is a registered trademark of Twilio Inc.; Postmark® is a registered trademark of ActiveCampaign, LLC; cPanel®, LLC owns the rights to cPanel®; Plesk® is a registered trademark of Plesk International GmbH; Hetzner® is a registered trademark of Hetzner Online GmbH; OVHcloud® is a registered trademark of OVH Groupe SAS; Terraform® is a registered trademark of HashiCorp, Inc.; Ansible® is a registered trademark of Red Hat, Inc.; cURL® is a registered trademark of Daniel Stenberg; Facebook®, Inc. owns the rights to Facebook®, Messenger® and Instagram®. This site is not affiliated with, sponsored by, or otherwise associated with any of the above-mentioned entities and does not represent any of these entities in any way. All rights to the brands and product names mentioned are the property of their respective copyright holders. All other trademarks mentioned are the property of their respective registrants. MANAGED SERVER® is a European registered trademark of MANAGED SERVER SRL, with registered office in Via Flavio Gioia, 6, 62012 Civitanova Marche (MC), Italy and operational headquarters in Via Enzo Ferrari, 9, 62012 Civitanova Marche (MC), Italy.

JUST A MOMENT !

Have you ever wondered if your hosting sucks?

Find out now if your hosting provider is hurting you with a slow website worthy of 1990! Instant results.

Close the CTA
Back to top