Upload
jan-willem-maessen
View
104
Download
0
Tags:
Embed Size (px)
DESCRIPTION
Talk from Velocity NY, Oct 2013. Inlining critical CSS speeds web page first render times markedly, especially on mobile devices. In this talk I discuss how to do this on your site, and how to employ the related technique of prioritizing the above the fold images on your page.
Citation preview
WebRTC
Jan-Willem MaessenPageSpeed Optimization [email protected]
Prioritize Your Critical CSS and Imagesto render your site fast
Prioritizing Critical CSS and Images Makes Render Fast
jmaessen@google
Inline critical CSS in <head>
Inline low res visible images
Lazy load everything else
jmaessen@google
Users Expect SpeedDelay User reaction
0 - 100 ms Instant
100 - 300 ms Slight perceptible delay
300 - 1000 ms Task focus, perceptible delay
1 s+ Mental context switch
10 s+ I'll come back later...
Our pages should render in 1000 ms or less
Website Abandonment (Strangeloop) Ilya Grigorik (Go to his talk)
BUT
jmaessen@google
Mobile web performance is crippled by network latencyWe need to build fast pages for today’s devices
jmaessen@google
Network Performance Varies Even in the Lab
jmaessen@google
Resource request (second host)
Time(200 ms RTT)
Total data (KB)
DNS lookup 800 ms –
TCP Connection 1000 ms –
First 10 packets (15K) 1200 ms 14K
Next 20 packets (29K) 1400 ms 44K
Next 40 packets (44K) 1600 ms 88K
Optimistic But Useful Model of HTTP Connection
Actually, all these numbers exceed the 384Kbit/s (48K/s) bandwidth of old 3G networks.
What is Happening Time(200 ms RTT)
Total data (KB)
Control plane (200-2500 ms) –
DNS lookup 200 ms –
TCP Connection 400 ms –
First 10 packets (15K) 600 ms 14K
Next 20 packets (29K) 800 ms 44K
Next 40 packets (44K) 1000 ms 88K
Resource request (original host)
Time(200 ms RTT)
Total data (KB)
TCP Connection 800 ms –
First 10 packets (15K) 1000 ms 14K
Next 20 packets (29K) 1200 ms 44K
Next 40 packets (44K) 1400 ms 88K
If your site is reached via a mobile redirect, you’re already down here.
jmaessen@google
@igrigorik
1. One RTT render for above the fold!2. No redirects + fast server response (<200 ms)3. Must optimize critical rendering path
a. Inline critical CSSb. Remove blocking JavaScriptc. Prioritize above-the-fold images
We don't need to render the entire page...
We need to render above the fold content!
What CSS will affect the above the fold HTML?What HTML will be above the fold after styling?How large is each above the fold image?Will JavaScript affect the content of the DOM?
Why can’t the browser do this?
jmaessen@google
Let's look at that simple example...
<!doctype html>
<html>
<head>
<title>prioritize_critical_css example</title>
<link rel="stylesheet" href="styles/blue.css">
<link rel="stylesheet" href="styles/big.css">
<style>
@import url(styles/all_using_imports.css);
</style>
<link rel="stylesheet" href="
styles/rewrite_css_images.css">
</head>
<body>
<div class="foo" style="display:inline-block;"></div>
<span class="blue big">Prioritize Critical CSS</span>
…<body>
.blue {color: blue;}
prioritize_critical_css.htmlstyles/blue.css
.big { font-size: 8em; }
.very_large_class… { font-size: 8em; }…(lots more unused rules)
styles/big.css
@import url(yellow.css);@import url(blue.css);@import url(bold.css);
styles/all_using_imports.css
.foo { background-image: url(../images/BikeCrashIcn.png); width: 100px; height: 100px;}
styles/rewrite_css_images.css
jmaessen@google
What happens when the browser loads our page
<!doctype html>
<html>
<head>
<title>prioritize_critical_css example</title>
<link rel="stylesheet" href="styles/blue.css">
<link rel="stylesheet" href="styles/big.css">
<style>
@import url(styles/all_using_imports.css);
</style>
<link rel="stylesheet" href="
styles/rewrite_css_images.css">
</head>
<body>
<div class="foo" style="display:inline-block;"></div>
<span class="blue big">Prioritize Critical CSS</span>
…<body>
prioritize_critical_css.htmlstyles/blue.css
styles/big.css
@import url(yellow.css);@import url(blue.css);@import url(bold.css);
styles/all_using_imports.css
.foo { background-image: url(../images/BikeCrashIcn.png); width: 100px; height: 100px;}
styles/rewrite_css_images.css
First render: 1.8s
jmaessen@google
Inline the CSS that is actually used on the page
<!doctype html>
<html>
<head>
<title>prioritize_critical_css example</title>
<style>.blue{color:blue}</style>
<style>.big{font-size:8em}</style>
<style>.blue{color:blue}.bold{font-weight:bold}</style>
<style>.foo{background-image:url(images/BikeCrashIcn.png);
width:100px;height:100px}</style>
</head>
<body>
<div class="foo" style="display:inline-block;"></div>
<span class="blue big">Prioritize Critical CSS</span>
…<body>
prioritize_critical_css.html
First render: 0.7s
jmaessen@google
● Around 40% of the CSS rules are used in a typical page
● Tweaking a PHP script to inline all the CSS should be easy
● Warning: 44K of compressed CSS on typical page
As always, test and measure – do what the data tells you for your site.
Simplest Option: Just Inline All the CSS
HTTP Archive data on CSS sizes jmaessen@google
@igrigorik
Identify critical CSS via an Audit (Manual)
DevTools > Audits > Web Page Performance
Inline the critical styles...
Let PageSpeed Find Critical CSS Automatically
ModPagespeedEnableFilters prioritize_critical_css # Apache
pagespeed EnableFilters prioritize_critical_css; # Nginx
PageSpeedServer
Client Browser
InstrumentedPage
Beacon result:List of critical selectors
Downside: first access to the page won’t be optimized.Upside: will be based on actual client browser behavior
jmaessen@google
Option 1: Include them in your critical CSS● Careful: they may not necessarily show up in an audit!
Option 2: Lazyload them● Load before we run the relevant JavaScript● Lazyload also works for non-screen styles (eg print)
Rules That Are Triggered by JavaScript Actions
jmaessen@google
How Not to Lazy Load CSS
<!doctype html>
<html>
<head>
<title>prioritize_critical_css example</title>
…
</head>
<body>
<div class="foo" style="display:inline-block;"></div>
<span class="blue big">Prioritize Critical CSS</span>
…
<link rel="stylesheet" href="styles/blue.css">
<link rel="stylesheet" href="styles/big.css">
<link rel="stylesheet" href="styles/all_using_imports.css">
<link rel="stylesheet" href="styles/rewrite_css_images.css" media="all">
</body>
</html>
prioritize_critical_css.html
The browser will notice the stylesheets when it reaches the bottom of the page and block rendering –
It can’t tell that none of the rules will apply to the page.
jmaessen@google
How PageSpeed Optimization Library Lazy Loads CSS
<!doctype html>
<html>
<head>
<title>prioritize_critical_css example</title>
…
</head>
<body>
<div class="foo" style="display:inline-block;"></div>
<span class="blue big">Prioritize Critical CSS</span>
…
<noscript class="psa_add_styles">
<link rel="stylesheet" href="styles/blue.css">
<link rel="stylesheet" href="styles/big.css">
<link rel="stylesheet" href="styles/all_using_imports.css">
<link rel="stylesheet" href="styles/rewrite_css_images.css" media="all">
</noscript>
<script>...Move <noscript> to a div...</script>
</body>
</html>
prioritize_critical_css.html
The noscript block keeps the browser from downloading the CSS until the script runs.
This blocks rendering when JS is switched off
But the page continues to work correctly
You can skip this for non-screen media= attributes.
jmaessen@google
Another very simple example...
<!doctype html>
<html><head>...</head>
<body>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<img src="images/BikeCrashIcn.png"><br/>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<img src="images/BikeCrashIcn.png"><br/>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<img src="images/BikeCrashIcn.png"><br/>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<img src="images/BikeCrashIcn.png"><br/>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<img src="images/BikeCrashIcn.png"><br/>
<p>*</p> <p>*</p>
<p>Should be below the fold...</p>
<p>*</p> <p>*</p>
<img src="images/Puzzle.jpg"><br/>
<img src="images/IronChef2.gif"><br/>
<img src="images/Cuppa.png"><br/>
</body> </html>
lazyload_images.html
images/BikeCrashIcn.png
images/Puzzle.jpg
images/IronChef2.gif
images/Cuppa.png
jmaessen@google
Lazyloading All the Images
<!doctype html>
<html><head>...</head>
<body>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<script>...lazyload code...</script>
<img lazy_src="images/BikeCrashIcn.png" width="100" height="100"><br/>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<img lazy_src="images/BikeCrashIcn.png" width="100" height="100"><br/>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<img lazy_src="images/BikeCrashIcn.png" width="100" height="100"><br/>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<img lazy_src="images/BikeCrashIcn.png" width="100" height="100"><br/>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<img lazy_src="images/BikeCrashIcn.png" width="100" height="100"><br/>
<p>*</p> <p>*</p>
<p>Should be below the fold...</p>
<p>*</p> <p>*</p>
<img lazy_src="images/Puzzle.jpg" width="1023" height="766"><br/>
<img lazy_src="images/IronChef2.gif" width="192" height="256"><br/>
<img lazy_src="images/Cuppa.png" width="65" height="70"><br/>
lazyload_images.html
jmaessen@google
Without image dimensions (left), page reflows on image load
Include Dimensions with Lazy Loaded Images
jmaessen@google
Don’t Lazy Load Images Above the Fold!
<!doctype html>
<html><head>...</head>
<body>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<img src="images/BikeCrashIcn.png" width="100" height="100"><br/>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<img src="images/BikeCrashIcn.png" width="100" height="100"><br/>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<img src="images/BikeCrashIcn.png" width="100" height="100"><br/>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<img src="images/BikeCrashIcn.png" width="100" height="100"><br/>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<img src="images/BikeCrashIcn.png" width="100" height="100"><br/>
<p>*</p> <p>*</p>
<p>Should be below the fold...</p>
<p>*</p> <p>*</p>
<script>...lazyload code...</script>
<img lazy_src="images/Puzzle.jpg" width="1023" height="766"><br/>
<img lazy_src="images/IronChef2.gif" width="192" height="256"><br/>
<img lazy_src="images/Cuppa.png" width="65" height="70"><br/>
lazyload_images.html
Remember: We’re trying to get the browser to fetch the visible page content first!
jmaessen@google
Low-Quality Inline Images Above the Fold + Lazy Load
<!doctype html>
<html><head>...</head>
<body>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<img lazy_src="images/BikeCrashIcn.png" src="data:image/jpg;..." width="100" height="100"><br/>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<img lazy_src="images/BikeCrashIcn.png" src="data:image/jpg;..." width="100" height="100"><br/>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<img lazy_src="images/BikeCrashIcn.png" src="data:image/jpg;..." width="100" height="100"><br/>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<img lazy_src="images/BikeCrashIcn.png" src="data:image/jpg;..." width="100" height="100"><br/>
<p>*</p> <p>*</p> <p>*</p> <p>*</p> <p>*</p>
<img lazy_src="images/BikeCrashIcn.png" src="data:image/jpg;..." width="100" height="100"><br/>
<p>*</p> <p>*</p>
<p>Should be below the fold...</p>
<p>*</p> <p>*</p>
<script>...lazyload code...</script>
<img lazy_src="images/Puzzle.jpg" width="1023" height="766"><br/>
<img lazy_src="images/IronChef2.gif" width="192" height="256"><br/>
<img lazy_src="images/Cuppa.png" width="65" height="70"><br/>
lazyload_images.html
jmaessen@google
Effect of our Optimizations: Visual Completeness
Before: 6.4s
With lazy load: 4.7s
Note: Mobile devices should load all images by OnLoad to avoid radio restart.
jmaessen@google
Let PageSpeed Find Above the Fold Images ModPagespeedEnableFilters lazyload_images,insert_image_dimensions ModPagespeedEnableFilters resize_mobile_images # Apache
pagespeed EnableFilters lazyload_images,insert_image_dimensions; pagespeed EnableFilters resize_mobile_images; # Nginx
PageSpeedServer
Client Browser
InstrumentedPage
Beacon result:List of visible images
Clients vote on what images are visible above the fold
jmaessen@google
Lazy load your images
Use low-quality inline placeholder images above the fold
Load all images before radio offjmaessen@google
Page Reflows due to JavaScript are a problemStatically sizing dynamically loaded areas eliminates page jankConsider loading JS that affects the page earlierBut use asynchronous techniques (eg async ads load)
A Note About JavaScript
jmaessen@google
Critical CSS (inlined)Above the fold HTML with inline image previewsBelow the fold HTML with image dimensionsAbove the fold imagesBelow the fold imagesNon-critical CSSJavaScript*
Ideal Page Load Order
jmaessen@google
In parallel
What This Looks Like on a Real Site
jmaessen@google
4.4s: Unopt first render
1.8-1.9s: First Render
2.2s: Low Res Banner
2.4s: Full Res Banner
3.7s: Dynamic Image
http://www.radiocity.com/tickets.html
Inline critical CSS in <head>
Inline low res visible images
Lazy load everything else
jmaessen@google
email [email protected] mod_pagespeed http://www.modpagespeed.com nginx_pagespeed http://ngxpagespeed.comPageSpeed Service https://developers.google.com/speed/pagespeed/service
Thank you!Slides @