On translate3d and layer creation hacks
Translate3d is often hailed as something of a silver bullet. In many cases it will drastically improve rendering performance in WebKit and Blink browsers like Chrome, Opera and Safari. Let's take a look at why it can improve rendering performance, and what we need to be careful of.
The "go faster" hack! #
So you know that magic bullet hack for Chrome (and other WebKit ports) that makes things really zippy? You know, -webkit-transform: translateZ(0);
or its good friend -webkit-transform: translate3d(0,0,0);
? Sometimes it’s called the null transform hack. A lot of developers apply it to their elements to give their pages a speed boost so I wanted to take a quick peek behind the scenes (from a Chrome perspective) and see why it works.
The translate3d
hack, then, does two things:
- It switches on the hardware compositing mode in Chrome, assuming it's supported for the platform you're on and isn't on already.
- It creates a new layer with its own backing surface in Chrome.
Hardware compositing is generally a good thing because it means the GPU will assist Chrome in putting together the page rather than everything happening on the CPU.
To the second point, not all newly created layers get a new backing surface (a graphics context into which layers are drawn), some layers happily share a backing surface. But in certain circumstances, like when you apply a 3D transform to an element, it gets one of its own. For the morbidly curious, here are the criteria that Chrome uses to determine if a layer needs its own backing surface:
- The layer has 3D or perspective transform CSS properties.
- The layer is used by
<video>
element using accelerated video decoding. - The layer is used by a
<canvas>
element with a 3D context or accelerated 2D context. - The layer is used for a composited plugin, e.g. Flash or Silverlight.
- The layer uses a CSS animation for its opacity or uses an animated webkit transform.
- The layer uses accelerated CSS filters.
- The layer has a descendant that is a compositing layer.
- The layer has a sibling with a lower z-index which has a compositing layer (in other words the layer is rendered on top of a composited layer).
Where things get really messy is on mobile devices, because they have comparatively limited VRAM, and it becomes easy to exhaust that and end up with excruciatingly poor rendering performance.
Each backing surface is essentially a texture that needs to be uploaded to, and composited by, the GPU. Compositing is the process where each of the individual textures uploaded to the GPU is drawn out in turn, and results in one final picture: your page. A major benefit of this is on subsequent frames, where if all you do is move layers around or change their opacity, the GPU can handle all the work directly, leaving the CPU side of things free to do something else.
On a hefty desktop device with a ton of video memory (VRAM) you’ll likely be able to create a lot of newly backed layers without problems. On laptops you’ll possibly have some hiccups, but generally speaking you’ll need to make a lot of layers before you see any snags. Where things get really messy is on mobile devices, because they have comparatively limited VRAM, and it becomes easy to exhaust that and end up with extremely poor rendering performance.
To make matters worse, not all devices are quick to transfer the textures from the CPU side over to the GPU for compositing. Now there are potentially a lot of textures, each taking a long time to get pushed to the GPU.
"Making layers considered dangerous" #
While using 3D transforms can be really tempting, especially if you’re seeing problems with respect to rendering performance, force-hacking layer creation may not be the right solution. Equally it's not something to shy away from, either, you just need to be aware of the trade-offs that you might be making along the way. The important thing is to test your page and adjust accordingly.
In order to test your pages you should first try the frame mode in DevTools's Timeline panel.
If you notice that you're breaking through your frame budget take a step back and see why that is. A lot of the time, in my experience, the reason is either paint or garbage collection. I'm not going to go into garbage collection here, I'll save that for another day, but let's talk briefly about how you can assess the paint work that's going on.
You'll notice the paint records have dimensions next to them, and if you roll over them Chrome handily pops a blue rectangle atop the page. The first thing to say is that if you’re doing a full screen paint, that’s probably very expensive and the first thing you should try to fix. If that's not your problem you’ve perhaps got expensive styles and you should look to minimize their impact. That’s where the new Continuous Paint mode in DevTools comes in handy. Eberhard Gräther, the engineer who built the feature, has written an excellent article on how to profile long paints using it and other features of Chrome's DevTools.
Ultimately translate3d
, like any layer creation criterion, can really boost performance. But it needs to be used wisely, and you should really make sure that it's actually going to solve whatever is slowing down your page.
Finally, like all performance advice, things change so don't guess it, test it.