Blog

Versnel je website met Performance.now() learnings

Laat jouw webshop hoger scoren op performance met onze learnings uit het event Performance.now(). Lees hier hoe je de LCP en INP optimaal verhoogt.

Donderdag 27 oktober en vrijdag 28 oktober heb ik de performance.now() conferentie in Amsterdam bezocht. Hier zijn hele interessante talks gegeven op het gebied van web-performance. In deze blog vertel ik je welke talks ik het meest interessant vond en wat je hier als webshop(developer) aan hebt of mee kunt doen.

Talk 1 - "What's new in performance?"

Priority hinting

Allereerst krijgen we de nieuwste performance updates van Katie Hempenius. Met het fetchpriority attribuut kun je naar de browser hinten wat de prioriteit van je asset zal gaan zijn. De browser bepaalt deze prioriteit zelf ook op basis van bepaalde voorwaarden.

Een afbeelding ‘above the fold’ krijgt van de browser automatisch een ‘high’ priority. Een afbeelding ‘below the fold’ krijgt automatisch een ‘low’ priority.

Browsers moeten vaak ook even nadenken over wat de prioriteit van een asset gaat zijn. Door een hint aan de browser te geven wat de prioriteit moet zijn, hoeft de browser dus niet meer na te denken en wordt de asset direct met de juiste prioriteit ingeladen. Meer documentatie kun je hier vinden.

Een mooie usecase hiervoor zou zijn wanneer de LCP (Largest Contentful Paint) van je pagina een afbeelding is. Deze wil je dan zo snel mogelijk inladen, zodat je LCP zo hoog mogelijk scoort. Wanneer je hier fetchpriority=”high” op plaatst, zal de browser deze afbeelding nog sneller herkennen als LCP en dus wordt je LCP score beter.

Bij onze klant Boerschappen hebben we dit toegepast. Je ziet duidelijk dat de afbeelding rechtsboven als eerste wordt ingeladen. Dit is de LCP van de pagina dus scoort de LCP goed.

Zoals je hieronder kunt zien hoef je simpelweg het fetchpriority attribuut toe te voegen aan je afbeelding element en that’s it!

Let op: Je kunt de fetchpriority van je asset niet aanpassen of veranderen met dit attribuut. Wanneer je op een afbeelding ‘below the fold’ fetchpriority=”high” plaatst zal deze nog steeds een low priority hebben. Daarom heet het dus priority hinting. Je geeft enkel een hint aan de browser wat volgens jouw de prioriteit van een asset gaat zijn.

Interaction to Next Paint

Interaction to Next Paint (INP) is een nieuwe performance metric die Google toepast in de Web Vitals. Deze metric meet de tijd die het duurt vanaf het moment dat een gebruiker bijvoorbeeld op een knop klikt en de eerstvolgende visuele verandering die wordt getoond.

Wanneer je slecht geoptimaliseerde javascript hebt geschreven, waardoor het heel lang duurt voordat je een visuele verandering ziet, zal je ook slecht scoren op INP. Idealiter bevat je website zo min mogelijk Javascript die je ‘Next Paint’ langzamer maakt. Soms is dit lastig om te verbeteren omdat je bijvoorbeeld afhankelijk bent van een API call.

Hoe wordt dit gemeten?

Zoals je in bovenstaande afbeelding kunt zien lijkt INP een beetje op FID (First Input Delay). Echter gaat FID enkel over de eerste interactie met de pagina en INP over alle interacties.

Hoe verbeter ik mijn INP?

  • Minder Javascript
    Dit is altijd beter voor de performance van je website en ook bij de metric INP. Wanneer je browser bezig is met het parsen (verwerken) van de Javascript is de browser even geblokkeerd. Als dit niet te lang duurt is dat prima, maar wanneer het te lang duurt spreek je van een ‘long-task of blocking task’. Bij een long task moet de gebruiker lang wachten voordat de browser weer reageert. Dit is erg slecht voor de gebruikerservaring en dus ook voor conversie.

  • Javascript code splitting / chunking
    Door je code op te splitsen in kleinere delen (chunks) is de kans kleiner dat je long tasks / blocking tasks zult hebben en scoor je beter op je FID en INP. Meer documentatie kan je hier vinden.

Quick fix

De snelste en makkelijkste manier om een goede INP score te hebben is om loaders toe te voegen die getoond worden op het moment van interactie tot de next paint. Bij een add-to-cart knop in een webshop zou je dit goed kunnen toepassen. De voorwaarde is natuurlijk wel dat je loaders direct getoond worden en dat hier niet ook nog een vertraging in zit.

Talk 2 - “Early Learnings for Early Hints at Shopify”

Early hints

Sia Karamalegos sprak in haar talk over Early Hints, een http status code ‘103’ die aangeeft dat de browser iets moet gaan doen voordat de HTML is gearriveerd in de browser.

Vaak moet een server nog allerlei acties uitvoeren voordat de HTML gereed is om naar de browser te versturen. Zoals bijvoorbeeld database queries of API calls. In de tussentijd is de browser aan het wachten en eigenlijk niks aan het doen. Dit is natuurlijk niet heel efficiënt, dus kunnen we de browser in deze tussentijd wel iets laten doen. Zoals bijvoorbeeld alvast de CSS ophalen en parsen. Wanneer de HTML dan arriveert in de browser is de CSS al kant en klaar om toegepast te worden. Dit scheelt tijd en is beter voor performance.

Hieronder een totaaloverzicht waar early hints tussen staan:

Bron: netfily.app

Hier zie je de lange weg die je request aflegt van de client naar de server en terug. Om dit te optimaliseren is het een goed idee om hier een CDN (Content Delivery Network) tussen te plaatsen. Deze bevat de gecachte variant van de website en dus ook de gecachte early hints. Hierdoor weet de browser nog sneller wat hij kan gaan preloaden terwijl de server bezig is.

Wat zijn dan die early hints?

De meest voorkomende early hints zijn ‘preload’ en ‘preconnect’.

Met preconnect vraag je aan de browser (wanneer deze er de tijd voor heeft) om alvast een verbinding op te zetten met een domein waar straks een call naar gedaan zal worden.

Met preload vraag je aan de browser om alvast een asset op te halen wanneer de browser hier de tijd voor heeft.

Let op: Early hints werken alleen echt goed wanneer je een situatie hebt waarin de server wat langer moet nadenken voordat de HTML wordt verstuurd. Ook moet de server in staat zijn om early hints te kunnen versturen, dit werkt niet altijd out of the box.

Talk 3 - “Optimising Largest Contentful Paint”

De talk van Harry Roberts heeft mij de afgelopen tijd aan het denken gezet. Mijn learnings hieronder komen deels uit de talk, maar ook uit mijn eigen ingevingen.

Wat en waarom LCP?

Gebruikers wachten over het algemeen tot de LCP geladen is voordat ze met de pagina interacteren. Daarom is het belangrijk dat deze zo snel mogelijk getoond wordt en gebruikers niet te lang moeten wachten.

Een duidelijk voorbeeld van wat een LCP is, zie je bijvoorbeeld bij onze klant Kwalitaria.

Hier zie je een groot leeg vlak wanneer de LCP nog niet geladen is. De gebruiker krijgt daardoor het gevoel dat de pagina nog niet geladen is en zal daarom nog even wachten met interacteren.

LCP zegt niet alles

De LCP zal altijd na de TTFB (Time To First Byte) en de FCP (First Contentful Paint) komen. Je zult dus eerst deze twee metrics moeten verbeteren voordat je de LCP kunt verbeteren. Wel zal het verbeteren van deze metrics de LCP ook automatisch verbeteren.

LCP zegt wel veel

Zoals je hier ziet is de LCP verantwoordelijk voor 25% van de totale performance score. Het is dus belangrijk dat je deze metric verbetert om snel je gehele performance score te kunnen verhogen. Met deze handige tool van Google kun je experimenteren met welke metrics je gehele performance score opbouwen.

Preload scanner

Sinds Internet Explorer 8 is de preload scanner in alle moderne browsers geïmplementeerd. Voor die tijd werd bij het parsen van styles, javascript etc. de gehele browser geblokkeerd. Maar met de preload scanner wordt er asynchroon door het document gescand naar assets en alvast gedownload. Sindsdien is het web 90% sneller geworden. Wij developers hoefden hier niets voor te doen en hoeven hier in principe nog steeds niets mee. Toch is het wel goed om je hier bewust van te zijn wanneer je een snelle LCP wilt hebben.

De reden dat je je bewust moet zijn van de preload scanner is omdat deze niet alle assets kan ontdekken. Zo worden CSS background-images bijvoorbeeld niet ontdekt door de preload scanner. Maak je hier gebruik van, dan zal je LCP score gegarandeerd lager uitvallen. Je kunt je er hier verder in verdiepen.

LCP do’s en don’ts

  1. Gebruik geen CSS background-image voor je LCP: de preload scanner ontdekt deze te laat.

  2. Gebruik geen Javascript om je LCP op te bouwen: HTML is snel, JS is langzaam. (Cookiebanner kan je LCP zijn)

  3. Gebruik geen loading="lazy" op je LCP: de preload scanner geeft dit een lage prioriteit en dus maak je je LCP bewust langzamer.

  4. Gebruik wel priority hints: dus fetchpriority=”high” op je LCP plaatsen.

Cookiebanner als LCP

Wanneer je cookiebanner te groot is, wordt deze als LCP gezien. Echter worden cookiebanners met javascript ingeladen, wat dramatisch is voor je LCP score. Dit was goed te zien toen de cookiebanner voor Boerschappen werd geïmplementeerd.

Links zie je de originele cookiebanner, die vanwege zijn grootte gezien werd als LCP van de pagina. We zagen in de LCP score hierdoor extreem verslechteren. Daarom hebben we de cookiebanner toen verkleind, zodat deze niet meer de LCP is. Onze score ging daardoor wel meer dan 300% omhoog. Dit laat goed zien wat de negatieve impact is wanneer je de LCP door middel van javascript inlaadt.

Text is best, image is good

Tekst kan ook gezien worden als LCP als deze visueel het grootste element is ‘above the fold’. Dit is goed om te weten want de LCP score wordt drastisch hoger bij een tekst dan een afbeelding. Wanneer je tekst hebt die bijna even groot is als de afbeelding die als LCP wordt gezien, dan is het misschien wel een optie om de afbeelding net wat kleiner te maken en de tekst een beetje groter. Net genoeg zodat de tekst als LCP wordt gezien in plaats van de afbeelding. Hierdoor zal je LCP vrijwel direct na de FCP komen en dus ‘perfect’ scoren.

“Puntjes op de i” - image decoding

Wanneer je alles hebt verbeterd voor je LCP, kun je nog de puntjes op de i zetten door de image-decoding expliciet te definiëren voor je LCP. Lees er hier meer over.

De twee opties voor image-decoding zijn ‘sync’ en ‘async’.

Hieronder zie je een async decoding van een afbeelding. Het is een pagina waarbij bovenaan een afbeelding staat met daaronder 10.000 paragrafen. Omdat de afbeeldingheeft, gaat de browser eerst de tekst renderen en daarna pas de afbeelding afronden.

Hieronder zie je een sync decoding van een afbeelding, dus img decoding=”sync”. In dit geval verloopt het renderen van de afbeelding synchroon met de tekst en wordt de afbeelding eerder getoond omdat deze dezelfde prioriteit heeft als de tekst.

De ultieme LCP

Laten we alles wat in deze blog beschreven staat combineren om onze afbeeldingen optimaal te laten scoren voor LCP.

Wanneer je LCP een afbeelding is zou deze er dus het beste als volgt uit moeten zien:

Wanneer een afbeelding niet de LCP is dan zou deze er zo uit moeten zien:

Met het doorgeven van early hints en het verbeteren van je LCP en INP scores, maak je jouw webshop nóg beter. Welke techniek ga jij als eerste toepassen om je performance te verhogen?