The cause of
I have read a problem (how to implement a progress bar) and other people’s articles, and I think there are still many holes left to be covered. If readers implement according to the author’s article, it may lead to bigger problems. Say train of thought below, everybody sees oneself in which layer!
The first layer
Our simplest implementation is a div inside a div, dynamically change the width of the div inside, to achieve the effect of a progress bar
Code:
<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta <title>Document</title> <style> #container {width: 600px; height: 20px; display: inline-block; border: 1px solid; overflow: hidden; } #progress { width: 0; background: pink; height: 100%; The transition: 0.5 s linear width; } < / style > < / head > < body > < div id = "container" > < div id = 'progress' > < / div > < / div > < div > < button id = "BTN" > button < / button > </div> <script> const btn = document.getElementById('btn') const progress = document.getElementById('progress') btn.onclick = () => { let width = 0 const timer = setInterval(() => { if (width === 100) return clearInterval(timer) progress.style.width = `${++width}%` }, 50); } </script> </body> </html>Copy the code
Performance:
As you can see from the picture, changing width frequently leads to layout, and layout usually leads to paint, so it takes a lot of time.
The second floor
We are now at the second layer, so we thought of using transform. I only change its position without triggering the layout, which must be good performance!
Code:
<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta <title>Document</title> <style> #container {width: 600px; height: 20px; display: inline-block; border: 1px solid; overflow: hidden; } #progress { display: inline-block; background: pink; height: 100%; The transition: 0.5 s linear transform; width: 100%; transform: translateX(-100%); } < / style > < / head > < body > < div id = "container" > < div id = 'progress' > < / div > < / div > < div > < button id = "BTN" > button < / button > </div> <script> const btn = document.getElementById('btn') const progress = document.getElementById('progress') btn.onclick = () => { let process = 0 const timer = setInterval(() => { if (process === 100) return clearInterval(timer) progress.style.transform = `translateX(-${100 - ++process}%)` }, 50); } </script> </body> </html>Copy the code
Performance:
We can see that without triggering the layout, we don’t trigger extra paint, and the natural performance is much better!
The third layer
The will-change attribute comes to mind at this point, which simply tells the browser what changes are about to happen, so the browser can optimize to make the page faster and more responsive.
Note:
- Do not abuse this property, which can degrade performance.
- A good use of will-change is to add attributes before they change, but browsers usually allow at least 200 milliseconds for optimization Settings, so we want to give browsers time to optimize.
Reference documentation
- Developer.mozilla.org/zh-CN/docs/…
- Drafts.csswg.org/css-will-ch…
The fourth floor
We set the elements ‘transition: transform’ or ‘will-change: Transform ‘to be promoted to the compositing layer for rendering, as shown below:
Open the control panel, then CTRL + Shift + P and search layers to open the panel
Layer explosion
In the following image, when the progress bar starts to move, it will be raised to the composite layer for rendering. However, many of the following data tags are stacked higher than the progress bar. To ensure the correct stacking order, the browser will raise the elements higher than the progress bar, because our li tag has overflow set: Hidden, causing the browser to fail to optimize for the extra promoted elements (layer compression), and thus causing the layer explosion to occur!
Layer explosion effect
The optimization effect
We set the bar to a high Z-index of 999, so that the bar is higher than all the other elements, so the browser doesn’t have to implicitly promote other elements and it doesn’t explode
Code:
<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta <title>Document</title> <style> #container {width: 600px; height: 20px; display: inline-block; border: 1px solid; overflow: hidden; } #progress { position: relative; display: inline-block; background: pink; height: 100%; The transition: 0.5 s linear transform; width: 100%; transform: translateX(-100%); } .list-item { position: relative; /* overflow: hidden; } .list-item-text { position: absolute; left: 0; top: 0; } < / style > < / head > < body > < div id = "container" > < div id = 'progress' > < / div > < / div > < div > < button id = "BTN" > button < / button > </div> <hr /> <! --> <ul id='listContainer'></ul> <script> const BTN = document.getelementById (' BTN ') const progress = document.getElementById('progress') btn.onclick = () => { let process = 0 const timer = setInterval(() => { if (process === 100) return clearInterval(timer) progress.style.transform = `translateX(-${100 - ++process}%)` }, 50); } const createData = () => { const listContainer = document.getElementById('listContainer') let str = '' for (let i = 0; i < 1000; i++) { str += `<li class='list-item'> <div class='list-item-text'>${i}++++++++++++++</div> </li>` } listContainer.innerHTML = str } createData() </script> </body> </html>Copy the code
The fifth floor
If we develop a progress bar component, we can’t guarantee that other users are familiar with the knowledge of layer explosion. At this time, we adjust the z-index of the progress bar, which may lead to other styles of confusion, so this should be carefully chosen!
The last
A simple progress bar covers a lot of browser rendering, rearrangement, redrawing, layer promotion, layer explosion, layer compression, craters and more.
I was looking at other open source component libraries that use width to implement the progress bar, and I thought they were at level 1. After slowly learning the front-end knowledge, I suddenly realized that they were at level 5!