![](https://blogcdn.namehero.com/blog/wp-content/uploads/2023/07/12110751/howtoinline-1024x576.jpg)
Knowing how to inline and defer CSS on your WordPress site is a vital part of improving the viewer experience. While it doesn’t improve your page load time, it makes a huge difference to how the user perceives the page to load.
Normally, all externally linked CSS stylesheets are render-blocking. Which means that the browser doesn’t proceed until they’ve been downloaded. So it’s a best practice to defer them (not the same “defer” as with Javascript though). Unfortunately, this has some side effects that we need to take care of.
This tutorial will show you how to:
- Generate critical CSS
- Defer CSS stylesheets
- Inline the critical CSS from Step 1
So let’s go.
Step 1: Generate Critical CSS
The importance of this step will become evident after step 2. For now, just visit a site like like, enter your site’s URL or page, and click “Generate Critical Path CSS”. The tool will scan your website and eventually give you a blob of text like this:
![Copy Critical CSS](https://www.namehero.com/blog/wp-content/uploads/2018/12/Copy-Critical-CSS.png)
Copy this and keep it safe. We’ll use it later.
Step 2: Defer CSS Stylesheets
Most CSS in WordPress is (and should be) enqueued properly using the “wp_enqueue_style” function. This will place a <link> element in the head that looks like this:
![CSS Files Without Preload](https://www.namehero.com/blog/wp-content/uploads/2018/12/CSS-Files-Without-Preload.png)
As mentioned earlier, this CSS stylesheet is render blocking. If you plug your page into a tool like Google’s PageSpeed insights for example, it’ll complain that a lot of stuff is preventing the page from displaying – and those tools will be right.
About the rel=’preload’ Attribute
To solve this problem, browsers have started supporting the “preload” attribute for resources like scripts. Basically, it tells the browser that the resources marked in this manner can be downloaded simultaneously in the background and that they’re not terribly important for page loading.
Of course, that’s not true. The CSS stylesheets are important. They define how your site looks after all! But for the moment, we’re interested in using the “preload” attribute value to defer our external stylesheets.
You can do this by inserting the following code into your WordPress’s functions.php file:
function add_rel_preload($html, $handle, $href, $media) { if (is_admin()) return $html; $html = <<<EOT <link rel='preload' as='style' onload="this.onload=null;this.rel='stylesheet'" id='$handle' href='$href' type='text/css' media='all' /> EOT; return $html; } add_filter( 'style_loader_tag', 'add_rel_preload', 10, 4 );
After you save your changes, your CSS stylesheets will have the “preload” tag attached to them like this:
![CSS is Preloaded](https://www.namehero.com/blog/wp-content/uploads/2018/12/CSS-is-Preloaded.png)
Great right? Not so fast!
Step 3: Panic As your Site Breaks
Unfortunately, running the above code makes your site “unstyled” like this:
![But the Page is Doesnt Display](https://www.namehero.com/blog/wp-content/uploads/2018/12/But-the-Page-is-Doesnt-Display.png)
This is because the CSS styles with “preload” haven’t been applied since the page went ahead and rendered without them. This is where the “critical” CSS from Step 1 comes in.
The “critical CSS” refers to only those CSS rules that apply to the “above the fold” content – namely the content that’s visible when your page first loads. This is typically a very tiny subset of the actual CSS contained in all the stylesheets.
In Step 1, we generated this critical CSS, and we need to insert it into the <head> of our webpage with following code:
function hook_css() { ?> [insert critical css here] <?php } add_action('wp_head', 'hook_css');
Replace [insert critical css here] with the code you copied from Step 1.
Note that this must include the <style></style> tags around it. If you’re using a different tool, it might just give you the CSS rules without the <style> opening and closing tags. Make sure you add them!
Once you’ve done this, your page will load normally and look the same. With the important difference that all your stylesheets are loading in a deferred manner! Say hello to fast page load speed scores!
![Bhagwad Park Profile Picture](https://www.namehero.com/blog/wp-content/uploads/2019/03/Bhagwad-Park-Profile-Picture.jpg)
I’m a NameHero team member, and an expert on WordPress and web hosting. I’ve been in this industry since 2008. I’ve also developed apps on Android and have written extensive tutorials on managing Linux servers. You can contact me on my website WP-Tweaks.com!
Hey there,
Really interesting method to remove CSS render-blocking. An issue with the function though, it only works for the home page. The critical path CSS I copied into the head only works for the home page. So other pages still break and even after page loading is complete, the layout is broken.
Could the function and method be improved to include conditional logic so I can target pages on an individual basis? Or even better, on a template by template basis?
It’s possible, but I would suggest just including ALL the critical CSS inline – even for those pages that don’t need it.
What you’re suggesting is valid in theory, but in practice it would require a LOT of maintenance. And each time you make a change like adding a plugin, changing a theme, or even styling a table, you would need to make modifications to your code. This would quickly become unmanageable.
Given the small size of text, the performance benefits would be truly minuscule – so small, that I doubt they could even be measured. So if I were you, I would gather all the critical CSS from all my site’s pages in one blob and paste them for all pages.
If you use Fast Velocity Minify – some prefer Autoptimize – you can inline all your CSS in the header or header and footer. As long as the file size in the header is no more than 50 – 60 kb you are good. No need to worry about critical CSS.
Obviously it’s better to deffer unused style rules, but if you’re within this limit then the benefits aren’t worth the hassle.
AMP has a 50 kb CSS limit for same reason.
Hello David,
I’m amateur, with no previous knowledge or experience with website building nor wordpress or something but I’m leraning little by little. I have a question with Fast Velocity Minify and what to do with CSS or JS processed files.
– /wp-content/plugins/elementor/assets/xxx.css
– /wp-content/plugins/woocommerce/assets/js/xxx.js
Should I exclude or include any of them or what ? Honestly I haven’t ask on WP forum since I started with FVM recently and then I noticed this blog and topic that I was looing for. Thank you in advance. Cheers and take you all care! Dragan
I’m having little problem with this technique. I’m using W3 Total cache plugin, As I load my critical css before loading any css and js, Critical css works fine but My Combined CSS Files doesn’t load combinely, they load separately. So my http requests increases from 29 to 45. This technique works but i don’t know how to load my combined css files after putting critical css first in the header.
Can anyone please tell me why that’s happening? and give me a solution if possible 🙂
I’m personally use AO for my website. The interface seems more friendly for me instead fvm. Unfortunately AO does not have feature for defer some assets, but they have preload and preconnect. I got 85 – 89 score in PageSpeed and thats more than enough since the page below 500kb. The real problem i need to solve is the Ads.
Is there a way to defer a single stylesheet instead of all stylesheets?
You’ll need to modify the code with an “if” condition to check for the specific style tag that you want to defer.
You can.
I personnaly did it like that so far :
function add_style_attributes( $html, $handle ) {
if ( ‘bootstrap’ === $handle ) {
return str_replace( “media=’all'”, “media=’all’ integrity=’sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T’ crossorigin=’anonymous'”, $html );
}
if ( ‘fontawesome’ === $handle ) {
return str_replace( “media=’all'”, “media=’all’ integrity=’sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr’ crossorigin=’anonymous'”, $html );
}
return $html;
}
add_filter( ‘style_loader_tag’, ‘add_style_attributes’, 10, 2 );
In this exemple, I also add the integrity and crossorigin attributes that the regular enqueue script does not handle by default.
Hope it helps.
Hi,
the above code doesn’t work – if uploaded in the functions.php, it results in string errors. Suggest this to be checked, so it can be used.
Thanks!!
Martin
Hi Martin,
Could you share the exact error you’re getting when you add the code along with the line number if possible, and the exact code you’re using?
Hey,
sure: I am using exactly your code snipped that you highlight above for the functions.php and pasted it in the functions.php of my child theme folder.
The resulting error: Parse error: syntax error, unexpected end of file in /XXX/XXX/XXX/wp-content/themes/mindfulness/functions.php on line 552
I’m having an issue in Firefox with this code. With Chrome, Safari, Opera and Edge, this code correctly works, and loads the css files after the page has rendered.
However, with Firefox, this code is preventing the CSS files from loading at all.
Has anyone else experienced this problem?
I have the same issue, my styles aren’t fonctional withing Firefox, plus, my nagivation is not even displayed in Chrome on top. Beside that, I also encounter various issues with img sizes on the front page, and, I presume, in other pages as well.
In short, it might be an interesting solution, because yes, the Chrome audits tells me it indeed remove most of the render-blocking CSS assets, but in the end it’s definitely not fully fonctionnal for my case, so I guess I will try another method or will just simply let them the way the behave initially.
Thanks, this is great!
As noted above, this isn’t playing nice with Firefox.
it’s better to just defer javascript than defer css.
This works fine in FF for me – just need to follow the more detailed guidelines here: https://web.dev/defer-non-critical-css/
and also, instead of adding the critical.css in wp_head, it’s better to carve out a case in the style_loader_tag where:
if ( strpos( $href, ‘themes//critical.css’ ) ) return $html;// Make sure this loads and is not deferred
I lied by the way ( caching is hard ) : FF sucks… you have to include a clause to return based on HTTP_USER_AGENT ( if Firefox, don’t mess with the script_tag )
There are several solutions for FF, but the easiest is to add something like:
rel=”stylesheet preload”
which works as a fall-through, for browsers which do not support preload.
Pagespeed optimisation really takes time. Thanks for sharing this stuff, it’s quite useful. Less plugin, less bloat.
Hello and thank you for this guide.
Unfortunately something is wrong with my setup.
I have installed both codes to my site (1st part with preload at the functions.php file and 2nd part with thefunction hook_css code at the header), but when I reload my site, I get a phrase appearing at my homepage, at the top left corner. This includes a few words from the function command.
Why is this happening and how to fix it?
Hi man! Thanks for your precious post, so useful! I would have a question: where have I to insert the inline css? In which php files? In the function as well?
Thanks,
Giuseppe
defer code loads everywhere. Is there any way to make it load only in single pages? I tried everything but couldn’t make it work. It will be huge help if you can help me defer stylesheets in posts only.
Thank you very much for the tip. I’ve just started working on WordPress, and it has been tough to me, since I’m a programmer who likes to build every inch of my development, hahaha! Now I’m looking for solutions to fix WP jams with no plugins involved, and your tip was just what I wanted! It worked fine at my work’s website. Thanks again! Greetings from Chile ^_^