Nettsiden er treg. Noen foreslår CDN. Noen andre foreslår en dyrere hosting. Svært sjelden er det noen som åpner nettleserens nettverksfane og ser at forsiden laster ned et fire megabyte stort bilde som vises på 600 piksler bredde.
Å sende bytes er det dyreste en nettside gjør. Å sende færre bytes er gratis, og det gjør alle andre tiltak mer effektive. Så fiks filene først.
Jeg lover ingen bestemte hastighetsgevinster her. De avhenger av bildene dine, siden din og lesernes nettforbindelse. Det du får, er en metode for å måle det selv, og en rekkefølge som sjelden gir dårlig utbytte.
Steg 0: Mål før du rører noe #
Åpne siden i nettleseren, åpne utviklerverktøyene (nettverksfanen), last siden på nytt med cache slått av og se på bildene. Noter for de tyngste:
- filstørrelse (overført)
- faktiske pikselmål på filen
- hvor stort bildet vises på siden
Hvis filen er 3000 piksler bred og vises på 800, har du funnet første problem. Gjør det samme med Lighthouse eller et annet verktøy du allerede bruker, og skriv ned tallene. Uten «før» er «etter» bare en følelse.
Steg 1: Riktige dimensjoner #
Det mest effektive er ofte det kjedeligste: ikke send en 4000-pikslers original til en plass som er 800 piksler bred. Velg bredden du faktisk trenger, og husk høytetthetsskjermer, som vil ha omtrent dobbelt så mange piksler som visningsbredden.
Steg 2: Responsive varianter #
Én bredde passer ikke alle skjermer. Med srcset og sizes forteller du nettleseren hvilke versjoner som finnes og hvor stort bildet vises, og lar den velge. MDN forklarer at w-verdiene i srcset er bildets egentlige bredde i piksler, og at sizes er et hint om visningsbredden, evaluert i rekkefølge slik at den første betingelsen som treffer, vinner:
<img
src="foto-800w.jpg"
srcset="foto-480w.jpg 480w, foto-800w.jpg 800w, foto-1600w.jpg 1600w"
sizes="(width <= 800px) 100vw, 800px"
width="800" height="533"
alt="Beskrivelse av bildet"> Steg 3: Moderne formater, med fallback #
WebP og AVIF gir ofte mindre filer enn JPEG ved sammenlignbar kvalitet, men «ofte» er ikke «alltid», og det avhenger av motivet. Mål, ikke anta. AVIF er dessuten tregere å kode, noe du merker ved mange bilder i en byggejobb.
Slik serverer du nye formater uten å miste leserne med eldre nettlesere: picture med type på hver kilde. Nettleseren hopper over formater den ikke kan og bruker img som siste utvei:
<picture>
<source type="image/avif" srcset="foto-800w.avif 800w, foto-1600w.avif 1600w" sizes="800px">
<source type="image/webp" srcset="foto-800w.webp 800w, foto-1600w.webp 1600w" sizes="800px">
<img src="foto-800w.jpg" width="800" height="533" alt="Beskrivelse av bildet">
</picture> Kvaliteten er en avveining du må se med egne øyne. Bildet skal se bra nok ut, ikke være teoretisk best.
Steg 4: Lazy loading, men ikke på det viktigste bildet #
loading="lazy" utsetter lasting av bilder som ligger utenfor skjermen. web.dev sier uttrykkelig at du ikke skal late-laste bilder som sannsynligvis er synlige når siden åpnes, særlig det største innholdsbildet. Det skal lastes med en gang. Samme artikkel anbefaler å alltid sette width og height på img, slik at nettleseren kan reservere plass og siden ikke hopper når bildet kommer.
Regelen er enkel: bildet øverst på siden lastes direkte, alt under brettet kan vente.
Hvordan måle før og etter, uten å gjette #
Her er et lite Node-skript som lager varianter av ett bilde i flere bredder og formater og skriver ut filstørrelsene, slik at du kan sammenligne på ditt eget bilde. Det bruker biblioteket sharp (npm install sharp). Skriptet er kjørt på et generert testbilde for å bekrefte at det virker, men jeg har ikke målt noe på ekte nettstedbilder. Kvalitetsverdiene er utgangspunkt, ikke fasit.
// mal-bilder.mjs. Bruk: node mal-bilder.mjs foto.jpg 480 800 1600
import sharp from "sharp";
import { statSync } from "node:fs";
import { parse } from "node:path";
const [, , fil, ...bredder] = process.argv;
const { name } = parse(fil);
const kib = (f) => (statSync(f).size / 1024).toFixed(0);
console.log(`original: ${kib(fil)} KiB`);
for (const b of bredder.map(Number)) {
for (const [fmt, valg] of [
["jpeg", { quality: 80, mozjpeg: true }],
["webp", { quality: 80 }],
["avif", { quality: 50 }],
]) {
const ut = `${name}-${b}w.${fmt === "jpeg" ? "jpg" : fmt}`;
await sharp(fil)
.resize({ width: b, withoutEnlargement: true })
.toFormat(fmt, valg)
.toFile(ut);
console.log(`${ut}: ${kib(ut)} KiB`);
}
} Kjør det på tre av dine egne tyngste bilder, og fyll ut en tabell:
Bilde Original 800w JPEG 800w WebP 800w AVIF Vises på siden som
forside.jpg ____ KiB ____ KiB ____ KiB ____ KiB 800 px bredt Sammenlign deretter helheten: last siden på nytt med nettverksfanen åpen, før og etter, og noter totalt overført bildevolum. Det er det tallet leserne faktisk merker. Jeg har ikke oppgitt noen fasittall her, og det er med vilje: sparingen på et fotografi og på en skjermdump er helt forskjellig.
Astro som praktisk eksempel #
Prinsippene over gjelder uansett rammeverk. Bruker du Astro, finnes det innebygd hjelp. Ifølge Astro-dokumentasjonen optimaliserer Image-komponenten lokale bilder i src/, setter alt som obligatorisk, legger på loading="lazy" og decoding="async" og regner ut bredde og høyde for å unngå layoutskift. Picture lager et picture-element med én kilde per format du ber om. Fra Astro 5.10 kan du dessuten sette layout, som genererer srcset og sizes for deg:
// i den øverste (frontmatter-)delen av .astro-filen:
import { Picture } from "astro:assets";
import foto from "../assets/foto.jpg";
// i selve malen:
<Picture
src={foto}
alt="Beskrivelse av bildet"
formats={["avif", "webp"]}
layout="constrained"
width={800}
/> Tre fallgruver fra samme dokumentasjon:
- Bilder i
public/blir ikke behandlet. De serveres som de er. Skal de optimaliseres, må de ligge isrc/. - Eksterne bilder behandles bare hvis kilden er godkjent via
image.domainsellerimage.remotePatterns. - Hvis hosting-adapteret ikke støtter Sharp, for eksempel Cloudflare, kan du måtte bruke
passthroughImageService(), og da hoppes bildetransformasjonene over. Du tror du har optimalisert, men filene er uendret. Sjekk resultatet i nettverksfanen.
Og så: når er et CDN verdt det? #
Et CDN (content delivery network) legger kopier av filene dine nær leseren og avlaster serveren din. Det hjelper når leserne er spredt geografisk, når trafikken er høy eller kommer i topper, eller når opprinnelsesserveren din er treg eller dyr å belaste.
Det hjelper ikke med å gjøre en 4 MB-fil liten, med mindre CDN-et også tilbyr bildetransformasjon. Det gjør mange, men da kjøper du i praksis steg 1–3 som en tjeneste i stedet for å gjøre dem én gang selv. Det kan være et fint valg, særlig hvis du har tusenvis av bilder eller opplastinger fra andre. Men du bør vite at det er det du kjøper.
Rekkefølgen er altså: mål, riktig størrelse, responsive varianter, moderne format, lazy loading på riktig sted, mål igjen. Og så, hvis tallene fortsatt ser dårlige ut, vurder CDN. Da vet du i det minste hva du prøver å fikse.
