Fast is better than slow.
Web applications are rife with opportunities to optimize performance.
Optimization efforts often focus early in the request. Those extra milliseconds of paint time at the end feel like a drop in the bucket.
It turns out that the time closest to the user is incredibly important — it can make or break the "snappiness" of your app. Proof!
Freeing up the UI thread with blisteringly-fast JS is key.
…but it's not enough!
Cutting down render time has traditionally been an exercise in tedium.
Edits to the document cause the browser to enter the rendering cycle.
Understanding each step can help diagnose slow rendering.
The Document Object Model (DOM) is an API for HTML documents. It provides a tree representation of the document, which JavaScript can interact with.
An accurate DOM tree is a prerequisite for all other rendering tasks.
This tree is reflected by the DevTools Element Inspector.
var el = document.getElementById('confirm'); el.innerText = 'Success!'; el.appendChild(successIcon.cloneNode());
The browser must calculate the value of every CSS property, for every element on the page.
<button id="menu-button"> Toggle </button>
#menu.closed { color: rgba(0, 0, 0, .9); } #menu:hover { box-shadow: 0, 0, 3px, rgba(0, 0, 0, .3); } #menu[disabled]:hover { box-shadow: none; }
var menuBtn = document.getElementById('menu-button'); menuBtn.classList.add('closed'); menuBtn.setAttribute('disabled', true);
This is a data structure that helps the browser perform layout tasks. Its contents and shape may differ significantly from the DOM.
DOM tree | Rendering tree | |
---|---|---|
Content | Elements and nodes | Boxes |
Parenting strategy | HTML parent | Containing block |
- <div style="display: none">
- <head>
- <script>
- <style>
- line box
- ::before
- anonymous box
- <div>
- <span>
- <a>
A box's containing block determines where and how it is rendered. Its rendering type determines its containing block.
Most boxes are contained by their DOM tree parent. This includes boxes in normal flow (e.g. block, inline) and floats.
Absolute boxes are contained by their closest positioned DOM ancestor.
Sometimes anonymous boxes are inserted, but this doesn't affect performance.
<sectionsectionsection style="position: relative"> <divdivdiv> Meh literally#Meh literallyMeh literally <navnavnav style="position: absolute">vice#vicevice</nav> american apparel.#american apparel.american apparel. </div> Fixie freegan sriracha,#Fixie freegan sriracha,Fixie freegan sriracha, <spanspanspan>direct trade#direct tradedirect trade</span> food truck.#food truck.food truck. </section>
block box: block box: absolute box: anonymous block box anonymous inline box: inline box: anonymous inline box:
- display
- float
- position
The rendering tree also affects layering; more on that shortly.
Calculate the position and dimensions of every box.
Relevant properties:
- height
- width
- padding
- border-width
- margin
- coordinates (top, right, bottom, left)
Determine what color to paint each pixel, create a bitmap, and upload to the GPU.
Transparency can be expensive, especially anti-aliased text.
Chrome paints layers individually. Particular HTML and CSS will invoke a layer, but note this is a Blink/Chrome implementation detail rather than specified behavior.
Layer bitmaps are transferred to the GPU, combined ("composited"), and drawn on the screen.
Relevant properties:
- opacity
- transform