Table Of Contents
- What makes CSS slow
- Reducing CSS file size
- Improving CSS animation performance
- Bonus: CSS Performance tips
What makes CSS slow?
File size
Large file size results in larger download times and parsing times. It's simple as that.
CSS Rendering
In order to understand where CSS rendering bottlenecks may come up, we need to look at the render pipeline steps:
1. Style - Determines which CSS rules apply to which elements in an HTML document.
2. Layout - Determines where the element is positioned on the screen and how much space does it take. CSS properties: position
, top
, left
, right
, bottom
, etc.
3. Paint - Determines visual elements. CSS properties: color
, border
, background-color
, etc.
4. Composite - Draws layers onto the screen. CSS properties: opacity
and transform
.
CSS offers a lot of options in terms of animation and transitions. We can create a transition on a lot of CSS properties. There are transitions and animations which can use GPU and perform really well, resulting in smooth 60 FPS (Frames per second) experience with fluid and smooth animations. On the flipš side, there are CSS properties that, when animated, can result in low FPS and choppy animations.
Any changes or updates happening on one of the steps cause updates on the following steps. We can see that the Layout step is the most expensive to animate and Composite step is the least expensive to animate.
Reducing CSS file size
By decreasing the file size of the CSS file, we can decrease the download time and loading time. Some improvements related to file size can be done even when we are finished working with CSS making it a very effective optimization. For maximum efficiency, it's best to keep in mind and apply these improvements from the start.
Minification
CSS file minification is an easy win and should be the first step for achieving better CSS performance. Minification removes formatting characters inside the CSS file (whitespaces, line breaks, etc.) which are only useful to us (makes the code readable).
/* Non-minified code */
.card {
padding: 1rem;
background-color: #aaa;
}
/* Minified code */
.card{padding:1rem;background-color:#aaa}
There are numerous online, automated and CDN "uglifying" tools that will help you with minification. Tools for CSS minification:
- CSS Compressor - simple online minification
- CSSNano - Automated CSS optimizer + minifier
- Clean CSS - Automated CSS optimizer + minifier
Optimization
Wait... We've already minified our CSS file. Isn't it already optimized?
Well, technically it is. When talking about CSS optimization, we are looking at removing unnecessary CSS or reformatting CSS properties that reduce the number of characters. Unlike minification, this improvement cannot be done on CDN and it must be done when code is being compiled (by a tool like Webpack or Gulp).
Let's take a look at the following example.
/* Unoptimized CSS */
.card {
background-color: #aaaaaa;
padding: 0.5rem 1rem 0.5rem 1rem;
}
.card__content {
padding: 0.5rem 1rem 0.5rem 1rem;
}
At first look, this looks like any regular CSS that anyone would write and not think twice about it. But there are some optimizations that could be done to reduce the number of characters.
/* Optimized CSS */
.card {
background-color:#aaa;
}
.card,
.card__content {
padding:.5rem 1rem;
}
We have reduced the number of characters from 132 to 85 (a 35% reduction). Let's apply minification and see the final result.
/* Optimized CSS with minification */
.card{background-color:#aaa}.card,.card__content{padding:.5rem 1rem}
We have reduced the number of characters from 132 to 68 (48% reduction in total).
You can see how much CSS impact the optimization has. The reduction is a result of removing the DRY code which can be avoided in this simple example. Looking at the CSS file with thousand of lines of code which is being changed on a regular basis (especially if split into several files), we can easily make our code less DRY. Luckily, there are tools that help us optimize our code and keep it DRY.
In the previous section, we have mentioned two of the numerous tools for optimizing CSS with minification included:
Compression
Compression is done server-side. It uses gzip or Brotli to compress and further reduce the file size in order to reduce the file download time.
This topic is very extensive and covers more file types than just CSS. CSS tricks wrote a great article on this topic if you are interested in implementing server-side compression.
It's also important to note that most CDN services offer the compression option out of the box.
CSS structure
Having a good CSS structure and using various CSS best practices and also result in a lower-sized CSS file when minified. For example, using BEM and only class selectors with low specificity will result in fewer characters in the file and the lower file size.
I've covered CSS structure improvements in one of my previous posts. By following these CSS principles, you will have a CSS file with great structure, DRY code and a great foundation for optimization and minification.
Improving CSS animation performance
Transitions and animations
We've covered the CSS rendering pipeline and what makes animation slow. So basically, Layout step is the most expensive to animate and Composite step is the least expensive to animate.
If we look at the CSS properties that cause the Composite layer to update, they are transform
and opacity
. These two properties use hardware (GPU) acceleration, resulting in very performant updates.
If you apply a transition to position attributes like top
or left
, animation performance will be poor because we are updating the Layout step which forces both Paint and Composite to update. Replacing the position CSS properties with transform
and using transition on it, we are updating Composite step only, resulting in smooth animation.
Promoting element into a composite layer
We aren't really restricted to using only transform
and opacity
for smooth animations. CSS offers quite a few ways of "promoting" an element into a composite layer to tell the browser that this element will have its Paint CSS properties updated often.
The hacky and "old way" of doing this is by either adding backface-visibility: hidden;
or transform: translate3d(0,0,0);
. In most cases, these properties won't affect your element in any way (if they don't override anything), but they will make the browser move the element into Composite layer, significantly improving animation performance.
.example {
width: 20rem;
height: 20rem;
background-color: #aaa;
border-radius: 0;
backface-visibility: hidden;
transition: border-radius 0.3s ease-in-out;
}
.example:hover {
border-radius: 50%;
}
will-change property
A modern way of telling browsers which element is expected to be updated (in terms of CSS rendering) is setting the will-change
property.
.card {
background-color: #aaa;
transition: background-color 0.3s ease-in-out;
will-change: background-color;
}
.card:hover {
will-change: background-color;
}
.card:active {
background-color: #bbb;
}
There are several things to keep in mind when using will-change
:
- Don't apply will-change to too many elements.
- Use sparingly
- Don't apply will-change to elements to perform premature optimization.
- Give it sufficient time to work.
contain property
The contain
CSS property represents the future of CSS render pipeline optimization. Currently, it sits at limited browser support. It allows us to indicate that an element’s subtree is independent of the rest of the page. This allows the browser to recalculate layout, style, paint, size, or any combination of them for a limited area of the DOM and not the entire page.
contain: none; /* No optimization */
contain: strict; /* Equivalent to contain: layout paint size style */
contain: content; /* Equivalent to contain: layout paint style */
contain: size; /* component size is set and no descendant will modify its size. */
contain: layout; /* changes to any descendant of this element will not affect the layout of any outside element and vice versa. */
contain: style; /* descendant’s styles will not affect outside elements. */
contain: paint; /* you specify that no descendant will display outside the elements bounds. Similar to overflow: hidden; */
Example of using contain
CSS property:
.box {
contain: layout size; /* Won't change size and won't affect layout */
}
<div class="box">
<div class="box__content">...</div>
</div>
Bonus: CSS Performance tips
Avoid using @import
@import
CSS property is used to include a CSS file within another CSS file. The issue is that these files are then loaded one after another instead of parallel when using the recommended HTML way of including stylesheets.
Use HTTP/2 if you have multiple stylesheets
HTTP/2 brings noticeable performance improvements when loading a lot of smaller files. This is an ideal solution if you are using CSS structure that results in multiple CSS stylesheets (individual screens, modules, components, etc.).
If you are not using HTTP/2, it's recommended to merge all your CSS files into a single CSS file.
Be aware of "expensive" properties
Some properties are more resource-heavy and increase render time. If you are intending to support devices with lower processing power, being aware of these properties would be beneficial:
border-radius
box-shadow
filter
position: fixed
*
:nth-child
Serve CSS file(s) over the CDN
Serving static files like images, CSS, JS, etc. from CDN improves download times. Additionally, some CDN services offer basic minification and optimization options, so you can easily get a performance boost if your code is not minified already.
Keep your selectors simple
Having simple class selectors (consider using BEM and OOCSS or other flavors and combinations) can benefit performance when rendering your site, especially on devices with lower processing power. I've covered this topic more in-depth in one of my previous articles:
These articles are fueled by coffee. So if you enjoy my work and found it useful, consider buying me a coffee! I would really appreciate it.
Thank you for taking the time to read this post. If you've found this useful, please give it a ❤️ or 🦄, share and comment.
Top comments (14)
I'm dubious about tips relating to decreasing the transfer size for CSS assets.
They're loaded once, and cached. Or they're served from a CDN. Once they're loaded they're unpacked in milliseconds where whitespace makes no difference and the difference between short-forms and full forms is inconsequential unless you have millions of rules.
What that means is maybe a dozen milliseconds more load time for the first page and then no perceivable effect on subsequent pages.
Keeping selectors simple is more worthwhile, but still most people won't notice the difference, especially when you consider that your CSS is likely aggregated with that provided by the five hundred "essential" plugins your framework bundles.
Speaking from experience working on an massive eCommerce site, minifying, concatenating and optimizing 2MB CSS file to 350kB-ish file resulted in an increase of mobile users. The improvement also added lazy loading for images and minifying JS and it boosted the number of mobile users significantly.
The problem was that users on mobile and slower connections would perceive the site as slow and unresponsive due to the massive file being loaded.
It's true that everything is well after that first load, but users might give up if they wait too long for that first load.
If you can play the Doom shareware episode in the size of your CSS you are doing something really wrong.
I've done quite a few audits of various sites in my career. I have seen some really crazy stuff I haven't thought of possible. Including the CSS and JS files with source maps included.
You are wrong, compressing the CSS speed up the website quite a lot.
After caching the website is fast but big BUT the first load it's most important the first load is the load that make sales, make great user experience etc...
Slowly 2019 is coming to end, every again every website should load critical CSS per URL and load the rest 99% of the CSS after the page as non render blocking.
Me as SEO Manager, I can't hire someone to optimize CSS if the developer don't know what critical CSS is and how to do it.
It was hard to find a developer who know how to do technical SEO optimization per instruction so if the website is WordPress I'm doing it myself but can't do it at custom coded website. Please educate yourself for SEOs needs because nearly every website is searching for SEO services.
Every one will ask you as developer to optimize the website as speed is ranking factor now.
We can extend further this conversation with examples and I can show you the difference white space is doing or speaking about discarding invalid CSS properties other than CSS 3.
Let's extend this conversation I might be able to find someone reliable that I can hire in the future.
I have this code ->
Is that efficient?
I like your Posts Adrian, good Job!
Thank you very much, Simon.
Dev.to and the community really inspired me to write articles more often and put more work into them.
Great article! Thank you for taking the time to write this, very insightful
Thank you very much. Glad you like it!
Correct me if I'm wrong but http/2 is fine if all of the stylesheets come from the same server, otherwise multiple http requests slows down mobile.
A very helpful and informative post. It's good to animate position, scale, rotate and opacity.
for more: html5rocks.com/en/tutorials/speed/...
Thank you. I do remember reading this article quite a while back.