This article will detail 8 tips for CSS performance optimization, divided into two categories: practical and recommended. Practical skills can be quickly applied to the project, can improve performance, is often used by the author, we suggest that we practice in the project as soon as possible. Advice type skills, some may not have a significant impact on performance, and some usually we will not be so used, so THE author will not focus on it, readers can understand it according to their own situation.
Before we start, we need to have some understanding of how the browser works. If you need it, you can have a brief understanding. Let’s start with 4 practical optimization tips, starting with the key CSS on the first screen.
Inline First Screen Critical CSS
One important metric in performance optimization is First Meaningful Paint (FMP), which is the amount of time that the primary content of a page appears on the screen. This metric affects the amount of time a user has to wait to see a page, and ** inlining Critical CSS (also known as Critical CSS) ** reduces this time.
You’re probably used to referencing external CSS files with the link tag. But it’s important to know that inlining CSS directly into HTML documents makes CSS download faster. With external CSS files, you don’t know which CSS files to reference until the HTML documents have been downloaded, and then download them. Therefore, inline CSS allows the browser to start rendering the page earlier, since it will be rendered after the HTML has been downloaded.
Since inline CSS makes the start time of page rendering earlier, can you inline all CSS? The answer is clearly no, this approach does not work with large inline CSS files. Because there is a limit to initial congestion window 3 (TCP related concepts, typically 14.6KB, compressed size), if the file after inlining CSS exceeds this limit, the system will need to make more round trips between the server and the browser, which will not advance page rendering time. Therefore, we should only inline the key CSS needed to render the first screen content into the HTML.
Now that you know that inlining the first-screen critical CSS improves performance, the next step is to determine the first-screen critical CSS. Obviously, we don’t need to manually determine which content is the key CSS for the first screen. There is a project on Github called Critical CSS4 that extracts the key styles that are part of the first screen. Take a look at the project and use it with your own build tools. Of course, in order to ensure that correct, you’d better personally confirm whether the extracted content is missing. One disadvantage of inline CSS is that it is not cached and will be re-downloaded each time. However, as mentioned above, this doesn’t seem to be a big deal if we keep the inline file size under 14.6 KB.
Above, we’ve covered why and how to inline key CSS, so what do we do with the rest of the CSS? It is recommended to use external CSS to bring in the rest of the CSS so that caching can be enabled, in addition to loading them asynchronously.
Loading the CSS asynchronously
CSS blocks rendering, and the browser will not render any processed content until the CSS file has been requested, downloaded, and parsed. Sometimes this blocking is necessary because we don’t want the browser to start rendering the page before the required CSS loads. After the key CSS is inlined on the first screen, blocking rendering of the rest of the CSS content is not necessary, and external CSS can be used and loaded asynchronously.
So how do you implement asynchronous loading of CSS? You can use the following four methods to load the CSS asynchronously.
The first is to use JavaScript to dynamically create a stylesheet link element and insert it into the DOM.
// Create link tag const myCSS = document.createElement("link"); myCSS.rel = "stylesheet"; myCSS.href = "mystyles.css"; / / insert to the header of the final location document. The head. The insertBefore (myCSS, document.head.childNodes[ document.head.childNodes.length - 1 ].nextSibling );Copy the code
The second way is to set the media property of the link element to a media type (or media query) that the user’s browser does not match
Media =”print”, or even a completely nonexistent type media=”noexist”. For the browser, if the stylesheet does not apply to the current media type, it is prioritized and downloaded without blocking the page rendering.
Of course, this is just for asynchronous loading of CSS, and don’t forget to set the media value to Screen or all after the file is loaded so that the browser can start parsing the CSS.
<link rel="stylesheet" href="mystyles.css" media="noexist" onload="this.media='all'">
Copy the code
Mark the Link element as alternate optional stylesheet with the REL attribute
Similar to the second approach, we can also mark the link element as alternate optional stylesheet through the REL attribute, as well as enable asynchronous browser loading. Also, don’t forget to change the rel back after loading.
<link rel="alternate stylesheet" href="mystyles.css" onload="this.rel='stylesheet'">
Copy the code
Rel =”preload”5 What does this Web standard say about asynchronously loading resources
All three methods are old. Now, rel=”preload”5, the Web standard, specifies how to load resources asynchronously, including CSS-like resources.
<link rel="preload" href="mystyles.css" as="style" onload="this.rel='stylesheet'">
Copy the code
Note that as is required. Ignoring the AS attribute, or the wrong AS attribute, makes preload equivalent to an XHR request, and the browser does not know what is being loaded, so such resources have a very low load priority. For alternative values of AS, refer to the standard documentation above.
Rel =”preload” appears to be used in the same way as the previous two, in that the browser asynchronously loads the CSS file but does not parse it until the load is complete and the changes are restored, and then the parsing begins.
One important difference, however, is that using preload can start loading CSS earlier than using mismatched media methods. Therefore, although the support for this standard is not perfect, it is recommended to use this method first.
This standard is now a candidate and will be supported by browsers over time. The following figure shows the browser support.
As you can see from the figure above, this approach is not well supported in current browsers, but we can polyfill with loadCSS6, so it is not a matter of whether it is supported or not.
File compression
One of the easiest and most commonly used ways to optimize performance is file compression, which often works.
The size of the file directly affects the loading speed of the browser, especially when the network is poor. Most of you are used to CSS compression, and today’s build tools such as WebPack, gulp/ Grunt, and rollup support CSS compression. The compressed file can be significantly smaller, which can greatly reduce the browser load time.
4. Remove unnecessary CSS
Although file compression can reduce file size. However, CSS file compression usually only removes unnecessary whitespace, which limits the compression ratio of CSS files. Are there other ways to simplify CSS? The answer is clearly yes, if the compressed file is still larger than expected, we can try to find and remove unwanted CSS from the code.
In general, there are two types of useless CSS code: duplicate code for different elements or otherwise, and CSS code that doesn’t work for the entire page. For the former, when writing code, we should extract as many common classes as possible to reduce duplication. For the latter, there is always code with CSS that is no longer used in the process of code maintenance by different developers, but it can also happen when one person is writing it. This useless CSS code not only increases browser downloads, but also browser parsing time, which can be a significant drain on performance. So we need to find and remove the useless code.
Of course, it is inefficient to manually remove these useless CSS. We can do this with the help of Uncss7 library. Uncss can be used to remove unwanted CSS from stylesheets and supports multi-file and javascript-injected CSS.
5. Use selectors selectively
As most of you probably know, CSS selectors are matched from right to left, a strategy that results in performance differences between different types of selectors. It obviously takes more time for the browser to generate the render tree with # markdown. content h3 than with #markdown-content-h3. That’s because you need to find all the H3 elements in the DOM, filter out the ancestor elements that aren’t.content, and filter out the ancestor elements that aren’t #markdown. Imagine that if there are more nested levels and more elements on the page, the time cost of matching will be higher. However, modern browsers have done a lot of optimization in this area, and the performance of the different selectors is not significantly different, if not very different. In addition, the performance of different selectors in different browsers is not completely uniform, and CSS cannot be written for every browser. For these two reasons, there are only a few things to keep in mind when using a selector, and the rest is up to your liking.
- Keep it simple and don’t use overly nested and complex selectors.
- Wildcards and attribute selectors are the least efficient and have the most elements to match, so avoid them.
- Do not use class selectors and ID selectors to decorate element tags such as H3 #markdown-content, which is unnecessary and inefficient.
- Don’t sacrifice readability and maintainability for speed.
If you still have doubts about the above points, I suggest adopting one of the following CSS methodologies (BEM9, OOCSS10, SUIT11, SMACSS12, ITCSS13, Enduring CSS14, etc.) as the CSS specification. Using a common methodology helps create a common style, reduces naming conflicts, and avoids the above problems. If you don’t already use it, use it now.
Why do CSS selectors match from right to left?
More selectors in CSS do not match, so when considering performance, you need to consider how to improve efficiency when selectors do not match. Right-to-left matching is intended for this purpose, and it makes CSS selectors more efficient when they do not match. When you think about it, it makes sense to spend a little more performance on matching.
6. Reduce the use of expensive attributes
All properties that require the browser to manipulate or calculate when the browser draws the screen are relatively expensive. They degrade browser rendering performance when pages are redrawn. So when writing CSS, we should minimize the use of expensive attributes such as box-shadow/border-radius/filter/ transparency /:nth-child, etc. Of course, this is not to say that you should not use these properties, because these should be the properties that we use all the time. The reason why I mention this is to give you an idea of this. When there are two options to choose, you can preferentially choose the option with no expensive attributes or fewer expensive attributes. If you choose this option every time, the performance of the website will be improved unconsciously
7. Optimize rearrangement and redraw
7.1 Reduce reordering Reordering causes the browser to recalculate the entire document and rebuild the rendering tree, a process that slows down the browser’s rendering speed. As shown below, there are many operations that trigger rearrangements, and we should avoid triggering them too often.
- Change font size and font family
- Change the inner and outer margins of elements
- Change the CSS class with JS
- Get position attributes of DOM elements from JS (e.g. width/height/left, etc.)
- CSS pseudo-classes are enabled
- Scroll the scrollbar or resize the window
In addition, you can query CSS Trigger15 to see which attributes trigger rearrangements and redraws. It is worth mentioning that some CSS properties have better rearrangement performance. When using Flex, rearrangement is faster than when using inline-block and float, so Flex can be prioritized in layout.
7.2 Avoid unnecessary redrawing
Redraw is triggered when the appearance of an element (such as color, background, visibility, etc.) changes. In the use of the site, redrawing is unavoidable. However, the browser has been optimized to combine multiple rearrangements and redraws into one execution. However, we still need to avoid unnecessary redrawing, such as the Hover event triggered when the page scrolls. We can disable the hover event when the page scrolls, so that the page scrolls more smoothly. In addition, we are writing more and more animation-related code in CSS, and we have become accustomed to using animation to improve the user experience. When writing animations, we should also refer to the above to reduce redraw and rearrangement triggers. Hardware Acceleration 16 and Will-Change17 are also available to improve animation performance, which is not covered in detail in this article. If you are interested, you can check out the link.
Finally, it’s important to note that users’ devices may not be as good as they think, at least not as good as our development machines. You can use Chrome’s developer tools to slow down the CPU and then test it.
8. Do not use @import
Finally, don’t use @import to introduce CSS, which I’m sure you rarely do.
There are two main reasons why @import is not recommended.
First, introducing CSS with @import affects parallel downloads in the browser. Only after the referenced CSS file is downloaded and parsed will the browser know that there is another CSS that needs to be downloaded, and then it will start parsing and building the Render Tree. This causes the browser to be unable to download the required style files in parallel.
Second, multiple @imports can result in a disordered download order. In IE, @import will cause the download order of resource files to be disrupted, that is, js files arranged after @import are downloaded before @import, and the parallel download of @import itself is disrupted or even destroyed.
So don’t use this method, just use the link tag.
conclusion
At this point, we’ve covered four practical and four suggested techniques for CSS performance tuning. With these tips in mind, CSS performance tuning can begin now. Don’t hesitate to start as soon as possible.