CSS and the First Meaningful Paint - All day Hey!, April 2017

CSS and the First Meaningful Paint - All day Hey!, April 2017

To render a webpage browsers needs to go through the complex dance of networking, parsing and painting before any content can be displayed to your user. Over the years, we've developed mechanisms and hacks to aid the browser at each stage of this process, but these have always come at some cost or trade-off.

How can we utilize modern web platform features to load our CSS as fast as possible? Should we still be inlining our critical content into the document or instead, how can HTTP/2 server push and Service Workers help us?

In this talk we will take a journey exploring the current, past, and future best-practices for loading CSS in the browser and how we can achieve a first meaningful paint within 1000ms. Ultimately creating a faster, more resilient experience for our users.

276c149f793de9af4e98991ed52ff874?s=128

Patrick Hamann

April 24, 2017
Tweet

Transcript

  1. 1.

    Name of Presentation CSS and the: First meaningful paint All

    Day Hey, April 2017
 Patrick Hamann @patrickhamann
  2. 2.
  3. 7.

    CSS and the first meaningful paint @patrickhamann How can we

    measure the perception and experience of our real users?
  4. 8.

    CSS and the first meaningful paint • First byte •

    Document complete • Load event • Requests • Start render • SpeedIndex • First meaningful paint • Interactivity • Custom… Old New
  5. 10.

    CSS and the first meaningful paint @patrickhamann First Meaningful Paint

    is the time when a page’s primary content appeared on the screen.
  6. 11.

    CSS and the first meaningful paint @patrickhamann First Meaningful Paint

    is the first paint after which the biggest above-the-fold layout change has happened, and web fonts have loaded.
  7. 19.
  8. 21.

    CSS and the first meaningful paint @patrickhamann • Where are

    your users based? • What is your device landscape? • In what context are they using your site? • What is their network profile? • What did they come for? What is your average user profile?
  9. 22.

    CSS and the first meaningful paint @patrickhamann The average load

    time for mobile sites is 19 seconds over 3G connections The need for mobile speed, Google DoubleClick
  10. 23.

    CSS and the first meaningful paint @patrickhamann 53% of mobile

    site visits are abandoned if pages takes longer than 3 seconds to load. The need for mobile speed, Google DoubleClick
  11. 24.
  12. 25.

    CSS and the first meaningful paint @patrickhamann Forming a TTFMP

    baseline: 3G EM 3G Cable 3 secs 2 secs 1 secs Time to First Meaningful Paint: 3G EM 3G Cable ? ? ? Insert your custom profiles here:
  13. 26.

    CSS and the first meaningful paint @patrickhamann Case-study profile: BW

    down BW up Latency RTT 3G EM 400 kbs 400 kbs 400 ms 3G 1.6 Mbs 768 kbs 150 ms Cable 5m Mbs 1Mbs 28 ms • Moto G (low-mid Android) • 9 runs • Chrome beta
  14. 28.

    CSS and the first meaningful paint @patrickhamann 1 <!DOCTYPE html>

    2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>FT.com</title> 6 7 <link rel="stylesheet" href="main.css" /> 8 9 Other head elements... 10 11 </head> 12 <body> 13 14 Content ... 15 16 </body> 17 </html>
  15. 30.

    Name of Presentation Baseline results TTFMP (ms) 0 1000 2000

    3000 4000 5000 6000 7000 8000 9000 10000 Baseline 3G EM 3G Cable TTFMP % impovement 3G EM 3259 63 3G 1462 63 Cable 1327 46
  16. 32.

    CSS and the first meaningful paint @patrickhamann Request page Network

    Renderer GET html Build DOM response Build CSSOM Render page GET css GET js response response idle idle Render blocking Run JS Async
  17. 33.

    CSS and the first meaningful paint @patrickhamann Request page Network

    Renderer GET html Build DOM response Build CSSOM Render page GET css GET js response response idle idle Render blocking Run JS Async
  18. 34.

    CSS and the first meaningful paint @patrickhamann Request page Network

    Renderer GET html Build DOM response Build CSSOM Render page GET css GET js response response idle idle Render blocking Run JS Async GET css response
  19. 35.

    CSS and the first meaningful paint @patrickhamann Request page Network

    Renderer GET html Build DOM response Build CSSOM Render page GET css response idle Async Render
  20. 36.
  21. 37.

    ! !

  22. 38.

    ç https://github.com/filamentgroup/loadCSS 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head>

    4 <meta charset="UTF-8"> 5 <title>FT.com</title> 6 7 <style> 8 html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}a{background-color:tran 9 10 Critical styles ... 11 </style> 12 13 <link rel="preload" href="main.css" as="style" onload="this.rel='stylesheet'"> 14 <noscript><link rel="stylesheet" href="main.css"></noscript> 15 <script> 16 /*! loadCSS. [c]2017 Filament Group, Inc. MIT License */ 17 (function(){ ... }()); 18 </script> 19 20 Other head elements... 21 22 </head> 23 <body> 24
  23. 40.
  24. 41.
  25. 42.
  26. 43.

    Name of Presentation Inline critical CSS results TTFMP (ms) 0

    1000 2000 3000 4000 5000 6000 7000 8000 9000 10000 Baseline Inline 3G EM 3G Cable % Improvement 0 10 20 30 40 50 60 70 80 90 100 TTFMP % impovement 3G EM 3259 63 3G 1462 63 Cable 1327 46
  27. 44.

    CSS and the first meaningful paint • No blocking resources

    • No SPOF on CSS • Less requests over wire • Instant painting • Causes reflow • Not cachable • Hard to maintain • Hard to automate Pros Cons
  28. 50.
  29. 51.
  30. 52.

    CSS and the first meaningful paint @patrickhamann Network JavaScript Render

    tree Layout Paint HTML DOM CSS CSSOM Network JavaScript Render tree Layout Paint HTML DOM CSS CSSOM
  31. 53.

    CSS and the first meaningful paint @patrickhamann Network JavaScript Render

    tree Layout Paint HTML CSS CSSOM Network JavaScript Render tree Layout Paint HTML DOM CSS CSSOM
  32. 54.

    CSS and the first meaningful paint @patrickhamann Network JavaScript Render

    tree Layout Paint HTML CSS CSSOM Network JavaScript Render tree Layout Paint HTML DOM CSS CSSOM
  33. 55.

    CSS and the first meaningful paint @patrickhamann Network JavaScript Render

    tree Layout Paint CSS CSSOM Network JavaScript Render tree Layout Paint HTML DOM CSS CSSOM
  34. 56.

    CSS and the first meaningful paint @patrickhamann JavaScript Render tree

    Layout Paint CSSOM Network JavaScript Render tree Layout Paint HTML DOM CSS CSSOM
  35. 57.

    CSS and the first meaningful paint @patrickhamann Render tree Layout

    Paint Network JavaScript Render tree Layout Paint HTML DOM CSS CSSOM
  36. 61.

    CSS and the first meaningful paint @patrickhamann Provides a declarative

    fetch primitive that initiates an early fetch and separates fetching from resource execution.
  37. 62.

    CSS and the first meaningful paint @patrickhamann 1 <!-- preload

    stylesheet resource via declarative markup --> 2 <link rel="preload" href="/styles/other.css" as="style"> 3 4 <!-- or, preload stylesheet resource via JavaScript --> 5 <script> 6 var res = document.createElement("link"); 7 res.rel = "preload"; 8 res.as = "style"; 9 res.href = "styles/other.css"; 10 document.head.appendChild(res); 11 </script> 1 Link: </styles/other.css> rel=“preload”; as=“style” nopush Preload with markup: Preload with HTTP header:
  38. 63.

    CSS and the first meaningful paint @patrickhamann < GET /index.html


    
 < HTTP/1.1 200 OK < Cache-Control: private, max-age=60, must-revalidate < Expires: Thu, 20 Apr 2017 21:39:52 GMT < Last-Modified: Thu, 20 Apr 2017 13:11:33 GMT < ETag: "966eca3815d88d8848933d33c68ab2bd" < Content-Type: text/html < Content-Encoding: gzip < Content-Length: 43177 < Date: Thu, 20 Apr 2017 21:39:52 GMT < Connection: keep-alive < Link: <main.css>; as=style; rel=preload; nopush, 
 <MetricWeb-Regular.woff>; rel=preload as=font crossorigin nopush, <MetricWeb-Semibold.woff>; rel=preload as=font crossorigin nopush, <ftlogo.svg>; as=image; rel=preload; nopush
  39. 64.
  40. 65.
  41. 66.
  42. 68.

    Name of Presentation Preload results TTFMP (ms) 0 1000 2000

    3000 4000 5000 6000 7000 8000 9000 10000 Baseline Inline Preload 3G EM 3G Cable % Improvement 0 10 20 30 40 50 60 70 80 90 100 TTFMP % impovement 3G EM 3176 64 3G 1778 55 Cable 1042 57
  43. 69.

    CSS and the first meaningful paint • Indicate hidden resources

    • Dictate priority and order • Separates fetch from exec • Easy to create contention • Requires server logic Pros Cons
  44. 74.

    CSS and the first meaningful paint @patrickhamann " # Client

    Server GET /index.html 200 OK /index.html
  45. 75.

    CSS and the first meaningful paint @patrickhamann " # Client

    Server GET /index.html GET /main.css 200 OK /index.html
  46. 78.

    CSS and the first meaningful paint @patrickhamann " # Client

    Server PUSH_PROMISE /main.css GET /index.html
  47. 79.

    CSS and the first meaningful paint @patrickhamann " # Client

    Server PUSH_PROMISE /main.css 200 OK /index.html GET /index.html
  48. 80.

    CSS and the first meaningful paint @patrickhamann 1 <!DOCTYPE html>

    2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>FT.com</title> 6 7 <link rel="stylesheet" href="critical.css" /> 8 <link rel="preload" href="main.css" as="style" onload=“this.rel='stylesheet'" /> 9 ... 10 1 Link: <critical.css>; rel=“preload”; as=“style” Indicate push of critical styles with Link preload header: Convert inline styles into normal link rel=“stylesheet” declaration and async the main styles
  49. 83.

    CSS and the first meaningful paint @patrickhamann /hero.jpg Stream ID:

    4 Weight: 16 /data.json Stream ID: 7 Weight: 16 /app.js Stream ID: 3 Weight: 64 /icon.svg Stream ID: 9 Weight: 16 /main.css Stream ID: 2 Weight: 110 /index.html Stream ID: 1 Weight: 128
  50. 85.
  51. 86.
  52. 88.

    Name of Presentation Push results TTFMP (ms) 0 1000 2000

    3000 4000 5000 6000 7000 8000 9000 10000 Baseline Inline Preload Push 1256 1042 1327 2477 2826 1778 1462 3983 5035 3176 3259 8849 3G EM 3G Cable % Improvement 0 10 20 30 40 50 60 70 80 90 100 TTFMP % impovement 3G EM 5035 43 3G 2826 29 Cable 1256 49
  53. 89.

    CSS and the first meaningful paint • Easy to configure

    • Creates contention • Requires server logic • Hard to debug • Not cache aware Pros Cons
  54. 94.

    CSS and the first meaningful paint @patrickhamann " # Client

    Server HTTP/2 connection GET /index.html
  55. 95.

    CSS and the first meaningful paint @patrickhamann " # Client

    Server PUSH_PROMISE /main.css $ HTTP/2 connection GET /index.html
  56. 96.

    CSS and the first meaningful paint @patrickhamann " # Client

    Server PUSH_PROMISE /main.css 200 OK /index.html HTTP/2 connection GET /index.html
  57. 98.

    CSS and the first meaningful paint @patrickhamann " # Client

    Server GET /index.html " GET /index.html App
  58. 99.

    CSS and the first meaningful paint @patrickhamann " # Client

    Server PUSH_PROMISE /main.css - GET /index.html " GET /index.html App
  59. 100.

    CSS and the first meaningful paint @patrickhamann " # Client

    Server PUSH_PROMISE /main.css - $ GET /index.html " GET /index.html App
  60. 101.

    CSS and the first meaningful paint @patrickhamann " # Client

    Server PUSH_PROMISE /main.css - $ 200 OK /index.html GET /index.html " GET /index.html 200 OK /index.html App
  61. 102.

    CSS and the first meaningful paint @patrickhamann 1 const http2

    = require('http2'); 2 3 function handler(request, response) { 4 if (request.url === "/index.html") { 5 const push = response.push('/critical.css'); 6 push.writeHead(200); 7 fs.createReadStream('/critical.css').pipe(push); 8 } 9 10 // Generate index response: 11 // - Fetch data from DB 12 // - Render template 13 // etc ... 14 15 response.end(data); 16 } 17 18 const server = http2.createServer(opts, handler); 19 server.listen(80);
  62. 103.
  63. 104.
  64. 105.

    Name of Presentation Push async results TTFMP (ms) 0 1000

    2000 3000 4000 5000 6000 7000 8000 9000 10000 Baseline Inline Preload Push Push async 3G EM 3G Cable % Improvement 0 10 20 30 40 50 60 70 80 90 100 TTFMP % impovement 3G EM 3062 65 3G 1613 59 Cable 1021 58
  65. 106.

    CSS and the first meaningful paint • Uses idle time

    • Ensures delivery before preload • Limited avaliablity • Custom server logic • Hard to debug Pros Cons
  66. 109.
  67. 110.
  68. 111.
  69. 112.
  70. 122.

    CSS and the first meaningful paint @patrickhamann Use preload to

    indicate critical resources, such as fonts to the browser.
  71. 123.

    CSS and the first meaningful paint @patrickhamann Push critical CSS,

    but only on first view and only within idle time.