LCP
Largest Contentful Paint
The render time of the largest content element
visible in the viewport.
First Contentful Paint ~Largest~ Contentful Paint
LCP players
(pre)fetching important assets early
Images - sizing and targeted appropriately
Fonts: progressive loading strategies
JS: enhancing content with little jank
3rd party JS: loading without blocking content
Fetching things sooner…
The many pre's
Preconnect
<link rel="preconnect" href="https://example.com" />
asks the browser to perform a connection to a domain in
advance.
DNS Prefetch
<link rel="dns-prefetch" href="https://example.com" /
>
asks the browser to perform a DNS resolution of a domain in
advance.
Preload
<link rel="preload" href="/scripts.js" as="script" />
tells the browser to download and cache a resource (like a
script or a stylesheet) as soon as possible. It's mandatory.
Potential impact of preloading
Possible "as" values
audio: Audio file, as typically used in <audio>.
document: An HTML document intended to be embedded by a <frame> or
<iframe>.
embed: A resource to be embedded inside an <embed> element.
fetch: Resource to be accessed by a fetch or XHR request, such as an
ArrayBuffer or JSON file.
font: Font file.
image: Image file.
object: A resource to be embedded inside an <object> element.
script: JavaScript file.
style: CSS stylesheet.
track: WebVTT file.
worker: A JavaScript web worker or shared worker.
video: Video file, as typically used in <video>.
Delivering Images
Images generally load unobtrusively
<img src="baseball.jpg" alt="…">
Data URIs: often an antipattern
<img src="data:text/
plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D…">
Aspect Ratio for CLS
Width & height are back!
<img src="baseball.jpg" width="600"
height="350" alt="…">
Don’t just optimize images,
make them responsive
Responsive images
<img src="sml.jpg" srcset=“sml.jpg 300w, lrg.jpg 800w”
sizes=“100vw”>
<picture>
<source srcset="large.png" media="(min-width: 800px)">
<source srcset="medium.jpg" media="(min-width: 400px)">
<img src="small.jpg" alt="…">
</picture>
Sml.jpg is 300px wide, and
The srcset syntax lrg.jpg is 800px wide
<img src="sml.jpg" srcset=“sml.jpg 300w, lrg.jpg 800w”
sizes=“100vw (max-width: 500px), 50vw” alt="…">
The srcset syntax
<img src="sml.jpg" srcset=“sml.jpg 300w, lrg.jpg 800w”
sizes=“100vw (max-width: 500px), 50vw” alt="…">
This image will be 100% viewport width up until 500px
viewport size, then it is 50% viewport width after that.
https://www.filamentgroup.com/lab/sizes-swap/
The Picture element syntax
<picture>
<source srcset="large.png" media="(min-width: 800px)">
<source srcset="medium.jpg" media="(min-width: 400px)">
<img src="small.jpg" alt="…">
</picture>
The rst one of these sources with a matching media query
wins!
If none, just use the img src as-is.
fi
http://usecases.responsiveimages.org/
Also good for image types
<picture>
<source srcset="awesome.webp" type="image/webp">
<img src="cool.jpg" alt="Alt Text!">
</picture>
Also good for image types
<picture>
<source srcset=“awesome.avif" type="image/avif">
<img src="cool.jpg" alt="Alt Text!">
</picture>
Great for art directed imagery
<picture>
<source src="large.jpg"
media="( (min-device-pixel-ratio: 1.5) and (min-width:
20.001em) and (max-width: 35.999em) ) or
( (max-device-pixel-ratio: 1.5) and (min-width:
120.001em) ) or
( (min-device-pixel-ratio: 1.5) and (min-width:
60.001em) )" />
<source src="medium.jpg"
media="( (max-device-pixel-ratio: 1.5) and (min-width:
20.001em) and (max-width: 35.999em) ) or
( (max-device-pixel-ratio: 1.5) and (min-width:
60.001em) ) or
Best bet: use both!
<picture>
<source srcset="small.jpg 400w, medium.jpg 800w"
sizes="(max-width: 400px) 100vw">
<source srcset="medium.jpg 800w, medium.jpg 1200w"
sizes="(max-width: 800px) 50vw">
<img src="large.jpg" alt="…">
</picture>
Loading SVGs
Performantly
External SVG… so many ways
<img src="skate.svg" alt="skateboard icon">
or… <svg width="100" height="100">
<use href="skate.svg"></use>
</svg>
or… <object data="skate.svg"></object>
or… background-image: url("skate.svg");
External SVG with control
<svg style="—wheelcolor: red;">
<use href="icons.svg#skateboard"></use>
</svg>
Inside icons.svg:
<svg>
<symbol id="skateboard">
<path style="fill: var(—wheelcolor, blue);">
https://frontstuff.io/multi-colored-svg-symbol-icons-with-css-variables
Preloading RWD
Images?
Preload a <picture> hero image
<link rel="preload" href="small.jpg" as="image"
media="(max-width: 399px)">
<link rel="preload" href="medium.jpg" as="image"
media="(min-width: 400px) and (max-width: 799px)">
<link rel="preload" href="large.jpg" as="image"
media="(min-width: 800px)">
<picture>
<source srcset="large.jpg" media="(min-width: 800px)">
<source srcset="medium.jpg" media="(min-width: 400px)">
<img src="sml.jpg" alt="…">
</picture>
Preload an image[srcset]…?
<img src="sml.jpg" srcset=“sml.jpg 300w, lrg.jpg 800w”
sizes=“100vw”>
How that would look…
<link rel="preload" imagesrcset="sml.jpg 300w, lrg.jpg
800w" imagesizes="100vw" as="image">
<img src="sml.jpg" srcset=“sml.jpg 300w, lrg.jpg 800w”
sizes=“100vw”>
Most images are
not that important…
https://afarkas.github.io/lazysizes/index.html
https://addyosmani.com/blog/lazy-loading/
So Lazy!
<img src="very-lazy.jpg loading="lazy">
<iframe src="ads.html" loading="lazy"></iframe>
Loading Video
Performantly
Video - like picture syntax!
<video controls playsinline poster="somevideo.jpg"
preload="none">
<source src="somevideo.webm" type="video/webm">
<source src="somevideo.mp4" type="video/mp4">
</video>
Video - make it responsive too.
<video controls playsinline poster="somevideo.jpg">
<source src="somevideo-sml.webm" media="(max-width: 400px)"
type="video/webm">
<source src="somevideo-sml.mp4" media="(max-width: 400px)"
type="video/mp4">
<source src="somevideo-lrg.webm" type="video/webm">
<source src="somevideo-lrg.mp4" type="video/mp4">
</video>
Short code tidbit.
<code attribute=”value”>
<morecode anotherattr=”value” />
<morecode anotherattr=”value” />
</code attribute=”value”>
Font rendering
Progressive font rendering
Standard
Optimized
No More JS: CSS font-display
@font-face {
font-family: “Nice Serif”;
src: url(niceserif.woff2);
font-display: swap;
}
h1 {
font-family: “Nice Serif”, “Georgia”, serif;
}
https://twitter.com/szynszyliszys/status/1126261253280649216
https://caniuse.com/#search=font-display
https://www.filamentgroup.com/lab/js-web-fonts.html
Grouped Repaints
var font = new FontFace( … );
var fontBold = new FontFace( … );
Promise.all([
font.load(),
fontBold.load()
]).then(function(loadedFonts) {
loadedFonts.forEach(function(font) {
document.fonts.add(font);
});
});
}
Adapt to User Preferences
function loadFonts() {
/* NOTE: Reuse the Group Repaints code snippet above,
here */
}
if( navigator.connection &&
navigator.connection.saveData ) {
} else {
loadFonts();
}
Adapt to User Context
function loadFonts() {
/* NOTE: Reuse the Group Repaints code snippet above,
here */
}
if( navigator.connection &&
( navigator.connection.effectiveType === "slow-2g" ||
navigator.connection.effectiveType === "2g" ) ) {
// do nothing
} else {
loadFonts();
}
https://www.zachleat.com/web/comprehensive-webfonts/
Identifying
Problems
https://filamentgroup.com
speedcurve.com
Over-reliance on JavaScript
for Content
Empty Body = Fragile/Slow!
<body>
<div id="app"></div>
</body>
<script>
createApp( "#app", data );
</script>
https://css-tricks.com/server-side-react-rendering/
https://developers.google.com/web/updates/2019/02/rendering-on-the-web
Tag Managers and the Double Delay
1st MP
“
When we started this process we had a collection of very
old scripts and couldn’t track the original requester. We
removed those on the premise that, if they were
important, people would get back in touch — no one did.
The Telegraph Engineering
https://medium.com/the-telegraph-engineering/improving-third-party-web-performance-at-the-telegraph-a0a1000be5
https://docs.adobelaunch.com/client-side-information/asynchronous-deployment#synchronous-vs-asynchronous
Good options; tough sells
Don't vary content for rst-time visits
Async the scripts, only change content far
down the page
Preconnect the scripts involved.
Move the content variation to the server-side
fi
At very least… preconnect the inevitable.
<link rel="preconnect" href="https://example.com/">
<script src="https://example.com/thirdparty-2.js"
async defer>
https://www.cloudflare.com/products/cloudflare-workers/
https://www.filamentgroup.com/lab/servers-workers.html