Er du rask i dit <head>? Opptegning av nettsider og the critical path
Hvorfor en rask nettside er viktig
Dagens brukere forventer at nettsider lastes raskt. Lastetiden er en faktor som direkte påvirker brukeropplevelsen, og noe vi bør jobbe med for å sikre fornøyde brukere - bare ta en titt på disse case studies.
Adobe forbedret lastetiden sin med ~4 sekunder. Det gjorde at besøksfrekvensen for engasjerte brukere økte med 35 % og gjennomsnittlig tid brukt på sidene deres økte med 21% for mobilbesøkende.
Dessuten kan det bidra til å øke konverteringen av nye brukere, redusere frafall, samt gi sidene våre en høyere SEO-rangering (Google prioriterer raskere nettsteder i sine søkeresultater).
Hvis en nettside er treg, kan det føre til frustrasjon og kanskje at brukere, i verste fall, forlater siden før de får tilgang til innholdet. På den andre siden kan en rask nettside øke sjansen for fornøyde brukere og at besøkende fullfører handlinger, som abonnementsregistreringer, og dermed øke konverteringsraten. Til slutt vil en rask nettside sikre at brukeren ikke mister tålmodigheten, bruker lengre tid og er mer engasjert på sidene våre.
Der er mange andre fordeler ved å prioritere ytelse. Som for eksempel:
- Mulige kostnadsbesparelse over tid, i forbindelse med redusering av båndbredde og serverressurser.
- Bedre håndtering av høy trafikvolumen (skalerbarhet).
- Gi et mere profesjonelt og pålitelig inntrykk av Amedia.
- ++
I kjerneteamet har vi jobbet mye med ytelse i 2024. Når vi jobber med ytelse, er en viktig del av puslespillet å forstå hvordan nettleseren tegner opp og håndterer ressurser på sidene våre. I den forbindelse må vi se på The Critical Path - Veien til optegning.
The Critical Path - Vejen til optegning
Er trinnene som er nødvendige for at siden tegnes opp i nettleseren.
For at nettleseren skal tegne opp en side, trenger den et HTML-dokument. I tillegg trenger den ressursene som er nødvendige for selve optegningen. Dette kan være scripts, fonts, stilark, eksterne referanser, osv.
Så hva skjer egentlig etter at nettleseren har lastet ned HTML-dokumentet som skal tegnes opp?
Nettleseren er flink til å tegne opp sider progressivt*, og så snart den har de nødvendige ressursene, vil den gjøre dette. Derfor må vi være oppmerksomme på når siden skal tegnes opp – og att den ikke gjør det for tidlig.
Nettleseren laster og viser innholdet gradvis, i stedet for å vente til alt innhold er lastet før det vises.
Vi har for eksempel ikke lyst til at siden skal tegnes så snart den har bare litt HTML, men ingen CSS eller JS. Da vil siden lastes ufullstendig i begynnelsen, for så å oppdatere seg umiddelbart etterpå. Du har sikkert sett dette for et par år tilbake, i Amedia-regi, hvor en side lastes med en fallback-font, for deretter raskt å laste den egentlige fonten. Siden ser altså midlertidig ødelagt ut – ikke en super brukeropplevelse.
Hvis nettleseren derimot venter på absolutt alle tilgjengelige ressurser før den tegner noe som helst, kan brukeren vente en god stund. Dette er ofte unødvendig, da det ikke er alle ressurser man trenger ved første optegning for å sikre en god brukeropplevelse.
Vi må altså definere et minimum av ressurser som nettleseren bør vente på, slik at vi sikrer at vi ikke viser en ufullstendig brukeropplevelse. Samtidig skal vi (ifølge webstandarder og fellesmål i Amedia (OKR)) ikke vente for lenge – under 1 sekund!
De stegene som nettleseren tar før den lager den første optegning kalles the critical rendering path – det er de avgjørende stegene for optegning av siden.
Å ha innsikt i disse stegene er viktig når vi jobber med ytelse. Vi må sørge for at alle nødvendige ressurser lastes og i riktig rekkefølge, slik at det ikke skjer unødvendig render-blokkering.
Sagt på en annen måte – Når en rekke handlinger er utført av nettleseren, vil brukeren se innhold på skjermen. Det er håndteringen av denne rekkefølgen som vi må ha kontroll på.
Vejen til rendering
Før vi ser en endelig side, utfører browseren disse handlinger:
- Konstruksjon av DOM fra HTML (struktur)
- Konstruksjon av CSSOM fra CSS (stiler)
- Tilføying av JS som skal endre DOM eller CSSOM (hvis det finnes)
- Konstruksjon av Render Tree fra DOM og CSSOM
- Utførelse av stil- og layoutoperasjoner på siden - for å se hva som passer hvor
- Opptegning av elementenes piksler i minnet
- Sammensetting av piksler hvis noen av dem overlapper
- Endelig/fysisk opptegning av resultatet av alle piksler
Denne prosessen skjer flere ganger og det er den innledende renderingen som starter prosessen. Men etter hvert som flere og flere ressurser (som har innvirkning på opptegningen av siden) lastes inn, vil nettleseren kjøre denne prosessen på nytt – som oftest bare deler av den, for å oppdatere det brukeren ser.
Hvilke ressurser er kritiske for opptegningen da?
Render-blocking refererer til enhver del av prosessen med å laste en nettside, som blokkerer opptegningen av brukergrensesnittet. Alt som tar over 50ms å laste, anses som render blocking. De vanligste årsakene til render blocking er de først lastede CSS- eller JavaScript-filene.
Nettleseren vil vente på kritiske ressurser den kan laste før den kan fullføre den første render. Disse ressursene er:
- En del av HTML-en
- Render-blokkerende CSS i
<head>
- Render-blokkerende JavaScript i
<head>
Et viktig poeng i måten nettleseren tegner siden på er at den gjør det på en streaming fashion. Det vil si litt etter litt. Så snart nettleseren får en del av sidens HTML vil den begynne å prosessere det. Den velger også ofte å tegne opp deler av HTML-en, selv om den ikke har lastet ned all HTML-en.
For første opptegning venter nettleseren vanligvis ikke på:
- All HTML
- Skrifttyper
- Bilder
- Ikke render-blokkerende JS som ligger utenfor
<head>
(for eksempel script-tagger i body) - Ikke render-blokkerende CSS som ligger utenfor
<head>
Husk: Render blocking ressurser vil altid være render blocking - uanset om de er plassert i
<head>
,<body>
, eller andre steder.
Bilder og skrifttyper anses av nettleseren som innhold som først skal tegnes opp av senere gjenopptegninger (rerenders), slik at de ikke blokkerer den første opptegningen. Dette kan i noen tilfeller føre til områder med tomme elementer, mens tekst venter på at skrifttypen lastes og bilder venter på kilden. Det er derfor viktig å sørge for at for eksempel dimensjoner på bilder er med i HTML-en. Slik vil man unngå Cumulative Layout Shift (CLS), som skjer når innhold blir lastet etterfølgende og layouten derfor hopper - igjen, ikke en god brukeropplevelse.
Bilder og skrifttyper anses av nettleseren som innhold som først skal tegnes opp av senere gjenopptegninger (rerenders), slik at de ikke blokkerer den første opptegningen. Dette kan i noen tilfeller føre til områder med tomme elementer, mens tekst venter på at skrifttypen lastes og bilder venter på kilden. Det er derfor viktig å inkludere dimensjonene på bildene (width
og height
) i HTML-en. Nettleseren bruker disse dimensjonene til å beregne ratio, som sikrer at det reserveres riktig plass i layouten allerede før bildet er lastet inn. Slik vil redusere risikoen Cumulative Layout Shift (CLS), som skjer når innhold blir lastet etterfølgende og layouten derfor hopper - igjen, ikke en god brukeropplevelse.
Har dit < head > bruk for paracet?
<head>
-elementet er en viktig brikke i prosessen som er the critical path, og å optimalisere innholdet i <head>
er et nøkkelelement i forbedring av ytelse. Kort fortalt inneholder <head>
-elementet metadata om siden og dens ressurser, men ikke noe som brukeren faktisk/teknisk sett ser. Synlig innhold ligger derimot i <body>
.
Før nettleseren kan tegne opp innholdet, trenger den både innholdet som skal rendres, samt metadata om hvordan dette skal skje.
Nettleseren bruker primært ressurser fra <head>
til å definere den første optegningen, fordi ressurser i <head>
tradisjonelt forventes å være nødvendige for å bygge den innledende strukturen og stylingen av siden.
Det er imidlertid ikke alle ressurser som det refereres til i <head>
, som er strengt nødvendige for første opptegning, så nettleseren vil kun vente på de som faktisk er (strengt nødvendige). For å identifisere hvilke ressurser som er nødvendige for veien til opptegning, må man først identifisere render-blokkerende og parser-blokkerende CSS og JS.
Render blocking
Noen ressurser er så viktige for nettleseren at den velger å sette hele opptegningen av siden på pause inntil den har lastet dem. Nettleseren er svært glad i CSS, og CSS er som standard i denne kategorien av viktige ressurser. Når en nettleser oppdager noe CSS (uansett om det er inline (<style>
) eller ekstern (<link rel=stylesheet href="">
) CSS) - venter nettleseren med å rendre mer inntil CSS-en er ferdig nedlastet og prosessert.
Vi er typisk mest interesserte i render-blokkerende ressurser fra <head>
, da disse faktisk blokkerer for rendering av hele siden. Dette er fordi ressurser i <head>
lastes og prosesseres før nettleseren begynner å rendre sidens innhold.
Så hva kan vi gjøre for å optimalisere disse ressursene?
Vi kan:
- Inline kritisk og tung CSS direkte i HTML-en (dersom CSS'en din er let og minifisert er det sandsynligvis ikke nødvendig å gjøre dette) [1]
- Bruke
defer
ellerasync
attributter på ikke-kritiske<script>
. - Minimere og komprimere CSS og JavaScript.
Dette vil gi betydlige forbedringer i sidens lastetid og generelle ytelse.
Nettleseren prøver alltid å være så effektiv som mulig. Når en ressurs er render-blokkerende, betyr det ikke at den stopper nettleseren i å gjøre andre ting. Den vil stoppe renderingsprosessen, men nettleseren vil fortsette med å prosessere resten av HTML-en og annet i mellomtiden. Stå på browser!
Og hvordan var det nå med defer
, async
og type=module
?
defer
er en eldre feature, async
litt nyere. Begge med bra støtte.
Den umidelbare forskjell er, at defer
venter på at hele HTML-dokumentet er parset, før den kjører scriptet - ideelt hvis du skal manipulere DOM'en eller er avhængig av andre scripts.
async
på den andre siden, kjører scriptet så snart det er lastet. Den venter altså ikke på noe annet end seg selv - ideel til scripts som ikke er avhængig av andre eller av at DOM'en er tegnet ferdig.
Når et <script>
har type="module"
, minner det i utgangspunktet mye om et <script>
med defer
- Det kjører først etter HTML-dokumentet er parset og moduler kjøres i den rekkefølgen de har i HTML'en.
Bruk bare
defer
medtype=module
for tydelighet. Ellers er det overflødigt.
Hold deg unna
async
medtype=module
- det funker ikke i denne kontekst.
Mere info om dette her: async, defer, async defer, module, nomodule, src, inline - the cheat sheet
Parser blocking
Parser-blokkerende ressurser er de som hindrer nettleseren i å finne annet å gjøre ved å fortsette med parsing av HTML-en.JavaScript er som standard parser-blokkerende, med mindre den er merket med async
eller defer
. Dette er fordi JavaScript kan endre DOM-en eller CSSOM-en når den kjøres. Derfor er det ikke mulig for nettleseren å fortsette med andre ressurser før den har det fulle bildet av hva den forespurte JavaScript-en gjør.
Parser-blokkerende ressurser er teknisk sett også render-blokkerende. Siden parseren ikke kan fortsette forbi en parser-blokkerende ressurs før den er fullstendig prosessert, kan den ikke få tilgang til og rendre innhold som kommer etter heller.
Nettleseren kan i utgangspunktet parse hvilken som helst HTML den har mottatt mens den venter på en blokkerer, men med tanke på the critical path, vil enhver parser-blokkerende ressurs i <head>
blokkere for alt annet innhold som skal rendres på siden, som vist i bilde under.
Så hva kan vi gjøre for å optimalisere disse ressursene?
- Sjekk om du kan bytte ut JavaScripten din med native HTML eller CSS løsninger - mindre JavaScript, raskere nettside.[2]
- Bruke
async
ellerdefer
attributter på ikke-kritiske<script>
. - Plassere
<script>
mot slutten av<body>
for å tillate progressiv rendering. - Være oppmerksom på at selv asynkrone skript kan blokkere parsing når de er ferdig nedlastet og begynner å kjøre.
Veien til optimeret ytelse
The critical path refererer til det minimum av ressurser, som nettleseren har bruk for, for at foreta den første (initielle) optegning af siden. En rask nettside er avgjørende for å oppnå en optimal brukeropplevelse, øke konverteringsrater og forbedre SEO.
De ressourcer som er en del af the critical path er:
- Render blocking JavaScript i
<head>
- Render blocking CSS i
<head>
- En del af HTML’en
Ved å forstå og forbedre the critical path kan vi redusere lastetiden og unngå render- og parser-blokkerende ressurser, noe som gir en jevn og effektiv opptegning av nettsidene. Tiltak som å inline kritisk CSS, bruke attributtene async og defer på JavaScript, flytte scripts til
samt minimere og komprimere kode, er avgjørende for å oppnå disse målene. Vi vil ikke bare gjøre sidene våre kjappere, vi vil også oppnå en bedre brukeropplevelse, styrke avisenes pålitelighet, profesjonalitet og i siste enden forbedre de forretningsmessige resultater.OBS - Der vil altid være noget som er render blocking og det er en del af renderingsprocessen. Det er til for at:
- Forhindre siden i at renderes i en ubrugelig eller ødelagt state.
- Sikre at synkron JavaScript først køres når parseren kommer til den, da JS kan ændre i DOM’en.
- Uden et
defer
ellerasync
attribut defineret i<script>
tagget, vil dette være parser blocking OG render blocking