Begynn med bildene. I nesten hver WordPress-måling vi gjør, er LCP-elementet et bilde, og de fleste optimaliseringsforsøk som ender uten effekt, har rørt alt annet først.
Grunnen er strukturell, ikke tilfeldig. Largest Contentful Paint måler tidspunktet der det største synlige elementet i viewporten er ferdig tegnet. På en produktside, en forside med et heltebilde eller en artikkel med et toppbilde er kandidatene bare noen få: overskriften, en bakgrunnsflate eller bildet. Tekst tegnes så snart skriften er tilgjengelig, ofte på første ramme. Bildet må først oppdages i HTML-en, deretter hentes over nettet, dekodes og tegnes. Fire steg mot ett. Derfor vinner bildet nesten alltid kappløpet om å bli det største, og taper kappløpet om å bli ferdig først.
Det praktiske utslaget er at LCP-arbeid på WordPress handler om fire spørsmål i rekkefølge: hvor tidlig finner nettleseren bildet, hvor stort er det i byte, hvilken variant velger den, og hvor mye annet konkurrerer om båndbredden i det samme sekundet.
Hvordan du finner ut hvilket element som faktisk er LCP
Ikke gjett. I Chrome DevTools viser Performance-panelet et LCP-merke i tidslinjen, og klikker du på det, markeres noden i Elements. Er du ute etter feltdata framfor labdata, henter du det samme fra et PerformanceObserver-kall som du kan kjøre i konsollen:
new PerformanceObserver((list) => {
const last = list.getEntries().at(-1);
console.log(last.element, Math.round(last.startTime), last.url);
}).observe({ type: 'largest-contentful-paint', buffered: true });To fallgruver her. LCP-elementet kan bytte identitet underveis, fordi hver ny kandidat rapporteres som en ny oppføring, og bare den siste teller. Og elementet er ofte et annet på mobil enn på skrivebord, siden viewporten avgjør hva som er størst. Vi har sett sider der heltebildet er LCP på skrivebord, mens en produktflise lenger nede tar over på mobil fordi heltebildet beskjæres bort av et responsivt utsnitt. Optimaliser feil element, og målingen rører seg ikke.
AVIF i praksis, og hva formatet koster
AVIF er WebP-etterfølgeren som endelig er trygg å bruke som standard. WordPress har støttet opplasting og generering av AVIF siden 6.5, så du trenger ikke lenger et programtillegg bare for å få formatet inn i mediebiblioteket. Nettleserstøtten er samlet opp: Chrome fra 85, Firefox fra 93 og Safari fra 16.4, altså macOS Ventura og iOS 16.4 og nyere.
Gevinsten ligger i komprimeringen. På fotografier med myke overganger, som produktbilder i interiørkategorier, ser vi jevnt over halvparten av WebP-størrelsen ved visuelt sammenlignbar kvalitet, og betydelig mer mot JPEG. På flate grafikker, logoer og skjermbilder med tekst er forskjellen mindre, og av og til negativ. Det er verdt å måle per bildetype framfor å konvertere hele biblioteket i blinde.
Kostnaden er koding. AVIF-koding er tung, og på en delt hosting med begrenset CPU-tid kan en masseregenerering av alle bildestørrelser ta timer og i verste fall tidsavbryte midt i. Vi kjører derfor konverteringen utenfor WordPress når biblioteket er stort, med avifenc eller Sharp i et lite skript, og laster inn ferdige filer. For løpende opplastinger er innebygd generering greit nok, fordi det da er ett bilde om gangen.
Fallback er fortsatt verdt å ta med når trafikken inneholder eldre iOS-enheter:
<picture>
<source type="image/avif" srcset="/bilder/sofa-800.avif 800w, /bilder/sofa-1600.avif 1600w" sizes="(max-width: 780px) 100vw, 780px">
<img src="/bilder/sofa-800.jpg" width="1600" height="900" alt="Modulsofa i gråmelert stoff" fetchpriority="high" decoding="async">
</picture>Merk at fetchpriority og dimensjonene hører hjemme på img-elementet, ikke på source. Det er en av de vanligste feilene i håndskrevet markup, og den er stille: markupen validerer, men prioriteringen forsvinner.
srcset og sizes, feilen som gjør AVIF verdiløs
Et riktig kodet AVIF-bilde hjelper ikke hvis nettleseren laster ned en variant som er tre ganger bredere enn plassen den skal fylle. Det er sizes-attributtet som avgjør dette, og det er nesten alltid feil på WordPress-temaer.
WordPress genererer srcset automatisk fra de registrerte bildestørrelsene, og setter en standard sizes som i praksis sier 100vw. På et tema der innholdskolonnen er 780 piksler bred på en 1440 piksler bred skjerm, betyr det at nettleseren regner med at bildet skal dekke 1440 piksler, og velger den nest største varianten den finner. Brukeren betaler for piksler som aldri vises.
Tre grep som faktisk flytter byte:
- Sett
sizessom speiler oppsettet ditt, ikke viewporten. Skriv den ut i temaet eller viawp_get_attachment_imagesitt attributtargument, og verifiser i DevTools under Network hvilken variant som ble valgt ved ulike vindusbredder. - Rydd i registrerte bildestørrelser. Et typisk kommersielt tema med noen programtillegg registrerer et tosifret antall, og hver opplasting genererer alle sammen. Det treffer både diskforbruk og
srcset-listen, som blir så lang at nettleserens valg blir mer sårbart for feilsizes. - Kjenn grensene. WordPress skalerer ned originaler over
big_image_size_threshold, som er 2560 piksler i standardoppsett, ogsrcset-kandidatene begrenses av filteretmax_srcset_image_widthmed 1600 piksler som utgangspunkt. Trenger du skarpe bilder på skjermer med høy pikseltetthet, må begge justeres bevisst, ikke ved et uhell.
Sanity-testen er enkel: last siden på en telefonbredde, se på det faktisk nedlastede bildets bredde i Network-fanen, og sammenlign med elementets clientWidth ganget med devicePixelRatio. Er det nedlastede bildet mer enn litt bredere, er sizes feil.
Lazy loading er nyttig overalt bortsett fra ett sted
WordPress har lagt loading="lazy" på bilder automatisk siden 5.5, og det har vært en av de mest lønnsomme standardendringene i kjernen. Men lat lasting på LCP-elementet er direkte skadelig: attributtet tar bildet ut av forhåndsskanningen, og nedlastingen starter først etter at oppsettet er beregnet. Vi har sett flere hundre millisekunder legge seg på LCP av den ene attributtverdien alene.
Kjernen prøver å håndtere dette selv. Siden 5.9 hopper den over det første bildet i innholdet, og fra 6.3 gjør den et bedre forsøk på å identifisere sannsynlig LCP-kandidat og legge på fetchpriority="high" der. Heuristikken er akkurat det, en heuristikk. Den ser ikke bilder som sidebyggere setter inn via shortcodes, bakgrunnsbilder i CSS eller bilder i en karusell som initialiseres av JavaScript. På sider bygget i Elementor eller lignende verktøy er det helt vanlig at heltebildet både er lat lastet og uten prioritet, mens et logobilde i toppmenyen får den høye prioriteten.
Sjekklisten vi går gjennom på hver side som skal måles:
- LCP-bildet har
fetchpriority="high", ikkeloading="lazy". - Alle bilder under folden har
loading="lazy"ogdecoding="async". - Ingen bilder over folden ligger som CSS-bakgrunn, fordi nettleserens forhåndsskanner ikke ser dem og de heller ikke kan prioriteres uten et eget
preload-hint. - Et eventuelt
<link rel="preload" as="image" imagesrcset=... imagesizes=...>bruker nøyaktig sammesrcsetogsizessom selve bildet. Avviker de, laster nettleseren to varianter av samme bilde, og du har gjort siden tregere mens grafen viser at du gjorde noe.
Plassen må reserveres før bildet finnes
Cumulative Layout Shift på bildetunge sider er som regel ikke et skriftproblem, det er et geometriproblem. Så lenge nettleseren ikke vet hvor høyt bildet blir, setter den av null piksler, og alt som ligger under hopper når filen lander.
width og height som attributter på img løser dette, fordi nettleseren regner ut størrelsesforholdet av dem og reserverer plass selv når CSS overstyrer den faktiske bredden. Attributtene skal være bildets ekte pikselmål, ikke visningsstørrelsen. Der markupen ikke lar seg kontrollere, for eksempel inni et programtillegg, setter vi aspect-ratio på beholderen i CSS i stedet.
To feller som overlever den første fiksen. Den første er bilder lastet etter interaksjon, typisk et galleri eller et anmeldelsesfelt som utvider seg, der forskyvningen skjer lenge etter innlasting og derfor ikke vises i en rask Lighthouse-kjøring, men teller i feltdata hvis den skjer innen fem sekunder etter siste inndata. Den andre er annonseplasser og innebygde widgeter med variabel høyde, der eneste robuste løsning er en beholder med fast minimumshøyde per bruddpunkt, satt etter å ha målt hva plasseringen faktisk returnerer.
Skrifter hører med i samme regnskap, men er et mindre problem enn folk tror når font-display: optional er i bruk: da byttes skriften aldri inn sent, og forskyvningen uteblir på bekostning av at noen besøkende ser systemskriften. size-adjust og ascent-override i en @font-face-erstatning er alternativet når designet ikke tåler det.
Hovedtråden bestemmer INP, og tredjepartsskript eier hovedtråden
Når bildene er i orden, flytter flaskehalsen seg til JavaScript. Interaction to Next Paint måler hele veien fra brukerens inndata til neste tegning, altså inndataforsinkelse, behandlingstid og tegningsforsinkelse samlet. På en typisk WooCommerce-side er det ikke butikkens egen kode som dominerer, det er sporing: en chat-widget, en tag-håndterer som laster fire andre skript, en piksel og et varmekartverktøy.
Partytown flytter slike skript til en Web Worker, og mekanismen er verdt å forstå før du installerer det. Worker-tråden har ikke tilgang til DOM, så Partytown fanger opp forsøkene og videresender dem synkront til hovedtråden gjennom en proxy. Det fungerer godt for skript som først og fremst sender data ut, og dårlig for skript som leser mye fra DOM eller manipulerer den, som A/B-testverktøy og noen samtykkebannere. Kompromisset er reelt: du kjøper responsivitet på hovedtråden mot en liten forsinkelse i sporingen og en ikke ubetydelig testjobb.
Der Partytown ikke passer, er rekkefølgen vi prøver: fjern skriptet helt hvis ingen har sett på dataene siste kvartal, last det etter første interaksjon, eller del opp lange oppgaver med scheduler.yield() der nettleseren støtter det. Det siste er ofte det eneste som hjelper mot egen tung kode, for eksempel en varianthåndterer som rekalkulerer hele prislogikken ved hvert klikk i et produktvalg.
Speculation Rules, og hvorfor den ikke er en unnskyldning
Speculation Rules API lar deg be nettleseren hente eller til og med rendre neste side før brukeren klikker. Dokumentregler gjør det mulig å beskrive hvilke lenker som er aktuelle, og eagerness styrer hvor aggressivt det skjer, fra conservative ved klikkstart til immediate.
<script type="speculationrules">
{
"prerender": [{
"where": { "href_matches": "/produkt/*" },
"eagerness": "moderate"
}]
}
</script>Effekten på opplevd hastighet er stor, fordi en prerendret side vises praktisk talt momentant. Begrensningene er like konkrete. Støtten er i praksis Chromium-basert, så Safari- og Firefox-brukere får ingenting. Prerendering koster minne og båndbredde hos brukeren, og immediate på en kategoriside med femti produktlenker er en fin måte å brenne mobildata på. Analyseverktøy teller prerendrede sidevisninger feil hvis de ikke sjekker document.prerendering. Og viktigst: en side som er treg å generere på serveren, blir like treg å prerendre, bare på et tidligere tidspunkt.
Serversiden setter gulvet
Ingen mengde bildearbeid kompenserer for høy Time to First Byte. TTFB er den delen av LCP som ingen frontend-teknikk kan skjule, fordi bildet ikke kan oppdages før HTML-en er levert.
De to tiltakene som gir mest på WordPress er vedvarende objektbuffer og HTML-buffring på kanten. Redis som objektbuffer fjerner de gjentatte databasespørringene etter menyer, valg og transienter, og på WooCommerce-installasjoner med mange autoloaded options er det ofte forskjellen mellom en side som genereres på hundre millisekunder og en som bruker nesten et sekund. Det er verdt å se på wp_options med autoload satt til yes før du konkluderer: et forlatt programtillegg som har lagret en megabyte med serialiserte data der, betaler du for ved hver eneste forespørsel.
Kantbuffring flytter selve leveransen nærmere brukeren, og for et norsk publikum betyr det at avstanden til opprinnelsesserveren slutter å dominere. Forbeholdet er at handlekurv, kasse og innloggede visninger må unntas, og at buffringsreglene må matche de informasjonskapslene butikken faktisk setter. En feilkonfigurert regel her er verre enn ingen buffring, fordi den kan servere én kundes tilstand til en annen.
Hva tallene betyr, og hvor de slutter å bety noe
Vi publiserer ikke prosentvis endring i fluktfrekvens, konverteringsrate eller annonsekostnad fra dette arbeidet. Grunnen er at slike tall ikke kan skilles fra sesong, kampanjer, sortimentsendringer og alt annet som skjedde i de samme ukene, og en leverandør som presenterer dem som sin egen effekt, presenterer en modell som en måling.
Det som derimot lar seg etterprøve, er terskelverdiene, og de er definert av Chrome-teamet, ikke av oss. LCP regnes som god under 2,5 sekunder, INP under 200 millisekunder og CLS under 0,1, alle målt på 75. persentil av ekte besøk. Du kan lese ditt eget nettsteds tall i Search Console under Core Web Vitals, eller direkte fra CrUX, uten å ta noen leverandørs ord for dem.
Sammenhengen mellom disse tallene og penger er reell, men indirekte. Raskere sider gir færre avbrutte innlastinger, og Page Experience er et av mange rangeringssignaler, ikke en bryter. Den ærlige formuleringen er at hastighetsarbeid fjerner en kjent friksjon, og at størrelsen på gevinsten avhenger av hvor mye friksjon som fantes, hvilke enheter publikummet ditt bruker, og hvor mye av trafikken som kommer på mobilnett med høy latens.
Rekkefølgen vi jobber i
Rekkefølgen er ikke tilfeldig, den følger hvor mye hvert steg låser opp for det neste.
- Mål først, på ekte enheter og med feltdata der de finnes. Labdata alene lyver begge veier.
- Identifiser LCP-elementet per viewport, ikke per side.
- Gjør det elementet lett og tidlig: riktig format, riktig variant, riktig prioritet, ingen lat lasting.
- Reserver plass for alt som lastes senere.
- Rydd i tredjepartsskript før du optimaliserer din egen JavaScript, fordi budsjettet ofte ligger der.
- Fjern serverlatens, som setter gulvet for alt over.
- Legg på spekulativ innlasting til slutt, som en forbedring av opplevelsen og ikke som en skjuling av arbeid du hoppet over.
Hastighet er ikke teknisk gjeld du betaler ned en gang. Den er en egenskap ved oppsettet som forfaller hver gang noen legger til et programtillegg, laster opp et ukomprimert bilde eller setter inn et nytt sporingsskript, og den eneste holdbare løsningen er en måling som kjører uten at noen ber om den.
Lekker din WooCommerce-butikk fart på grunn av bilder, skript og serverlatens? WPPoland måler først, viser hva som faktisk holder siden igjen, og fikser rekkefølgen.







