{"id":1339,"date":"2020-08-14T13:31:52","date_gmt":"2020-08-14T13:31:52","guid":{"rendered":"https:\/\/lvboard.infostore.in.ua\/?p=1339"},"modified":"2020-08-14T13:31:52","modified_gmt":"2020-08-14T13:31:52","slug":"optimizing-css-for-faster-page-loads","status":"publish","type":"post","link":"https:\/\/lvboard.infostore.in.ua\/?p=1339","title":{"rendered":"Optimizing CSS for faster page loads"},"content":{"rendered":"\n<p>Not long ago I decided to improve the loading times of my website. It already loads pretty fast, but I knew there was still room for improvement and one of them was CSS loading. I will walk you through the process and show you how you can improve your load times as well.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 id=\"why-loading-time-matters%3F\">Why loading time matters?<a href=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/?fbclid=IwAR2qKRMd1ODcSJFg4G8CmoBouP8Yssxd8oRP4fquXVDQupYCOOXtW-kEaGE#why-loading-time-matters%3F\">#<\/a><\/h2>\n\n\n\n<p>Because&nbsp;<em><strong>Time is money<\/strong><\/em>. That proverb is especially true for webpage load times. Your page load time has a direct impact on your profit. People are more likely to buy something on a fast e-shop than on the slow one. According to study&nbsp;<a href=\"https:\/\/www2.deloitte.com\/ie\/en\/pages\/consulting\/articles\/milliseconds-make-millions.html\">Milliseconds make millions<\/a>&nbsp;improvement by 0.1s on mobile site increased conversions by 10.1% and order value by 1.9% on Travel sites. That can be a lot of money.<\/p>\n\n\n\n<p>So if you want to build a profitable business, you shouldn\u2019t underestimate your page load times.<strong>NOTE:<\/strong>&nbsp;There is more studies confirming this pattern. I used an example from the study mentioned above because it&#8217;s the most recent one I could find.<\/p>\n\n\n\n<h3 id=\"how-does-css-affect-load-times\">How does CSS affect load times<a href=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/?fbclid=IwAR2qKRMd1ODcSJFg4G8CmoBouP8Yssxd8oRP4fquXVDQupYCOOXtW-kEaGE#how-does-css-affect-load-times\">#<\/a><\/h3>\n\n\n\n<p>To see how CSS affects the load time of a webpage we first have to know how the browser converts an HTML document into a functional webpage.<\/p>\n\n\n\n<p>First, it has to download an HTML document and parse it to create DOM (Document Object Model). Any time it encounters any external resource (CSS, JS, images, etc.) it will assign it a download priority and initiate its download. Priorities are important because some resources are critical to render a page (eg. main stylesheet and JS files) while others may be less important (like images or stylesheets for other media types).HTTP\/1.1 has also a hard limit on the number of connections per one domain (the exact number depends on the browser, it&#8217;s usually 6 these days). So if you want to download a large number of resources from one domain some of them have to wait in a queue until resources with higher priorities finish downloading. So keep the number of requests small when using HTTP\/1.1. HTTP\/2 doesn&#8217;t have this limitation, but not all sites are using HTTP\/2 so far.<\/p>\n\n\n\n<p>In the case of CSS, this priority is usually high because stylesheets are necessary to create CSSOM (CSS Object Model). To render a webpage browser has to construct both DOM and CSSOM. Without those browser will not render any pixels on the screen. The reason for this is that styles define the look of the page and rendering page first without them would be a waste of processing powers and bad user experience. Only when the browser has both DOM and CSSOM available it can create render tree by combining them and start rendering the screen. In short no CSS downloaded, no page rendered.<\/p>\n\n\n\n<p>As you can see CSS has a huge impact on the load time of your webpage. There are two basic areas affecting webpage load time when we talk about CSS:<\/p>\n\n\n\n<ol><li>CSS file size and the total amount of CSS on the page (number of files). Too large CSS files will take a longer time to download and thus the entire page will take much more time to render (it has to wait for that big CSS to download first).<\/li><li>When and how we initiate and download our CSS. You want to download your styles as soon as possible.<\/li><\/ol>\n\n\n\n<p>Let\u2019s see in detail how we can improve those.<\/p>\n\n\n\n<h2 id=\"limit-size-of-your-stylesheet\">Limit size of your stylesheet<a href=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/?fbclid=IwAR2qKRMd1ODcSJFg4G8CmoBouP8Yssxd8oRP4fquXVDQupYCOOXtW-kEaGE#limit-size-of-your-stylesheet\">#<\/a><\/h2>\n\n\n\n<p><strong>TLDR:<\/strong>&nbsp;Configure your tools correctly to use modern code whenever possible.<\/p>\n\n\n\n<p>If you want to faster load times, making your CSS files smaller is a good idea. These days it\u2019s pretty common to use some tool to modify the CSS on build time (either post processor or&nbsp;<a href=\"https:\/\/postcss.org\/\">PostCSS<\/a>) to provide fallbacks for older browsers or some other enhancements.<\/p>\n\n\n\n<p>I would suggest checking the result code for unnecessary bloat. Especially if you are using PostCSS with multiple plugins. In my case, I had CSS with generated fallbacks for CSS variables and with prefixes for older flexbox syntax. That may seem like a trivial issue with very little effect, but resulting savings were around 3 kB for small stylesheet like mine. I think that is a great improvement for very little work. And for large CSS it has the potential to have an even bigger impact.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>old index.css:  12.5kB (without GZip)new index.css:   9.2kB (without GZip, ~26.4% smaller)<\/code><\/pre>\n\n\n\n<p>All I had to do was to update a&nbsp;<a href=\"https:\/\/github.com\/browserslist\/browserslist\">browserslist<\/a>&nbsp;config which is used by Autoprefixer and other similar tools to target generated code for specific browser versions. I have updated my PostCSS config a bit as well. (I also added the plugin to concatenate media queries together to save some extra space). See the&nbsp;<a href=\"https:\/\/github.com\/Pustelto\/personal_web\/blob\/master\/src\/styles\/index.11ty.js\">PostCSS config in the source code<\/a>&nbsp;and&nbsp;<a href=\"https:\/\/github.com\/Pustelto\/personal_web\/blob\/master\/package.json#L47\">my browserslist definition<\/a>&nbsp;if you want to see my exact setup.<\/p>\n\n\n\n<h2 id=\"use-critical-css\">Use critical CSS<a href=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/?fbclid=IwAR2qKRMd1ODcSJFg4G8CmoBouP8Yssxd8oRP4fquXVDQupYCOOXtW-kEaGE#use-critical-css\">#<\/a><\/h2>\n\n\n\n<p>So we shrank our CSS file, but we still need to download it. We can speed up the webpage load time by reducing network requests. And best network requests are no requests at all. We can inline our styles directly into the HTML to avoid the need for downloading any external stylesheets and thus saving some time.<\/p>\n\n\n\n<p>Of course, including an entire 9kb stylesheet (or large for bigger projects) on every page is not very effective. So we will include only the styles necessary to render the part of the page&nbsp;<em>above the fold<\/em>&nbsp;and lazy-load the rest of the styles. That way we can still leverage browser caching for other pages and make our webpage load faster. Since we include styles that are critical for page rendering this technique is called&nbsp;<em>Critical CSS<\/em>.<img loading=\"lazy\" alt=\"Above the fold is the content visible right away after page loads. Content not visible without scrolling is below a fold.\" src=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/e53cd5c6-296.jpg\" width=\"296\" height=\"223\"><\/p>\n\n\n\n<p>Luckily you don\u2019t have to decide what styles should be included in the HTML. Some tools will do it for you, like&nbsp;<a href=\"https:\/\/github.com\/addyosmani\/critical\">Critical<\/a>&nbsp;from Addy Osmani. Please keep in mind this technique is about compromises. You need to find the right balance between what to include and the size of the CSS since this technique will save you one request when loading page but it also makes each page bigger (and thus makes it longer to download). So you want to experiment with this and measure the results to find the best setup for your site.<\/p>\n\n\n\n<h2 id=\"lazy-load-stylesheets\">Lazy-load stylesheets<a href=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/?fbclid=IwAR2qKRMd1ODcSJFg4G8CmoBouP8Yssxd8oRP4fquXVDQupYCOOXtW-kEaGE#lazy-load-stylesheets\">#<\/a><\/h2>\n\n\n\n<p>Since we use Critical CSS we want to lazy-load our stylesheets to avoid blocking the render of the page. Unless you need to support some old browsers, modern solution these days is using normal link tag you use for stylesheets but with different media type and a little bit of JS. This clever little trick is fully described in the&nbsp;<a href=\"https:\/\/www.filamentgroup.com\/lab\/load-css-simpler\/\">Filament Group blog post<\/a>. Below you can see the snippet for lazy-loading CSS from the post, but I suggest reading the entire thing.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;link rel=\"stylesheet\" href=\"\/path\/to\/my.css\" media=\"print\" onload=\"this.media='all'\"><\/code><\/pre>\n\n\n\n<p><strong>NOTE:<\/strong>&nbsp;If you use Critical package from above, it transforms your stylesheet to be lazy loaded like that automatically.<\/p>\n\n\n\n<p>You may want to include fallback when JS is disabled. That way your styles will load normally and you will avoid unstyled content which would badly affect user experience.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;link rel=\"stylesheet\" href=\"\/path\/to\/my.css\" media=\"print\" onload=\"this.media='all'\">&lt;noscript>  &lt;link rel=\"stylesheet\" href=\"\/path\/to\/my.css\" media=\"screen\">&lt;\/noscript><\/code><\/pre>\n\n\n\n<p>In the waterfall diagrams below you can see that page with critical CSS starts rendering right away (violet portion of the graph in&nbsp;<em>Browser main thread<\/em>&nbsp;row) and is interactive much sooner compared to the old version where CSS file has to be downloaded first.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img src=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/c9a7cf9-296.jpg\" alt=\"Page starts rendering after 3.6 seconds and is interactive after 3.8 seconds.\"\/><figcaption>Waterfall chart for projects page&nbsp;<strong>without<\/strong>&nbsp;critical CSS.<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img src=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/9ba39302-296.jpg\" alt=\"Page starts rendering after 3.2 seconds and is interactive after 3.3 seconds.\"\/><figcaption>Waterfall chart for projects page&nbsp;<strong>with<\/strong>&nbsp;critical CSS.<\/figcaption><\/figure>\n\n\n\n<h2 id=\"use-code-splitting-for-your-stylesheets\">Use code-splitting for your stylesheets<a href=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/?fbclid=IwAR2qKRMd1ODcSJFg4G8CmoBouP8Yssxd8oRP4fquXVDQupYCOOXtW-kEaGE#use-code-splitting-for-your-stylesheets\">#<\/a><\/h2>\n\n\n\n<p>We have CSS with properties we need for modern browsers and we use critical CSS and lazy-load the rest. But we can probably decrease our file size a bit more. In Chrome dev tools there is a tool called Coverage. It can show you what portion of CSS and JS files is used on the current page. Open dev tools and press&nbsp;<kbd>Ctrl<\/kbd>+<kbd>Shift<\/kbd>+<kbd>p<\/kbd>&nbsp;to open a command pallet and type&nbsp;<em>Coverage<\/em>. Select&nbsp;<em>Show coverage<\/em>&nbsp;option to show the panel. Now reload the page.<img loading=\"lazy\" alt=\"Coverage report for my home page before any optimizations, over 45% of the CSS is not used on the page.\" src=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/609d2b36-296.jpg\" width=\"296\" height=\"62\"><img loading=\"lazy\" alt=\"Coverage report for my projects page before any optimizations, over 53% of the CSS is not used on the page.\" src=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/5cdcf12e-296.jpg\" width=\"296\" height=\"54\"><\/p>\n\n\n\n<p>I had almost 50% of my CSS code unused on the page. When we check another page we get even more \u2013 almost 54% of unused CSS. That\u2019s a lot of unnecessary code. And this number can be even bigger on large legacy apps.<\/p>\n\n\n\n<p>When using JS we often use code-splitting to create multiple smaller files (bundles). We download those bundles when needed them instead of fetching one large JS bundle on page load. We can use a similar approach for CSS as well. We can split our CSS in three different ways.<\/p>\n\n\n\n<h3 id=\"split-css-based-on-media-queries\">Split CSS based on media queries<a href=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/?fbclid=IwAR2qKRMd1ODcSJFg4G8CmoBouP8Yssxd8oRP4fquXVDQupYCOOXtW-kEaGE#split-css-based-on-media-queries\">#<\/a><\/h3>\n\n\n\n<p>In this approach, you split your big CSS into smaller stylesheets based on your media queries (PostCSS have&nbsp;<a href=\"https:\/\/github.com\/hail2u\/node-css-mqpacker\">plugin<\/a>&nbsp;for that) and reference those stylesheets in your HTML.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;link rel=\"stylesheet\" href=\"index.css\" media=\"all\" \/>&lt;link rel=\"stylesheet\" href=\"mobile.css\" media=\"(max-width:44.9375rem)\" \/>&lt;link rel=\"stylesheet\" href=\"table.css\" media=\"(min-width: 45rem)\" \/><\/code><\/pre>\n\n\n\n<p>Be aware that this approach doesn\u2019t make much sense when using Critical CSS and lazy-loading of the stylesheet. The browser will download all stylesheets no matter what media query is used. It will only use media attribute to prioritize the downloads. So basically it will download CSS with a high priority for active media query and lazy-load the rest of the stylesheets.<\/p>\n\n\n\n<h3 id=\"page-based-code-splitting\">Page based code-splitting<a href=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/?fbclid=IwAR2qKRMd1ODcSJFg4G8CmoBouP8Yssxd8oRP4fquXVDQupYCOOXtW-kEaGE#page-based-code-splitting\">#<\/a><\/h3>\n\n\n\n<p>Another approach is to use separate CSS for each page. As we have seen above there is a lot of unused styles for different pages. It would be great if we could remove those unused styles and keep only what is necessary for a given page. This is what I choose to do. Sadly I couldn\u2019t find any tool to do this \u2014 take one large CSS file and generate a smaller bundle for each page based on its content.<\/p>\n\n\n\n<p>Sounds fairly simple so I decided to give it a shot and build a node script which can do this kind of thing. It\u2019s called&nbsp;<a href=\"https:\/\/github.com\/Pustelto\/css-split\">CSS Split<\/a>&nbsp;and it works great for sites built using static site generator (like&nbsp;<a href=\"https:\/\/www.11ty.dev\/\">Eleventy<\/a>&nbsp;which I use for my site). It uses&nbsp;<a href=\"https:\/\/purgecss.com\/\">PurgeCSS<\/a>&nbsp;to remove unused styles so it should work on other non-HTML files as well (based on their documentation). I didn\u2019t test it for anything else than HTML so when using it this way, be sure to double-check the results.<\/p>\n\n\n\n<p>Using this technique I was able to reduce the file size of requested CSS by almost 50%. Below are some stats after implementing Critical CSS and page based code-splitting:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>single index.css for all pages:      9.2kB (without GZip)CSS file for homepage:               5.4kB (without GZip)CSS file for projects:               4.4kB (without GZip)<\/code><\/pre>\n\n\n\n<p><img loading=\"lazy\" alt=\"Coverage report for my home page after code-splitting, only around 400 bytes are unused.\" src=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/77fe87ad-296.jpg\" width=\"296\" height=\"57\"><img loading=\"lazy\" alt=\"Coverage report for my projects page after code-splitting, only around 400 bytes are unused.\" src=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/b1e5a9d5-296.jpg\" width=\"296\" height=\"61\"><\/p>\n\n\n\n<p>You can see that there are still some unused bytes. That\u2019s ok as Coverage doesn\u2019t include hover or focus states or queries. It is unlikely that you will ever get unused bytes to 0.<\/p>\n\n\n\n<h3 id=\"component-based-code-splitting\">Component based code-splitting<a href=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/?fbclid=IwAR2qKRMd1ODcSJFg4G8CmoBouP8Yssxd8oRP4fquXVDQupYCOOXtW-kEaGE#component-based-code-splitting\">#<\/a><\/h3>\n\n\n\n<p>I\u2019ve got this tip from&nbsp;<a href=\"https:\/\/csswizardry.com\/\">Harry Roberts<\/a>. We can also split CSS on the component basis and only load progressively CSS for components we use on the page (footer, header, article, etc.). You can read more about this neat trick in&nbsp;<a href=\"https:\/\/csswizardry.com\/2018\/11\/css-and-network-performance\/\">Harry\u2019s article<\/a>. This technique I\u2019m talking about is described in the last section of the article. But read the entire article, it\u2019s full of great info about improving CSS network performance I don\u2019t cover here (couldn\u2019t write it better anyway).<\/p>\n\n\n\n<p>I still didn\u2019t test this technique to see how well it will work compared to my current setup, but it\u2019s on my To-do list. So stay tuned for some future article.<\/p>\n\n\n\n<h2 id=\"summary\">Summary<a href=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/?fbclid=IwAR2qKRMd1ODcSJFg4G8CmoBouP8Yssxd8oRP4fquXVDQupYCOOXtW-kEaGE#summary\">#<\/a><\/h2>\n\n\n\n<p>Even though my site is fairly simple and doesn\u2019t have too much room for improvements, by using the techniques mentioned there I was able to speed up the initial load of my webpage and lower the total size of assets. You can use the same process for any webpage to improve it\u2019s loading performance (probably with better results for larger projects).<\/p>\n\n\n\n<p>Below you can see some final results after the updates. Graphs show what percentage of the page was rendered at what time. Those tests were run on a slow 3G connection, that\u2019s why it takes so long to load the page.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img src=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/b75f023b-296.jpg\" alt=\"Graph comparing time to fully render homepage before and after optimizations. Homepage loads around 0.2 second faster after optimizations.\"\/><figcaption>Homepage \u2013 final comparison<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img src=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/85320521-296.jpg\" alt=\"Graph comparing time to fully render projects page before and after optimizations. Page loads around 0.5 second faster after optimizations.\"\/><figcaption>Projects page \u2013 final comparison<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img src=\"https:\/\/pustelto.com\/blog\/optimizing-css-for-faster-page-loads\/2ea919b9-296.jpg\" alt=\"Graph comparing time to fully render single blog post before and after optimizations. Page loads around 0.6 second faster after optimizations.\"\/><figcaption>Single article \u2013 final comparison<\/figcaption><\/figure>\n\n\n\n<p>Thanks for reading the article. If you have any suggestions or ideas how to make the article better or you simply like it, feel free to share and discuss it on Twitter.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Not long ago I decided to improve the loading times of my website. It already loads pretty fast, but I knew there was still room for improvement and one of them was CSS loading. I will walk you through the process and show you how you can improve your load times as well.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[30],"tags":[105],"_links":{"self":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts\/1339"}],"collection":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1339"}],"version-history":[{"count":1,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts\/1339\/revisions"}],"predecessor-version":[{"id":1340,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts\/1339\/revisions\/1340"}],"wp:attachment":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1339"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1339"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1339"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}