Udacity: Browser Rendering Optimization

December 20, 2017 - CSS, HTML, javascript

60 frames per second – approx 10-16 ms per frame

Making a frame

HTTP GET request
Server sends HTML
Browser parses HTML into DOM – PARSE HTML
Render tree (only visible elements)
Change list of nodes into vector boxes on a page – LAYOUT
Change vector into raster – PAINT
Painting images – IMAGE DECODE + RESIZE

Painting can make multiple layers and paint to them individually in CPU COMPOSITE LAYERS
At the end CPU handles data to GPU and content is painted

Layout and Paint

  1. JS/CSS Style Layout Paint Composite (margin, width)
  2. JS/CSS Style Paint Composite (color, background)
    2.. JS/CSS Style Composite (cursor, transform, opacity)

CSS Triggers






Javascript Compilers

Just In Time

Modern Browsers recompile JS code to run in Engine. Avoid Micro Optimizations.

Execute JS as early as possible every frame.


function animate() {


requestAnimationFrame Polyfill

Using web workers

Create a web worker

    var myWorker = new Worker('scripts/worker.js');

Send data to web worker

myWorker.postMessage({"imageData":imageData, "type": type});

Code of web worker

this.onmessage = function(e) {
  console.log('Message in the worker');
  var imageData =;
  var type =;
    } catch (e) {
    function ManipulationException(message) { = "ManipulationException";
      this.message = message;
    throw new ManipulationException('Image manipulation error');

Getting data back from web worker

    // Get data from web worker
    myWorker.onmessage = function(e) {
        var image =;

JS Memory management

var x = { };

When garbage colector works everything else pauses.

See the memory spikes
If memory doesn’t get to 0 when garbage is collected, we have a memory leak.

GC for Garbage Collection


The cost of recalculate styles scales linearly with the number of elements.

Selector matching


Class matching is preferreed

Reduce Affected Elements = fewer changes to render tree
Reduce Selector Complexity = use fiwer tags + class names to select elements

Create an array of DOM nodes to use with forEach()

Batch your style changes and avoid running layout as much as possible.

function getDomNodeArray(selector) {
  // get the elements as a DOM collection
  var elemCollection = document.querySelectorAll(selector);

  // coerce the DOM collection into an array
  var elemArray = Array.prototype.slice.apply(elemCollection);

  return elemArray;

var divs = getDomNodeArray('div');
# sample 1
var newWidth = container.offsetWidth;
divs.forEach(function(elem,index,arr) { = newWidth;
# sample 2
if (elem.offsetHeight < 500) {
divs.forEach(function(elem,index,arr) { = '100vh';

Compositing and Painting

To see which portions of the screen need to be repainted turn on Paint flashing in Performance (Esc) – Rendering – Paint Flashing

Paint Profile

Record performance and deep dive into Paint on Main timeline


Don’t use paint when possible.

Use layers and translate them.

Managing layers

See if an element already has it’s own layer
Performance (Esc) – Rendering – Layer Borders

### Make a layer for the element

 .circle {
     /* for older browsers */
     transform: translateZ(0)
         will-change: transform; /* left top width height */

Number of layers

  1. Open Performance and record interaction
  2. Select item in Frames
  3. Layers Tab becomes available and shows a 3D environment

Using CSS to show/hide

.story-details {
    width: 100%
    height: 100%
    left: 100%;
    top: 0;
    z-index: 2;
    display: flex
    position: fixed;
    overflow: hidden
    transition: transfotm 0.3s;
    will-change: transform;

.story-details.visible {
    transform: translateX(-100vw)

.story-details.hidden {
    transform: translateX(0);


Udacity: Browser Rendering Optimization