From Braces to Pixels and Inside look at modern browser browser.
Layout changes involve calculating the geometry (position and size) of all the elements affected by the change. If you change one element, the geometry of other elements may need to be recalculated. For example, if you change the width of the
<html> element any of its children may be affected. Due to the way elements overflow and affect one another, changes further down the tree can sometimes result in layout calculations all the way back up to the top.
The larger the tree of visible elements, the longer it takes to perform layout calculations.
Paint is the process of determining in what order elements should be painted to the screen. It is often the longest-running of all tasks in the pipeline.
The majority of painting in modern browsers is done in software rasterizers. Depending on how the elements in your app are grouped into layers, other elements besides the one that changed may also need to be painted.
Compositing is the process of separating the page into layers, converting the information about how the page should look into pixels (rasterization), and putting the layers together to create a page (compositing).
This is why the
opacity property is included in the list of things which are cheap to animate. As long as this property is in its own layer, changes to it can be handled by the GPU during the compositing step. Chromium-based browsers and WebKit create a new layer for any element which has a CSS transition or animation on
For an in-depth look at compositing see the article GPU Animation: Doing It Right
By placing the things that will be animated or transitioned onto a new layer, the browser only needs to repaint those items and not everything else. You may be familiar with Photoshop's concept of a layer which contains a bunch of elements that can be moved together. Browser rendering layers are similar to that idea.
While the browser does a good job of making decisions about what elements should be on a new layer, if it misses one there are ways to force layer creation. You can find out about that in How to create high-performance animations. However, creating new layers should be done with care because each layer uses memory. On devices with limited memory creating new layers may cause more of a performance problem than the one you are trying to solve. In addition, each layer's textures need to be uploaded to the GPU. Therefore you may well hit constraints of bandwidth between the CPU and GPU.
You can read a good explanation of layers, and how to create them in Layers and how to force them.
As explained in this article, other changes to transforms and opacity can, in many cases, also be handled by the compositor thread.