Upgrade to Pro — share decks privately, control downloads, hide ads and more …

CSS and the First Meaningful Paint - CSS Conf EU, May 2017

CSS and the First Meaningful Paint - CSS Conf EU, May 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.

Patrick Hamann

May 06, 2017
Tweet

More Decks by Patrick Hamann

Other Decks in Technology

Transcript

  1. CSS and the: First meaningful paint CSS Conf EU, May

    2017 Patrick Hamann @patrickhamann
  2. CSS and the first meaningful paint • First byte •

    Document complete • Load event • Requests / bytes • Start render • SpeedIndex • First meaningful paint • Time to Interactivity • Custom… Old New
  3. CSS and the first meaningful paint @patrickhamann First Meaningful Paint

    is the time when a page’s primary content appeared on the screen.
  4. 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.
  5. CSS and the first meaningful paint @patrickhamann • Where are

    your users based? • What is their 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?
  6. 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:
  7. 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>
  8. Name of Presentation Baseline results TTFMP (ms) 0 1000 2000

    3000 4000 5000 6000 7000 8000 9000 10000 Baseline 3G EM 3G Cable
  9. 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 JS
  10. 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 JS
  11. 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 JS GET css response
  12. 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 CSS Render
  13. ç 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
  14. 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
  15. CSS and the first meaningful paint • No blocking resources

    • No SPOF on CSS • Eliminates critical request • Instant painting • Causes reflow • Not cachable • Hard to maintain • Hard to automate Pros Cons
  16. CSS and the first meaningful paint @patrickhamann Request page Network

    Renderer GET html Build DOM response Build CSSOM First paint GET css response idle idle Render blocking Render tree
  17. CSS and the first meaningful paint @patrickhamann Request page Network

    Renderer GET html Build DOM response Build CSSOM First paint GET css response idle idle Render blocking GET font response Text paint Text blocking Render tree
  18. CSS and the first meaningful paint @patrickhamann Request page Network

    Renderer GET html Build DOM response Build CSSOM First paint GET css response idle idle Render blocking GET font response Text paint Text blocking Render tree
  19. CSS and the first meaningful paint @patrickhamann Provides a declarative

    fetch primitive that initiates an early fetch and separates fetching from resource execution.
  20. 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:
  21. 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
  22. 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
  23. 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
  24. CSS and the first meaningful paint @patrickhamann ! " Client

    Server GET /index.html GET /main.css 200 OK /index.html #
  25. CSS and the first meaningful paint @patrickhamann ! " Client

    Server PUSH_PROMISE /main.css 200 OK /index.html GET /index.html
  26. 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
  27. 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
  28. 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
  29. 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
  30. 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);
  31. 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
  32. CSS and the first meaningful paint • Uses idle time

    • Ensures delivery before preload • Easy to create contention • Limited avaliablity • Custom server logic • Hard to debug Pros Cons
  33. CSS and the first meaningful paint @patrickhamann Use preload to

    indicate critical resources, such as fonts to the browser.
  34. CSS and the first meaningful paint @patrickhamann Push critical CSS,

    but only on first view and only within idle time.