Making silky smooth Web Page

Table of Contents

  • Critical Rendering Path
  • RAIL
  • JavaScript
  • Style & Layout
  • Paint & composite

Critical Rendering Path

The process of rendering pixels

using HTML, CSS, and JavaScript

Build DOM

BytesCharactersTokensNodesDOM
BytesCharacters3C 62 6F 64 79 3E 48 65 6C 6C …<html><head>…</head><body>…
Tokens<html><head>…</head><body>…CharactersStartTag:htmlStartTag:headEndTag:headStartTag:body

Build CSSOM

BytesCharactersTokensNodesCSSOM
CharactersTokensNodesbodypspanspanbody {font-size: 16px;}p {color: red;}p span {display:none;}span {font-size: 14px;}img {float: right;}imgCSSOMfont-size:16px;font-size:16px; float:right;font-size:16px; font-size:14px;font-size:16px; color:red;font-size:16px; color:red; display:none;

Build Render Tree

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Demos</title>
    <style>
        body {font-size: 16px;}
        p {color: red;}
        p span {display:none;}
        span {font-size: 14px;}
        img {float: right;}
    </style>
</head>
<body>
    <p>Hello <span>berwin</span></p>
    <span>Berwin</span>
    <img src="https://p1.ssl.qhimg.com/t0195d63bab739ec084.png" />
</body>
</html>

Layout

Paint

JavaScript

Blocking

Build DOM

CSSOM Blocking

Build DOM

Build DOMDOMCSSOMBuild CSSOMRender Tree1.2 sBuiDOMCSSOMBuild CSSOMRender TreeJSRun JavaScriptBui0.2sBuild DOM1sblockingFInd JSFind CSS1 s1 sContinue to build DOMwait CSSOMVSBuiFind CSS

We can do better...

Optimizing the Critical Rendering Path

  • The number of critical resources
  • The critical path length
  • The number of critical bytes

Optimizing the DOM

Minify the file

Cache

Compress

Remove

unnecessary

styles

Minify

Cache

Compress

Unblocking

CSS

Optimizing the CSSOM

Unblocking CSS

why wait on styles you don`t need?

<link href="print.css" rel="stylesheet" media="print">
<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Demos</title>
    <link rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/y6/l/1,cross/9Ia-Y9BtgQu.css">
</head>
<body>
    Hello
</body>
</html>

Demo

First Paint

First Paint

How do I load styles that I need but don't matter?

<link href="print.css" rel="stylesheet" media="print" onload="this.media='all'">
<link rel="preload" href="style.css" as="style" onload="this.rel='stylesheet'">
<link rel="alternate stylesheet" href="style.css" onload="this.rel='stylesheet'">

What is best practice?

Put CSS in the document head

Let the browser load resources as early as possible

Avoid CSS imports

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Demos</title>
    <link rel="stylesheet" href="http://127.0.0.1:8887/style.css">
    <link rel="stylesheet" href="https://lib.baomitu.com/CSS-Mint/2.0.6/css-mint.min.css">
</head>
<body>
    <div class="cm-alert">Default alert</div>
</body>
</html>

First Paint

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Demos</title>
    <link rel="stylesheet" href="http://127.0.0.1:8887/style.css">
</head>
<body>
    <div class="cm-alert">Default alert</div>
</body>
</html>

// style.css

@import url('https://lib.baomitu.com/CSS-Mint/2.0.6/css-mint.min.css');
body{background:red;}

First Paint

Optimizing the JavaScript

asynchronous JavaScript resources

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Demos</title>
    <link rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/y6/l/1,cross/9Ia-Y9BtgQu.css">
</head>
<body>
    <p class='_159h'>aa</p>
    <script async src="http://qiniu.bkt.demos.so/static/js/app.53df42d5b7a0dbf52386.js"></script>
</body>
</html>
<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Demos</title>
    <link rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/y6/l/1,cross/9Ia-Y9BtgQu.css">
</head>
<body>
    <p class='_159h'>aa</p>
    <script src="http://qiniu.bkt.demos.so/static/js/app.53df42d5b7a0dbf52386.js"></script>
</body>
</html>

RAIL

a user-centric performance model

Response
Animation
Idle
Load

Perception

how users perceive performance delays

16ms

Users perceive animations as smooth so long as 60 new frames are rendered every second.

100ms

Users feel like the result is immediate.

1s

Users lose focus on the task they are performing.

10s

users are frustrated and are likely to abandon tasks.

Any longer, and the connection between action and reaction is broken.

RESPONSE

100ms

50ms

ANIMATION

16ms

10ms

IDLE

50ms

LOAD

1s

100ms

16ms

50ms

1s

RESPONSE

ANIMATION

IDLE

LOAD

JavaScript

Optimizing JavaScript Execution

The pixel pipeline

60fps and Device Refresh Rates

1000/60 = 16.666666...

ANIMATION:

16ms

10ms

Produced by OmniGraffle 7.9.3 2018-12-18 07:05:28 +0000 版面 1 图层 1 Composite 向右三角形 Paint 向右三角形 向右三角形 Layout 向右三角形 向右三角形 Style 向右三角形 向右三角形 JavaAcript Solid Line Solid Line Start End Must be less than 16 ms <=10ms

Miss a frame

16ms16msTimer FiredRe…Composite LayerssetInterval Fired16ms

We can do better...

requestAnimationFrame(
  slideAnimation
)

LongTask

recalculate style

Layout

UI Event

Everything...

>50ms

We can do better...

Web Worker

and

Time Slicing

Web Worker

const testWorker = new Worker('./worker.js')
setTimeout(_ => {
  testWorker.postMessage({})
  testWorker.onmessage = function (ev) {
    console.log(ev.data)
  }
}, 5000)

// worker.js
self.onmessage = function () {
  const start = performance.now()
  while (performance.now() - start < 1000) {}
  postMessage('done!')
}

Before

After

Time Slicing

Layout

UI Event

recalculate style

Everything...

function block () {
  ts(function* () {
    const start = performance.now()
    while (performance.now() - start < 1000) {
      console.log(11)
      yield
    }
    console.log('done!')
  })
}

setTimeout(block, 5000)

function ts (gen) {
  if (typeof gen === 'function') gen = gen()
  if (!gen || typeof gen.next !== 'function') return

  (function next () {
    const res = gen.next()
    if (res.done) return
    setTimeout(next)
  })()
}

Style & Layout

Optimizing Recalculate Style and Layout

The Cost of Styles Changes

Selector Matching

1

2

.box:nth-child(3)

.box--three

Roughly 50% of the time used to calculate the computed style for an element is used to match selectors

Optimizing Recalculate Style

  • Reduce the complexity of your selectors
  • Reduce the number of elements on which style calculation must be calculated

Optimizing Layout

Avoid Forced Synchronous Layouts

What is FSL

// Set the width.
el.style.width = '100px';

// Then ask for it.
const width = el.offsetWidth;
// Get the last known width.
const width = el.offsetWidth;

// Then update it.
el.style.width = '100px';
const container = document.querySelector('.container');
const boxes = document.querySelectorAll('p');

for (var i = 0; i < boxes.length; i++) {
    // Read a layout property
    const newWidth = container.offsetWidth;
    
    // Then invalidate layouts with writes.
    boxes[i].style.width = newWidth + 'px';
}
const container = document.querySelector('.container');
const boxes = document.querySelectorAll('p');

// Read a layout property
const newWidth = container.offsetWidth;

for (var i = 0; i < boxes.length; i++) {    
    // Then invalidate layouts with writes.
    boxes[i].style.width = newWidth + 'px';
}

Avoid layout thrashing

Paint & Composite

how to reduce the paint area?

will-change

or

transform: translateZ(0);

* {

    will-change: left;

    transform: translateZ(0);

}

Why?

Thank you!

Q & A

Copy of Silky smooth web page

By 刘博文

Copy of Silky smooth web page

  • 1,337