Trainer München Thomas Puppe 22. März 2023 Workshop @ JS Days München 2023 Website Performance
A presentation at JavaScript, Angular, React, HTML & CSS Days in München in March 2023 in Munich, Germany by Thomas Puppe
Trainer München Thomas Puppe 22. März 2023 Workshop @ JS Days München 2023 Website Performance
👋 Hi, ich bin Thomas Senior Frontend Developer bei ZEIT Online. #webperf #a11y #leanweb
Website Performance
Credit: httparchive.org
Credits: https://de.statista.com/infografik/29079/durchschnittliche-kosten-fuer-1-gb-datenvolumen-in-ausgewaehlten-laendern-regionen/ , https://de.statista.com/infografik/24774/anteil-der-befragten-nach-der-groesse-des-inklusiven-datenvolumens/
Credit (left to right): Anastasia Nelen auf Unsplash
Credit: Pawel Czerwinski auf Unsplash
“According to Google’s DoubleClick, when comparing sites that load in 5 seconds to sites that load in 19 seconds, the faster sites had 70% longer average session lengths, 35% lower bounce rates and 25% higher ad viewability than their slower counterparts.” – wpostats.com
“Rebuilding Pinterest pages for performance resulted in a 40% decrease in wait time, a 15% increase in SEO traffic and a 15% increase in conversion rate to signup.” – wpostats.com
“SpeedSense worked with an e-commerce company to improve performance and saw a 7.6% increase in sitewide conversion, translating to roughly a $6 million lift in annual revenue. Mobile transactions increased by nearly 30% and sales per session increased by 16%.” – wpostats.com
“Rakuten 24 ran an A/B test showing: improved vitals brought a 53.4% incrase in revenue per visitor, 33.1% increase in conversion rate, 15.2% increase in average order value, 35.1% reduction in exit rate and more!” – wpostats.com
Credit: wpostats.com
Credit: Markus Spiske auf Unsplash
Website 😻 Performance
Aspekte von Aus Usersicht Website schnell / schlank / ruckelt nicht Performance Browser / Technologien HTML / CSS / Bilder / JavaScript / Schriften / Video / Audio Build / Server Bildformate / Komprimierung / CDN, Cloud / Caching / Netzwerk Wirkung Objektive Zahlen / Subjektive Wahrnehmung Kontrolle Messung / Testing / Monitoring / SEO Einfluss
Aspekte von Aus Usersicht Website schnell / schlank / ruckelt nicht Performance Browser / Technologien HTML / CSS / Bilder / JavaScript / Schriften / Video / Audio Build / Server Bildformate / Komprimierung / CDN, Cloud / Caching / Netzwerk Wirkung Objektive Zahlen / Subjektive Wahrnehmung Kontrolle Messung / Testing / Monitoring / SEO Einfluss
Her mit dem Code !
lama.thomaspuppe.de
Los gehts ! https://lama.thomaspuppe.de/notes.html 1– Wir setzen eine lokale Kopie auf unserem eigenen Rechner auf. 2– lokal öffnen, oder lokaler Webserver, oder Netlify/Vercel 3– Debugging mit dem Chrome Browser
erster Überblick
Devtools im Browser Der Webbrowser mit seinen Developer Tools ist das allerbeste Werkzeug für Web-Developer.
Alarmsignale: • Caching • Komprimierung
Bildoptimierung Größe in MB 55 Original 14.9 Breite 1000px Optimierte PNG 3.5 WEBP 0.867
Bildoptimierung Bildoptimierung, schnell und simpel mit Node Modulen. Originalbilder 55,5 MB npx image-cli-tools ./images/.png maxwidth=1000 npx image-cli-tools ./images/.png -o npx image-cli-tools ./images/*.png -webp Quasi jedes Tool lässt sich manuell aufrufen oder in den Build-Prozess integrieren. Außerdem gibt es kostenlose Web-Services und Applications mit GUI. Das gilt selbst für SVGs (SVGOptimize).
Takeaway Absolute Basics: - Bildkomprimierung beim Build - Datentransfer mit gzip / brotli - Caching
WebP Browser Support
WebP Fallback Einbindung mit Fallback für ältere Browser: <picture> <source srcset=”hero.webp” type=”image/webp”> <source srcset=”hero.png” type=”image/png”> <img src=”hero.jpg” alt=”Lamas!”> </picture> Responsive Bilder und Retina lassen wir heute außen vor.
BildOptimierung Coding Time ☐ Bildpfade ändern von images_unoptimized zu images_optimized Credit: Pitch Sticker “Cyberpunk”
Credits: apple.com, Lee Campbell auf Unsplash, Shiwa ID auf Unsplash
Browser Network Throttling Chromium und Firefox haben in den Devtools die Funktion, eine langsamere Netzwerkverbindung zu simulieren und das Caching auszuschalten.
Credits: Walt Disney Animation Studios / Giphy
Takeaway 80% der Performance-relevanten Beobachtungen mache ich im Netzwerk-Panel der Browser Developer Tools.
Was wird wann geladen?
Hero-Image
Die Spalten im Netzwerk-Tab der Developer Tools lassen sich anpassen. So kann man zum Beispiel den Initiator von Requests anzeigen.
Critical Rendering Path im Browser Credit: https://www.youtube.com/watch?v=ufCVTowBxoY
Preload Mit Preload-Links können wir im Head einer HTML-Seite dem Browser schon Hinweise geben auf Ressourcen, die während dem Rendern gebraucht werden.
<head> <link rel=”preload” as=”image” href=”/images_optimized/png/hero.png”> {… CSS usw usf …} </head> <body> … Unterstützt werden nicht nur Bilder, sondern auch Videos, JS Dateien, CSS Dateien.Preload Coding Time ☐ Gib dem Browser das Hero-Image schon im HTMLHead bekannt
<link rel=”preload” as=”image” href=”/images_optimized/png/hero.png”> Credit: Pitch Sticker “Cyberpunk”Hero-Image mit rel=preload
Developer Tools: Resource Priority Im Netzwerk-Tab kann man mit der rechten Maustaste die dargestellten Spalten umstellen. Eine davon ist die Priority. Sie zeigt an, ob der Browser dieselbe Vorstellung von Resource Priority hat wie ihr.-
rel=preload Browser Support
rel=preload und Media Queries, Retina
<link rel=”preload” as=”image” href=”hero-narrow.png” media=”(max-width: 600px)” > <link rel=”preload” as=”image” href=”/images/hero-huge_2x.png” media=”(min-width: 900px) and (-webkit-mindevice-pixel-ratio: 2)”> <link rel=”preload” as=”image” href=”hero.jpg” imagesrcset=”hero_800px.jpg 800w, hero_1600px.jpg 1600w” imagesizes=”50vw”> <link rel=”preload” as=”image” imagesrcset=”hero.png 1x, hero-2x.png 2x”>Takeaway Bilder und andere Ressourcen, die im ersten Viewport gezeigt werden, aber nicht im HTML vom Browser gefunden werden, per rel=preload im Head vorladen!
Während Preload Ressourcen auf der aktuellen Seite priorisiert, können mit Prefetch Inhalte vorgeladen werden, die auf späteren Seiten benötigt werden. Prefetch <link rel=”prefetch” as=”image” href=”/images/checkout-hero.jpg” /> <link rel=”prefetch” as=”document” href=”next-step.html” /> Das funktioniert für HTML-Seiten Bilder, Videos, Styles, JS. Es verbraucht Datenverkehr, sollte also bewusst und gezielt eingesetzt werden. User können es in den Browser-Settings unterbinden. “Quicklink” und “Guess” sind JavaScript Bibliotheken, die das Prefetchen automatisieren.
Lazy Loading
Lazy Loading Große Ressourcen sollten erst geladen werden, wenn sie tatsächlich gebraucht werden. Zum Beispiel: Bilder erst beim Scrollen auf der Seite laden.
Lazy Loading
Lazy Loading via JavaScript Für eine einfache Lazyload Implementierung reicht aus: <img data-src=”hero.png” alt=”Lamas!” > Dieses JavaScript tauscht die Bilder aus, sobald sie in den Viewport kommen: const images = document.querySelectorAll(‘img[data-src]’); const options = { rootMargin: ‘0px’, threshold: 0.5 }; const observer = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const image = entry.target; const src = image.getAttribute(‘data-src’); image.setAttribute(‘src’, src); image.removeAttribute(‘data-src’); observer.unobserve(image); } }); }, options); images.forEach(image => { observer.observe(image); });
Lazy Loading Für eine einfache Lazyload Implementierung reicht aus: <img data-src=”hero.png” alt=”Lamas!” > via JavaScript Dieses JavaScript tauscht die Bilder aus, sobald sie in den Viewport kommen: const images = document.querySelectorAll(‘img[data-src]’); const options = { rootMargin: ‘0px’, threshold: 0.5 }; const observer = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const image = entry.target; const src = image.getAttribute(‘data-src’); image.setAttribute(‘src’, src); image.removeAttribute(‘data-src’); observer.unobserve(image); } }); }, options); images.forEach(image => { observer.observe(image); });
Lazy Loading Für eine einfache Lazyload Implementierung reicht aus: <img data-src=”hero.png” alt=”Lamas!” > via JavaScript Dieses JavaScript tauscht die Bilder aus, sobald sie in den Viewport kommen: const images = document.querySelectorAll(‘img[data-src]’); const options = { rootMargin: ‘0px’, threshold: 0.5 }; const observer = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const image = entry.target; const src = image.getAttribute(‘data-src’); image.setAttribute(‘src’, src); image.removeAttribute(‘data-src’); observer.unobserve(image); } }); }, options); images.forEach(image => { observer.observe(image); });
Lazy Loading Für eine einfache Lazyload Implementierung reicht aus: <img data-src=”hero.png” alt=”Lamas!” > via JavaScript Dieses JavaScript tauscht die Bilder aus, sobald sie in den Viewport kommen: const images = document.querySelectorAll(‘img[data-src]’); const options = { rootMargin: ‘0px’, threshold: 0.5 }; const observer = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const image = entry.target; const src = image.getAttribute(‘data-src’); image.setAttribute(‘src’, src); image.removeAttribute(‘data-src’); observer.unobserve(image); } }); }, options); images.forEach(image => { observer.observe(image); });
Lazy Loading nativ Natives Lazyloading im Browser: <img src=”hero.png” alt=”Lamas!” loading=”lazy” >
Lazy Loading nativ Natives Lazyloading im Browser: <img src=”hero.png” alt=”Lamas!” loading=”lazy” >
<iframe src=”datawrapper.html” loading=”lazy” >Lazy Loading nativ Natives Lazyloading im Browser: <img src=”hero.png” alt=”Lamas!” loading=”lazy” >
loading=lazy Verbreitung: 25% der Seiten im Netz nutzen das loading=lazy Attribut an Bildern. Credit: https://httparchive.org/reports/state-of-images#imgLazy
Lazy Loading Mit loading=lazy übergibt man die Kontrolle an den Browser. Und der macht vielleicht Dinge, die man nicht möchte. nativ Zum Beispiel wird mehr vorgeladen, wenn die Internetverbindung langsam ist! kein Throttling: 2 Bilder fast 3G: 7 Bilder slow 3G: 16 Bilder
Lazy Loading Coding Time ☐ Implementiere Lazy Loading mit data-src und js/lazyload.js — oder — ☐ Implementiere Lazy Loading mit load=lazy Credit: Pitch Sticker “Cyberpunk”
Pause Credit: Pitch Sticker “Cyberpunk”
Layout Shift
Layout-Shift
Cumulative Der Cumulative Layout Shift (CLS) ist eine Maßeinheit für unerwartetes Verschieben des Layouts einer Website. Layout Shift CLS ist einer der Core Web Vitals von Google und fließt mit in das Google-Ranking ein! Credit: https://web.dev/cls/
Platz freihalten gegen Wer kennt den Padding-Trick? .image-container { position: relative; Layout-Shift padding-bottom: 56.25%; /* 16:9 Format, 9/16*100 */ } .image-container img { position: absolute; } Der Container des Bildes bekommt einen Padding-Bottom entsprechend des Bildverhältnisses. Das funktioniert, weil sich ein prozentuales Padding an der Breite des Containers orientiert. In den entsprechend dimensionierten Container passt das Bild (absolut positioniert, um nicht unter dem Padding zu landen) genau rein.
Platz freihalten gegen Layout-Shift Und wer kennt aspect-ratio? .img { aspect-ratio: 1.777; /* aspect-ratio: 16/9; */ } aspect-ratio definiert für Box-Elemente automatisch die Höhe anhand der Breite. Der Wert ist eine Dezimalzahl, die man aber auch durch einen Bruch angeben kann. Dieser wiederum nimmt auch die width/height Attribute eines Bildes entgegen.
Platz freihalten Und wer kennt aspect-ratio? gegen .img { Layout-Shift } aspect-ratio: 16/9; aspect-ratio definiert für Box-Elemente automatisch die Höhe anhand der Breite.
Cumulative Layout Shift Coding Time ☐ Binde das Hero-Image als Figure ein (statt als Hintergrundbild) und lade die kleinere CSS-Datei statt “styles-large.css”. ☐ Definiere eine aspect-ratio von 1.777 für die Bilder ☐ Beobachte den Layout Shift (vorher und) nachher. ☐ ggf Lazy Loading Credit: Pitch Sticker “Cyberpunk”
Takeaway Elemente, deren Höhe der Browser noch nicht kennt (aber ihr) mit aspect-ratio freihalten lassen, um Layout Shift zu vermeiden.
Core Web Vitals Web Vitals sind Metriken, die Google als zentrale Werte für die Performanve von Websites ermittelt. Diese Werte fließen ins Page Ranking mit ein. • LCP (Largest Contentful Paint): Zeit vom Klick auf einen Link bis zum Rendern des größten Teils des Inhalts. • CLS (Cumulative Layout Shift): optische Instabilität der Seite, gemessen aus Positionsverschiebungen von Elementen. • FID (First Input Delay): Verzögerung zwischen der ersten Interaktion mit er Seite, und einer Reaktion.
Pause Credit: Pitch Sticker “Cyberpunk”
Font Loading
Google Fonts @import url(‘https://fonts.googleapis.com/css2? family=Montserrat’); h1 { font-family: ‘Montserrat’; }
Google Fonts
<head> <link rel=”preconnect” href=”https://fonts.googleapis.com”> <link rel=”preconnect” href=”https://fonts.gstatic.com” crossorigin> <link href=”https://fonts.googleapis.com/css2? family=Montserrat” rel=”stylesheet”>Selfhosted @font-face { font-family: ‘Montserrat’; Fonts font-style: normal; font-weight: 400; font-display: block; src: url(‘/fonts/Montserrat-Regular.woff2’) format(‘woff2’); } h1 { font-family: ‘Montserrat’; }
<link href=”/fonts/Montserrat-Regular.woff2” rel=”preload” as=”font” crossorigin>Exkurs: Größe von Webfonts reduzieren 01 02 woff2 als Format verwenden Subsetting auf die benötigten Glyphen https://cloudconvert.com/ttf-to-woff2 https://everythingfonts.com/subsetter https://www.zachleat.com/web/glyphhanger/ 198 200 150 100 61 50 13 0 ttf Format woff2 Format woff2 Latin Subset 🤩
Font Preload Coding Time ☐ Optimiere die Einbindung der Schrift: ☐ Self Hosting (lokale “MontserratLocal” verwenden) ☐ kurzer “Critical Rendering Path” mit rel=preload ☐ Achtung: Google Font entfernen. Credit: Pitch Sticker “Cyberpunk”
Takeaway Schriften im woff2 Format selbst hosten und im HTML Head mit einem rel=preload ankündigen! Pro-Tip: Font Subsetting!
Font Loading / Display
… und während dem Laden der Webfonts?
… und während dem Laden der Webfonts? Credit: Zach Leatherman: The Mitt Romney webfont problem
Credits: https://www.fasterize.com/en/blog/web-performance-optimising-loading/
font-display Die font-display CSS-Property an @font-face Definitionen gibt dem Browser die Ladestrategie für Webfonts vor. @font-face { font-family: ‘MyWebFont’; src: url(‘myfont.woff2’) format(‘woff2’); font-display: [auto|block|swap|fallback|optional]; }
font-display Die font-display CSS-Property an @font-face Definitionen gibt dem Browser die Ladestrategie für Webfonts vor. @font-face { font-family: ‘MyWebFont’; src: url(‘myfont.woff2’) format(‘woff2’); font-display: [auto|block|swap|fallback|optional]; } Credit: https://caniuse.com/css-font-rendering-controls
font-display font-display: block; font-display: swap; font-display: fallback; font-display: optional; block swap fallback optional Platz wird freigehalten, System-Font wird Platz wird kurz freigehalten, Wie Fallback, aber der bis die Webfont angezeigt, bis die dann wird Systemfont Browser darf die Webfont geladen ist. Webfont geladen ist. gezeigt, dann die Webfont auch weglassen bei (wenn binnen 3s geladen). langsamen Verbindungen. Beim nächsten Seitenaufruf Beim nächsten Seitenaufruf ist die Schrift dann da. ist die Schrift dann da. FOIT FOUT (flash of invisible text) (flash of unstyled text) auto ist der Browser-Default, und das ist in der Regel swap/fallback. Swap wird auch von Google Fonts mitgegeben.
font-display Coding Time ☐ Benutze die langsame ‘MySlowWebfont” auf unserer Testseite. ☐ Beobachte und ändere die Font Loading Strategie ☐ Welche Strategie ist am besten gegen Layout Shift? Credit: Pitch Sticker “Cyberpunk”
Tooltipp Langsame Verbindungen simulieren mit • https://slowfil.es/ • https://www.npmjs.com/package/deelay Timeouts simulieren mit • https://blackhole.webpagetest.org • Blackhole-IP in die /etc/hosts eintragen: 72.66.115.13 www.google-analytics.com
Exkurs: Bei font-display: swap/fallback gibt es einen Flash of Unstyled Text (FOUT). Optimierung der Fallback Systemschrift Durch die unterschiedliche Laufweite und Buchstaben-Höhe von Systemschrift und Webfont springt der Text beim Laden der Webfont.
Exkurs: Bei font-display: swap/fallback gibt es einen Flash of Unstyled Text (FOUT). Optimierung der Fallback Systemschrift Mit dem Font Style Matcher von Monica Dinculescu kann man seine Fallbackfont per CSS so tweaken, dass der Flash of Unstyled Text möglichst unauffällig ist.
Vielleicht kannst du ganz auf Webfonts verzichten. Die Standard-Schriften der Betriebssysteme sind vielfältig. System Font Stacks • https://modernfontstacks.com/ • https://gist.github.com/don1138/5761014
Takeaway
Performance Measuring Tools
Developer Tools: Code Coverage https://devtoolstips.org
Lighthouse Google Lighthouse ist ein kostenloses Open-Source-Tool von Google, das Webentwicklern dabei hilft, die Leistung, Zugänglichkeit, Best Practices und Suchmaschinenoptimierung (SEO) ihrer Websites zu bewerten und zu verbessern. Lighthouse führt automatisch eine Reihe von Tests durch, um festzustellen, wie gut eine Website in diesen Bereichen abschneidet, und gibt dann Empfehlungen zur Verbesserung der Ergebnisse aus. • in den Browser Devtools • CLI • 🎯 npm install -g lighthouse) npx lighthouse ( http://localhost:4321/index.html • Pagespeed Insights Website https://pagespeed.web.dev/
Webpagetest .org 🥰 Bestes Tool zur manuellen Überprüfung. Bietet gute Übersicht für Einsteiger, und eine Menge Profi-Features. Gratis-Account verfügbar.
Speedcurve Bestes Tool für kontinuierliches Monitoring. Bietet neben synthetischen Tests auch Real User Monitoring. .com Nur Bezahl-Accounts, startet bei 12$ pro Monat.
🚀 Quellen zum Reinnerden ins Thema • web.dev/fast , awesome-wpo , • Blogs von CalibreApp , Harry Roberts , Tim Kadlec , Smashing Magazine , DebugBear , perfplanet.com • perf-tooling.today
🚀 Dankeschön https://www.thomaspuppe.de https://webperf.social/@thomaspuppe
Timing verpeilt? 1– Witzige Lama-Bilder generieren 2– Was fiel euch noch auf auf der Lama-Website? 3– Eine Website eurer Wahl analysieren 4– Fragen oder freie Diskussion zu Website Performance 5– fetchpriority, Responsive Images, JS/CSS Async Loading