WecTeam: From the mobile phone scrolling frame loss problem, learn browser synthesis and rendering layer optimization

WecTeam: From the mobile phone scrolling frame loss problem, learn browser synthesis and rendering layer optimization

Reprinted from: [WecTeam: Browser composition and rendering layer optimization] (https://mp.weixin.qq.com/s/knmQ1XRwt4sUdwTjORoF4A)

A murder case triggered by CSS properties

Web page performance is a special focus for front-end development. There are many indicators for judging the performance of front-end Web pages. The fluency of the page is one of them. How to make the page "smooth and silky" is quite a discussion. There is a topic of material. When I was developing the mobile H5 page before, I encountered an interesting performance problem-a certain store page appeared severely stuck on the IOS phone, but it performed very smoothly on the Android model. Summarize the specific performance tested on iPhoneX:

  • There is a significant delay when the page loads, but the network request captured by the proxy takes no longer than Android;
  • When the page is scrolled, there will be a brief partial white screen, that is, frame loss.

Based on these characterizations, it is not difficult to infer that something is madly occupying the CPU and blocking the rendering process.

However, I don't know what it is, if you ask me. For this kind of problem that cannot be located through the breakpoint, I am afraid that only the "code dichotomy" passed down by the ancestor can be used to overcome it. After some arduous investigation, the source of the problem finally focused on the following line of CSS code:

  filter: blur(100px);

This line of CSS code is used to implement a Gaussian blur to construct the bottom shadow of a coupon module. Because the event is configured with multiple coupons, there are multiple div elements with this attribute set on the page, and the browser of IOS mobile phone seems to be very struggling to render this attribute (but the reason for the strenuousness is unknown), which leads to The CPU occupancy rate of the rendering process is too high, which will eventually cause a freeze.

Oh? Is the CPU too busy? Easy to handle! I added this line of code to the coupon module, and the problem was solved...

  will-change: transform;

You read that right, and I didn't write less, it is indeed solved by one line of code.

People who know it may have seen it. The general principle is actually very simple. This line of code can turn on GPU to accelerate page rendering, which greatly reduces the load pressure on the CPU and achieves the purpose of optimizing page rendering performance. If you don’t understand CSS hardware acceleration, you can Check out this article Increase Your Site's Performance with Hardware-Accelerated CSS[1] .

The problem is solved, but is it really finished like this? In line with the great principle of "pull the tree to find the roots", I studied this thing carefully and found that GPU acceleration is actually not that simple.

Browser rendering process

Before discussing the principle in detail, we need to understand some basic concepts of the browser rendering process. The browser rendering process is an old topic. For the question of "how the browser renders the content of a page", many people can talk about a relatively complete process, from network request to browser analysis, which can be specific to Lots of details. The step of removing the network resource acquisition, Web page of our understanding of the display, can generally be divided 构建 DOM 树, 构建渲染树, 布局, 绘制, 渲染层合成a few steps.

  • Building a DOM tree: The browser parses HTML into a tree structured DOM tree. Generally speaking, this process occurs when the page is first loaded, or when the page JavaScript modifies the node structure.
  • Build the render tree: The browser parses the CSS into a tree structured CSSOM tree, and then merges it with the DOM tree into a render tree.
  • Layout: The browser calculates the position of each node on the screen according to the nodes embodied in the rendering tree, the CSS definition of each node, and their affiliation. The layout of elements in a Web page is relative. Changes in the position and size of the elements on the page often cause other nodes to interact, requiring recalculation of the layout. The layout process at this time is generally called Reflow.
  • Drawing (Paint): traverse the tree rendered, the renderer calls the paint()method of drawing out the contents of the node on the screen, a pixel is essentially the filling process. This process also occurs in partial repainting of the screen caused by reflow or some CSS modification that does not affect the layout. At this time, it is called repaint. In fact, the drawing process is done on multiple layers, and these layers are called RenderLayer.
  • Rendering layer composition (Composite): Multiple rendered rendering layers are merged in an appropriate overlapping order, and then a bitmap is generated, which is finally displayed on the screen through the graphics card.

This is a basic browser's process from parsing to drawing a Web page. It is related to the solution to the page jam problem above. It is mainly the last link-rendering layer synthesis.

Render layer composition

1. what is rendering layer composition

Each node in the DOM tree corresponds to a render object (RenderObject). When their render objects are in the same coordinate space (z-axis space), they will form a RenderLayers, which is the rendering layer. The rendering layer will ensure that the page elements are stacked in the correct order. At this time, layer composition (composite) will occur, so as to correctly handle the display of transparent elements and overlapping elements.

This model is similar to the layer model of Photoshop. In Photoshop, each design element is an independent layer, and multiple layers are superimposed on the z-axis space in an appropriate order to form a complete design drawing.

For pages with overlapping elements, this process is especially important, because once the merged order of the layers is wrong, the elements will display abnormally.

2. the rendering principle of the browser

From the rendering process of the browser, we know that the page HTML will be parsed into a DOM tree, and each HTML element corresponds to a node node on the tree structure. And from the DOM tree to each rendering layer, and finally perform the process of merging and drawing, there are actually some transitional data structures in the middle. They record the principle of transformation from the DOM tree to the screen graphics. The essence is the tree structure to Evolution of layer structure.

1. Render Object (RenderObject)

A DOM node corresponds to a rendering object, and the rendering object still maintains the tree structure of the DOM tree. A rendering object knows how to draw the content of a DOM node, and it draws the DOM node by issuing the necessary drawing calls to a graphics context (GraphicsContext).

2. Render Layer (RenderLayer)

This is the first layer model constructed during browser rendering. Rendering objects in the same coordinate space (z-axis space) will be merged into the same rendering layer. Therefore, according to the stacking context, rendering objects in different coordinate spaces will be Form multiple rendering layers to reflect their stacking relationship. Therefore, the browser will automatically create a new rendering layer for a rendering object that meets the conditions for forming a stacking context. Can cause the browser to create a new rendering layer for it, including the following types of common situations:

  • Root element document
  • Have clear positioning attributes (relative, fixed, sticky, absolute)
  • opacity <1
  • Has CSS fliter attribute
  • Has CSS mask property
  • There is a CSS mix-blend-mode property and the value is not normal
  • Has a CSS transform property and the value is not none
  • The backface-visibility property is hidden
  • Has CSS reflection property
  • There is a CSS column-count property and the value is not auto or there is a CSS column-width property and the value is not auto
  • Currently there are application animations for opacity, transform, fliter, and backdrop-filter
  • overflow is not visible

There is a one-to-one correspondence between DOM nodes and rendering objects, and the rendering objects that meet the above conditions can have independent rendering layers. Of course, the independence here is not completely accurate, and it does not mean that they completely share the rendering layer. Because the rendering object that does not meet the above conditions will share the same rendering layer with the first parent element that has the rendering layer, the actual Above, these rendering objects will share this rendering layer with some of its child elements.

3. Graphics Layer (GraphicsLayer)

GraphicsLayer is actually a layer model responsible for generating the content graphics that are finally ready to be presented. It has a graphics context (GraphicsContext), and GraphicsContext will be responsible for outputting the bitmap of this layer. The bitmap stored in the shared memory will be uploaded to the GPU as a texture, and finally multiple bitmaps will be synthesized by the GPU, and then drawn on the screen. At this time, our page is also displayed on the screen.

So GraphicsLayer is an important rendering carrier and tool, but it does not directly deal with the rendering layer, but the composite layer.

4. CompositingLayer

The rendering layer that meets some special conditions will be automatically promoted to the composite layer by the browser. The composite layer has a separate GraphicsLayer, and other rendering layers that are not composite layers share one with the first parent layer that has GraphicsLayer.

So what special conditions can a rendering layer meet before it can be promoted to a composite layer? Here are some common situations:

  • 3D transforms: translate3d, translateZ, etc.
  • video, canvas, iframe and other elements
  • Opacity animation conversion realized by Element.animate()
  • Opacity animation conversion realized by СSS animation
  • position: fixed
  • Has the will-change attribute
  • Animation or transition applied to opacity, transform, fliter, backdropfilter

Therefore, the first example of text solutions, in fact, is the use of will-change properties, high CPU consumption render elements upgraded to a new synthetic layer, in order to open the GPU acceleration, so you can also use transform: translateZ(0)to solve this problem.

It is worth noting here that many people confuse the conditions of these composite layers with the conditions generated by the rendering layer. These two conditions occur in two different layer processing links and are completely different.

In addition, some articles will also list CSS Filter as one of the factors that affect Composite. However, after verification, I found that it has no effect.

3. implicit synthesis

As mentioned above, when certain explicit special conditions are met, the rendering layer will be promoted to the composition layer by the browser. In addition, in the Composite phase of the browser, there is also an implicit composition. In some specific scenes, some rendering layers will be promoted to composition layers by default.

For implicit synthesis, CSS GPU Animation [2] describes it like this:

This is called implicit compositing: One or more non-composited elements that should appear above a composited one in the stacking order are promoted to composite layers. Is promoted to the composition layer.)

This sentence may be difficult to understand, but it is actually describing an overlap problem (overlap). Give an example to illustrate:

  • Two absolute positioned div on the screen overlap, according to z-indexthe relationship, one div will "cover" another top.
  • At this time, if the lower div is added with the CSS attribute:, transform: translateZ(0)it will be promoted to the composition layer by the browser. The upgraded synthesis layer is located above the Document. If there is no implicit synthesis, the div that should have been on the top still shares a GraphicsLayer with the Document, but the level is lowered, and there is a problem of disordered element overlap relationships.
  • Therefore, in order to correct the wrong overlapping sequence, the browser must also upgrade the rendering layer that should be "covered" to the composite layer at the same time.

4. layer explosion and layer compression

1. Layer explosion

From the above research, we can find that some of the reasons for the synthesis layer are too concealed, especially the implicit synthesis. In the usual development process, we seldom pay attention to the problem of layer synthesis. It is easy to produce some synthetic layers that are not within the expected range. When these synthetic layers that do not meet expectations reach a certain level, they will become layers. explosion.

Layer explosion will take up GPU and a lot of memory resources, seriously depleting page performance, so blindly using GPU acceleration, the result may be counterproductive. CSS3 hardware acceleration also has pits[3] This article provides a very interesting DEMO[4] , this DEMO page contains an h1 title, which applies an animation to the transform, which in turn causes it to be rendered in the composition layer. Due to the special nature of animation transform (overlapping dynamic uncertainty), the synthesis can occur implicitly without the need for overlapping, it has led in all the page z-indexabove its nodes corresponding to all lifting render layer synthetic layer In the end, thousands of composite layers were generated on this page.

Eliminate implicit element synthesis is to eliminate overlap, take this DEMO, we just need to give h1 title of z-indexproperty to a higher value, it can be higher than other page elements, naturally there is no synthetic layer upgrade Necessary. Click the check button in the DEMO to add a larger title to the h1 title z-index, and the effect before and after is very obvious.

2. Layer compression

Of course, in the face of this problem, browsers also have corresponding countermeasures. If multiple rendering layers overlap with the same composite layer, these rendering layers will be compressed into a GraphicsLayer to prevent possible overlap caused by " Layer explosion". This sentence is not easy to understand, you can take a look at this example:

  • The same as the previous model, but this time the difference is that there are four absolutely positioned divs that overlap on the screen. Div is now in the bottom of the CSS properties added transform: translateZ(0)after the browser upgraded to synthetic layer, according to the principle implicit synthesis, cover it on top of the div will be promoted to a new synthetic layer, and the third div Covering the second one will naturally be promoted to a composite layer, and the fourth is the same. In this way, wouldn't it have four composite layers?
  • However, this is not the case. The browser’s layer compression mechanism compresses multiple implicitly synthesized rendering layers into the same GraphicsLayer for rendering, that is to say, the three divs above will end up in the same composite layer. , This is the layer compression of the browser.

Of course, the automatic layer compression of the browser is not omnipotent. There are many specific situations in which the browser cannot perform layer compression. Wireless performance optimization: The article Composite[5] lists many detailed scenarios.

Page rendering optimization based on layer composition

1. The gains and losses of layered synthesis

Layer composition is a relatively complex browser feature. Why do we need to pay attention to something that is so low-level and difficult to understand? That's because after the rendering layer is upgraded to the compositing layer, it will bring us a lot of benefits:

  • The bitmap of the synthesis layer will be synthesized by the GPU, which is much faster than the CPU;
  • When repaint is needed, only repaint itself is needed, and other layers will not be affected;
  • After the element is promoted to a composite layer, transform and opacity will not trigger repaint. If it is not a composite layer, it will still trigger repaint.

Of course, the pros and cons are relative and coexistent, and layer composition also has some shortcomings, which often become the root of our web page performance problems:

  • The drawn layers must be transmitted to the GPU. After the number and size of these layers reach a certain level, the transmission may be very slow, which will lead to flickering on some low-end and mid-range devices;
  • Implicit synthesis is prone to produce excessive synthesis layers. Each synthesis layer occupies additional memory. Memory is a precious resource on mobile devices. Excessive use of memory may cause the browser to crash, making performance optimization counterproductive.

2. how to view the composition layer in Chrome Devtools

The characteristics of layer composition provide us with a way to optimize page performance by using terminal hardware capabilities. For some pages that are heavily interactive and animated, reasonable use of layer composition can greatly improve the rendering efficiency of the page and improve the interactive experience. And what we need to pay attention to is how to avoid the negative impact of layer synthesis on the page, or to put it another way, more often, how to weigh the advantages and disadvantages and rationally organize the composition layer of the page, which requires us to prioritize the composition of the page. Have a detailed understanding. Chrome Devtools provides us with some tools to easily view the composition layer of the page.

1. take a look at the rendering of the page. Take a section page as an example. Click More tools -> Renderingand select Layer borders, and you can see that the composite layers in the page are all with yellow borders.

This is not enough, we also need a more detailed layer composition, click More tools -> Layers, you can see a view like this:

On the left is a list of all the elements that have been promoted to an independent composite layer, and on the right is a view of the overall composite layer boundary and the details of the selected composite layer, including the following key information:

  • Size: The size of the composite layer, which is actually the size of the corresponding element;
  • Compositing Reasons: The reason for the formation of the composite layer is the most critical, and it is also the breakthrough point for us to analyze the problem. For example, the reason for the composite layer in the picture is the overlap problem;
  • Memory estimate: memory usage estimate;
  • Paint count: the number of draws;
  • Slow scroll regions: Slow scroll regions.

It can be seen that we have inadvertently produced many unexpected synthetic layers, and these synthetic layers that have no practical significance can be optimized.

3. some optimization suggestions

1. The animation is implemented using transform

For some key animations with high experience requirements, such as some interactive and complex gameplay pages, there are animation elements that continuously change positions. It is best to use transform to achieve it instead of changing the left/top method. The reason for this is that if you use left/top to change the position, the animation node and the Document will be placed in the same GraphicsLayer for rendering, and the continuous animation effect will cause the entire Document to continue to redraw. If you use transform, The animation node can be placed in an independent composite layer for rendering and drawing, and other layers will not be affected when the animation occurs. And on the other hand, the animation will run completely on the GPU. Compared with the CPU processing the layer and then sending it to the graphics card for display and drawing, such animation is often smoother.

2. Reduce implicit synthesis

Although implicit compositing is fundamentally to ensure the correct layer overlap order, but in actual development, implicit compositing can easily lead to the generation of some meaningless composite layers. In the final analysis, we are required to constrain ourselves during development. The layout habits to avoid stepping on pits.

For example, in the column page mentioned above, the page has too many composite layers due to inadvertent development. When I tried to check the page composite layer, I could already feel the lag on the PC. After analyzing the use of Chrome Devtools not difficult to find, there is a button with a button inside the page animation transform and upgrade to synthetic layer, overlapping animation uncertainty makes other pages within z-indexlarger than it in fact did not overlap but also all the nodes Promote to the composite layer (this reason is really a pit).

This time we just need this animation node z-indexproperty value is set larger, so too high stacking order page other unrelated node on the line. Of course, not blindly set z-indexwill be able to avoid, sometimes z-indexstill lead to an implicit synthesis, this time you can try to adjust the order of the nodes in the document directly behind the node to node front cover, without z-indexadjusting the overlapping relationship . The method is not unique, the specific method still has to be analyzed according to different pages.

The improved page effect is as follows, you can see that compared to before optimization, we have eliminated a lot of meaningless synthesis layers.

3. Reduce the size of the composite layer

Here is a simple example, were painted the same two sizes div, but a little different implementations: a direct setting size 100x100, another set size 10x10, then scaleenlarged 10 times, and we let these two are upgraded to synthetic div Floor:

<style> .bottom, .top {position: absolute; will-change: transform;} .bottom {width: 100px; height: 100px; top: 20px; left: 20px; z-index: 3; background: rosybrown;} .top {width: 10px; height: 10px; transform: scale(10); top: 200px; left: 200px; z-index: 5; background: indianred; }</style><body> <div class="bottom "></div> <div class="top"></div></body>

After using the Chrome Devtools view both memory footprint found synthetic layer, .bottomthe memory footprint is 39.1 KB, but .topis 400 B, the gap is very obvious. This is because the .topsynthetic layer, located Composite Transform stage, is now entirely on the GPU. Thus for some solid layer, we can use the width and height attributes to reduce the physical size of the synthetic layer, and then transform: scale(…)amplified to such a layer can greatly reduce memory consumption brought synthesized.

Reference: https://cloud.tencent.com/developer/article/1540230 WecTeam: From the mobile phone scrolling frame loss problem, learn browser composition and rendering layer optimization-Cloud + Community-Tencent Cloud