preface

With the development of the Internet so far, for the website, performance is more and more important, CSS as an important link of page rendering and content display, affecting the user’s first experience of the whole website. Therefore, we need to focus on csS-related performance optimization.

Project development early we may because of various reasons (a large part of the reason is that the project time limit, the product is often the time sticks in the project launch, don’t listen to what you said what performance optimization), how comfortable how to write, for performance optimization we often go to consider in the project, often be postponed to the end of the project, Performance tuning is performed even when serious performance problems are exposed.

In order to avoid this situation more, it is important to pay attention to the performance optimization related work throughout the entire product design and development. The second is to understand the performance aspects of the project so that performance tuning occurs naturally during the project development process.

If this article helps you, ❤️ follow + like ❤️ to encourage the author, the article public account first, followThe front nine southGet the latest articles for the first time

CSS rendering rules

To optimize CSS performance, we first need to understand CSS rendering rules. CSS selectors are matched from right to left

Here’s an example 🌰 :

.nav h3 a{font-size: 14px; }Copy the code

The rendering process looks something like this: first find all the A’s, look for H3 along the parent element of A, and then look for.nav along the parent element of A. The nodes that match the matching rules are added to the result set. If the root element is found and the HTML does not match, the path is no longer traversed and the search match is repeated starting with the next A (as long as there are multiple right-most nodes of A on the page).

Why are CSS selectors matched 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.

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 users have to wait to see a page, which can be reduced by inlining Critical CSS (also known as Critical CSS).

Many people like to refer to 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.

But we should not inline all CSS in HTML documents because there is a limit to the initial congestion window (TCP related concepts, typically 14.6kB, compressed size). If the file is inlining CSS beyond this limit, the system will need to make more round trips between the server and the browser. This does not advance page rendering time. Therefore, we should only inline the key CSS needed to render the first screen content into the HTML.

⚠️ Another point to note is that the inline CSS has no cache and will be re-downloaded each time the HTML is loaded. However, we kept the key inline first-screen CSS under 14.6KB, which has a positive effect on performance optimization. (Every coin has both advantages and disadvantages)

Asynchronously loading non-first-screen CSS

Two things we need to know: (See my previous post: How many of these browser interview questions can you answer?)

  • CSSDoes not blockDOMParsing, but blocksDOMThe rendering of
  • CSSblocksJSExecute, but do not blockJSFile download

Since CSS will block DOM rendering, after we inline the key CSS on the first screen, the remaining non-first screen CSS content can use external CSS and load asynchronously to prevent non-first screen CSS content from blocking the rendering of the page.

CSS asynchronous loading mode

The first method is dynamic creation

// Create a link label
const myCSS = document.createElement( "link" );
myCSS.rel = "stylesheet";
myCSS.href = "mystyles.css";
// Insert to the end of the header
document.head.insertBefore( myCSS, document.head.childNodes[ document.head.childNodes.length - 1 ].nextSibling );
Copy the code

The second method is to add the link elementmediaProperty set to media type not matched by the user’s browser (or media query)

For the browser, if the stylesheet does not apply to the current media type, it is prioritized and downloaded without blocking the page rendering. After the first screen file loads, set the value of media to Screen or all to let the browser start parsing the CSS.

<link rel="stylesheet" href="mystyles.css" media="noexist" onload="this.media='all'">
Copy the code

The third way is throughrelProperty will belinkThe element is labeledalternateOptional style sheets

<link rel="alternate stylesheet" href="mystyles.css" onload="this.rel='stylesheet'">
Copy the code

The fourth way is to userel=preloadTo load the CSS asynchronously

<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.

CSS File Compression

This is probably the easiest way to reduce the CSS file size to improve page loading speed. Today’s build tools, such as Webpack, gulp/ Grunt, rollup, etc., also support CSS compression. The compressed file can be significantly smaller, which can greatly reduce the browser load time.

CSS hierarchies should be no more than three

In general, elements cannot be nested at more than three levels, and excessive nesting can lead to bloated, redundant, and complex code. Resulting in large CSS file size, resulting in wasted performance, affect rendering speed! And too much reliance on HTML document structure. Such CSS style, maintenance, extremely troublesome, if you want to modify the style later, may use! Important coverage. Keep it simple and don’t use too many nested and complex selectors.

Remove useless CSS 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.

So how do we know which CSS code is useless?

Google’s Chrome browser does just that right out of the box. Simply go to View > Developer > Developer Tools and open the Sources TAB in the most recent version, then open the Command menu. Then, click Coverage to highlight unused code on the current page in the Coverage Analysis window.

Use * wildcards with caution

We might sometimes write code like this to eliminate the default style of some tags or to unify browser differences in tag rendering:

* {margin:0;padding:0;
}
Copy the code

This is not the best performance, although the code is small, so we’d better write the corresponding tag selector:

body.dl.dd.h1.h2.h3.h4.h5.h6.p.form.ol.ul{
  margin:0;padding:0;
}
Copy the code

Avoid using wildcard selectors in your development

Small picture processing

Generally speaking, there will be many small ICONS on a website. For these small ICONS, the current mainstream solutions are three: cssSprite(Sprite), font ICONS, and image transformation into Base64.

  • CssSprite:Synthesize all icon images into a PNG image, set the width and height of the node, and add bacgroud-position for background positioning. Display ICONS as background images. If a site has 20 ICONS, ask 20 times to use themcssSprite, requiring only one request, greatly reducing HTTP requests. The disadvantage is that the management is not flexible, if you need to add an icon, you need to change the merged image source file, icon positioning should also be standardized, otherwise it is easy to interfere with the positioning between images.
  • Font ICONS: The simple and crude understanding is to treat all ICONS as one font! So you don’t have to ask for pictures. Generally, ICONS are defined by class. To replace ICONS, only the style name is changed, which is easy to manage, clear meaning, flexible zoom in and out, and will not cause distortion. But only monochrome images are supported.
  • Base64:Another solution is to transfer the small icon images into Base64 encoding, which can directly integrate the Base64 encoding into JS or CSS without asking for images, so as to prevent image 404 errors caused by some relative paths or images being deleted. But finding a way to generate a bunch of Base64 encodings. In general, images below 8K are converted to Base64 encoding. If you convert a 50K image to Base64 encoding, you will generate over 65,000 characters of Base64 encoding, which is almost 70K! The advice is:Images below 8K are converted to Base64 encoding.

Avoid using @import

There are two main reasons why @import is not recommended:

  • Importing CSS with @import can affect 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.

  • Multiple @imports can cause the download order to be out of 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.

Do not nest other selectors in front of the ID selector

Nesting other selectors in front of the ID selector is purely redundant

  • The ID selector is unique and has such a large weight that it is nested (.content #text) a total waste of performance.
  • In addition to nesting, no labels or other selectors need to be placed in front of the ID selector. Such asdiv#textor.box#text. Both methods are completely redundant because the ID is unique on the page. Anything in front of it is superfluous!

Remove unnecessary units and zeros

CSS supports a variety of unit and number formats, you can remove trailing and trailing zeros, zeros are always zero, and adding dimensions doesn’t add any value to the contained information.

.box {
  padding:.2px;
  margin: 20px;
  avalue: 0;
}
Copy the code

Optimize reflux and redraw

The browser needs to detect and re-render the changes that occur during the use of the site, some of which are more costly in performance. We all know that the user feels comfortable using the site when the FPS is 60. This means that we need to do everything related to each render in 16.67ms, so we need to do as little as possible.

Reduce backflow and redraw

Merger ofDOMStyle modification, adoptedcss classTo modify the

const el = document.querySelector('.box')
el.style.margin = '5px'
el.style.borderRadius = '12px'
el.style.boxShadow = '1px 3px 4px #ccc'
Copy the code

CSS class is recommended

.update{
  margin: 5px;
  border-dadius: 12px;
  box-shadow: 1px 3px 4px #ccc
}
const el = document.querySelector('.box')
el.classList.add('update')
Copy the code

If you need to access the DOM multiple times, try to cache the DOM using local variables

Avoid using a table layout because a small change can cause the entire table to be rearranged

CSS selectors match from right to left to avoid too many node hierarchies

DOM offline processing to reduce backflow redraw times

The offline DOM does not belong to any part of the current DOM tree, which means that our processing of the offline DOM does not cause backflow or redrawing of the page.

  • usedisplay: noneAs we mentioned above (display: none) completely removes elements from the render tree so that they are neither visible nor part of the layout, and subsequent operations on the DOM do not trigger backflow or redrawdisplayProperty changed to display triggers only one redraw and redraw.

Note that ⏰ : visibility: hidden elements only affect redrawing, not rearrangement.

  • throughdocumentFragmentTo create adomDocument fragment on which to batch operatedom, and then add to the document, which triggers only one rearrangement.
const el = document.querySelector('.box')
const fruits = ['front'.'nanjiu'.'study'.'code'];
const fragment = document.createDocumentFragment();
fruits.forEach(item= > {
  const li = document.createElement('li');
  li.innerHTML = item;
  fragment.appendChild(li);
});
el.appendChild(fragment);
Copy the code
  • Clone the node and replace the original node after modification
const el = document.querySelector('.box')
const fruits = ['front'.'nanjiu'.'study'.'code'];
const cloneEl = el.cloneNode(true)
fruits.forEach(item= > {
  const li = document.createElement('li');
  li.innerHTML = item;
  cloneEl.appendChild(li);
});
el.parentElement.replaceChild(cloneEl,el)
Copy the code

The DOM is detached from the normal document flow

Use absoult or Fixed to remove the element from the normal document flow. Using absolute positioning makes the element a child of the body in the rendering tree, with low rearrangement overhead and less impact on other nodes.

CSS3 Hardware acceleration (GPU acceleration)

Using CSS3 hardware acceleration, transform, opacity, and filters can be rendered without backflow redrawing. Other properties of animations, such as background-color, will still cause backflow redraw, but it can still improve the performance of those animations.

Common CSS properties that trigger hardware acceleration:

  • transform
  • opacity
  • filters
  • Will-change

Set the node to a layer

Layers prevent the rendering behavior of this node from affecting other nodes. For the video TAB, for example, the browser automatically turns the node into a layer.

For more information on Reflow & Repaint, see this article: Reflow & Repaint, and how to optimize it.

Recommended reading

  • Super comprehensive summary of Vue interview knowledge points, help golden three silver four
  • Common front-end sorting algorithms
  • Common front-end security problems and preventive measures
  • Why are big factories using GIF as a burying point?
  • Don’t just know about KFC, you should know about BFC, IFC, GFC and FFC
  • What is the difference between Promise, Generator, and Async?
  • In 2022, don’t you know the difference between an arrow function and a normal function?
  • From how to use to how to implement a Promise
  • Explains the page loading process in great detail

The original address point here, welcome everyone to pay attention to the public number “front-end South Jiu”, if you want to enter the front-end exchange group to learn together, please click here

I’m Nan Jiu, and we’ll see you next time!!