Slide 1
THE
BIG PICTURE
TIM KADLEC
@TKADLEC
Slide 2
Slide 3
Slide 4
Slide 5
Slide 6
Slide 7
Slide 8
Slide 9
Slide 10
How quickly does the most important content get displayed on the screen?
Slide 11
Largest Contentful Paint (LCP) How long until the largest piece of content is displayed on the screen.
Slide 12
Slide 13
What counts as “content”? <img> - <image> inside svg - post images of <video> elements - background images - block-level text (h1, h2, p, etc) -
Slide 14
LCP Types 18% 27%
46%
Mobile
51%
Desktop 31%
27% Text
Background Image
Image
Slide 15
73% 82% on mobile
on desktop
Slide 16
LCP at 75th percentile
2.573s 2.861s 3.071s text
image
background image
Slide 17
LCP at 75th percentile
2.861s 3.071s image
background image
Slide 18
LCP at 75th percentile
2.861s 3.071s image
background image
Slide 19
Slide 20
Slide 21
Slide 22
Network
HTML JS
DOM
CSS
CSSOM
Render Tree
Layout
Paint
Slide 23
Network
HTML JS
DOM
CSS
CSSOM
Render Tree
Layout
Paint
Slide 24
Network
HTML JS
DOM
CSS
The browser doesn’t know the image exists until the CSS is downloaded and parsed…
CSSOM
Render Tree
Layout
Paint
Slide 25
Network
HTML JS
DOM
CSS
…and it won’t request it until it knows it needs to be displayed.
CSSOM
Render Tree
Layout
Paint
Slide 26
<link rel=”preload” href=”https://ethicaltraveler.org/ wp-content/themes/et2015/static/images/hero_masthead.jpg” as=”image”/>
Slide 27
Slide 28
Slide 29
Slide 30
Preload helps with discovery, but doesn’t impact priority
Slide 31
Network
HTML JS
DOM
CSS
CSSOM
Render Tree
Layout
Paint
Slide 32
Network
HTML JS
DOM
CSS
The browser can find <img> elements pretty early….
CSSOM
Render Tree
Layout
Paint
Slide 33
Network
HTML JS
DOM
CSS
CSSOM
Render Tree
Layout
Paint
…but it doesn’t want those images to delay the more important CSS and JS.
Slide 34
Document: High Scripts: High CSS: High Images: Low Fonts: Medium
Slide 35
Document: Highest Scripts: Normal CSS: Normal Images: Low Fonts: High
Slide 36
Document: Highest Scripts: Low-High CSS: Highest Images: Low-High Fonts: High-Highest
Slide 37
Slide 38
<head> <link rel=”preload” href=”https://ethicaltraveler.org/ wp-content/themes/et2015/static/images/hero_masthead.jpg” as=”image”/>
Slide 39
Slide 40
Priority Hints to the rescue?
Slide 41
fetchPriority=”high” fetchPriority=”low”
Slide 42
Document: Highest Scripts: Low-High CSS: Highest Images: Low-High Fonts: High-Highest
Slide 43
<link rel=”preload” href=”https://ethicaltraveler.org/ wp-content/themes/et2015/static/images/hero_masthead.jpg” as=”image” fetchpriority=”high”/> </head>
Slide 44
Slide 45
LCP at 75th percentile
2.861s 3.071s image
background
Slide 46
Slide 47
Slide 48
Slide 49
Slide 50
/>
data-tracking-event=”button-click” data-tracking-info=”{“name”:”clickthrough”,”placeme class=”bose-zoom lazyload” data-lazy=”//assets.bose.com/content/dam/Bose_DAM/Web/consumer_electron alt=”Bose Noise Cancelling Headphones 700” data-sizes=”auto” data-zoom-image=”//assets.bose.com/content/dam/Bose_DAM/Web/consumer_el itemprop=”contentURL” data-srcset=”//assets.bose.com/content/dam/Bose_DAM/Web/consumer_electr
Slide 51
Slide 52
Network
HTML JS
DOM
CSS
CSSOM
Render Tree
Layout
Paint
Slide 53
Network
HTML JS
DOM
CSS
CSSOM
Render Tree
Layout
Paint
The browser sees an <img>, but with no src, it has no idea what to request until JS is downloaded, parsed and executed.
Slide 54
Slide 55
From #111 and LCP of ~11.5s
Slide 56
Slide 57
<img src=”hero.jpg” loading=”eager”> <img src=”other.jpg” loading=”lazy”>
Slide 58
Slide 59
Slide 60
Slide 61
Based on viewport & connection
Slide 62
4G, 5 total
3G, 8 total
2G, 21 total
Slide 63
Always bet on the browser
Slide 64
//assets.bose.com/content/dam/…
Slide 65
Slide 66
Slide 67
Slide 68
Slide 69
Slide 70
Slide 71
The browser has to establish a connection to the new domain
Slide 72
fi
https://res.cloudinary.com /webpagetest /image /upload/ f_auto,q_auto,c_ ll,w_640,h_512/Frame_1_1_dqtcfv.png
Slide 73
Get your buzzword bingo cards ready…..
Slide 74
Get your buzzword bingo cards ready…..
Edge Computing
Slide 75
fi
https://blog.webpagetest/org/cloudinary /webpagetest /image /upload/ f_auto,q_auto,c_ ll,w_640,h_512/Frame_1_1_dqtcfv.png
Slide 76
// cloudinary.js export default async function (request) { const url = new URL(request.url); url.pathname = url.pathname.substring(11); // remove /cloudinary url.hostname = “res.cloudinary.com”;
};
const image = await fetch(url.toString(), request); return image;
Slide 77
// cloudinary.js export default async function (request) { url.pathname = url.pathname.substring(11); // remove /cloudinary url.hostname = “res.cloudinary.com”;
};
Slide 78
// cloudinary.js export default async function (request) {
return image;
Slide 79
[[edge_functions]] path = “/cloudinary/*” function = “cloudinary.js”
Slide 80
Slide 81
Slide 82
Largest Contentful Paint t n e m e v o r p m i n a e m s m 8 8 4 ~ of
Slide 83
Slide 84
Slide 85
Slide 86
Lots of bandwidth available
Slide 87
Only a couple requests early
Slide 88
fetchPriority=”high” fetchPriority=”low”
Slide 89
<img src=”/images/wpt_home_featureimg.jpg” width=”1414” height=”843” alt=”screenshot of wpt results page” />
Slide 90
<img src=”/images/wpt_home_featureimg.jpg” width=”1414” height=”843” alt=”screenshot of wpt results page” fetchPriority=”high” />
Slide 91
Slide 92
Slide 93
Slide 94
Slide 95
First Contentful Paint n o i s s e r g e r n a me s m 5 4 1 ~ f o
Slide 96
Slide 97
Slide 98
Slide 99
Slide 100
Slide 101
LCP & Images Checklist ⛔ Avoid background images ✅ If you must, then pair background image + preload ✅ Use fetchpriority sparingly for a little boost in Chrome/Edge ✅ Load your LCP images from your main domain ⛔ Don’t lazy-load your LCP image! ✅ Use loading attribute to replace JS lazy-loading
Slide 102
Slide 103
Largest Contentful Paint (LCP)
Slide 104
Slide 105
Slide 106
A more robust measurement Measure image load even when not the LCP Measure in Firefox & Safari
Slide 107
<img class=”post__figure-image” src=”/cloudinary/image/upload/ f_auto,q_auto,c_fill,w_640,h_512/Frame_1_1_dqtcfv.png” srcset=”…” width=”640” height=”512” sizes=”(min-width: 44em) 40rem, 90vw” />
Slide 108
<img class=”post__figure-image” src=”/cloudinary/image/upload/ f_auto,q_auto,c_fill,w_640,h_512/Frame_1_1_dqtcfv.png” srcset=”…” width=”640” height=”512” sizes=”(min-width: 44em) 40rem, 90vw” elementtiming=”post-hero” />
Slide 109
<img
elementtiming=”post-hero”
Slide 110
let observer = new PerformanceObserver((list) PerformanceObserver => { for (const entry of list.getEntries()){ console.info(entry); } }); observer.observe({type: type: ‘element’, ‘element’ buffered: true}); true
Slide 111
let observer = new PerformanceObserver((list) => {
Slide 112
Slide 113
Slide 114
Measure in Firefox & Safari
Slide 115
Slide 116
<img src=”hero.jpg” onload=”performance.mark(‘hero1’)”> <script>performance.mark(‘hero2’)</script>
Slide 117
<img class=”post__figure-image” src=”/cloudinary/image/upload/ f_auto,q_auto,c_fill,w_640,h_512/Frame_1_1_dqtcfv.png” srcset=”…” width=”640” height=”512” sizes=”(min-width: 44em) 40rem, 90vw” elementtiming=”post-hero” />
Slide 118
<img class=”post__figure-image” src=”/cloudinary/image/upload/ f_auto,q_auto,c_fill,w_640,h_512/Frame_1_1_dqtcfv.png” srcset=”…” width=”640” height=”512” sizes=”(min-width: 44em) 40rem, 90vw” elementtiming=”post-hero” onload=”performance.mark(‘post-hero2’)” /> <script>performance.mark(‘post-hero3’)</script>
Slide 119
1.377s
post-hero3 <script>
1.467s
post-hero2 onload
Slide 120
Slide 121
3.542s
post-hero3 <script>
5.448s
post-hero2 onload
Slide 122
Slide 123
A more robust measurement ✅ Measure image load even when not the LCP ✅ Measure in Firefox & Safari
Slide 124
Slide 125
We’re using metrics supported in two major browsers….
Slide 126
…optimizing for goals (CrUX) based on one browser….
Slide 127
…and measuring with tools that work in one browser.
Slide 128
Meanwhile in Germany….
47.1% 19.1% 12.8% 6.8%
Slide 129
Slide 130
Remember why we’re doing it….
Slide 131
How easy it to use? Does the functionality meet my needs? Does the functionality work? Is the site fast enough? Is the site available?
Slide 132
“When we design and build our websites with the outliers in mind, whether it’s for performance or even user experience, we build an experience that can be easy for all to access and use — and that’s what the web is about, access and information for all.” - Stephanie Stimac, Program Manager for Edge Developer Experiences
Slide 133
Performance is foundational
Slide 134
THANK YOU! TIM KADLEC
@TKADLEC