Een afbeeldingscomponent omvat best practices op het gebied van prestaties en biedt een kant-en-klare oplossing om afbeeldingen te optimaliseren.
Afbeeldingen zijn een veel voorkomende bron van prestatieknelpunten voor webapplicaties en een belangrijk aandachtsgebied voor optimalisatie. Niet-geoptimaliseerde afbeeldingen dragen bij aan het opzwellen van de pagina en zijn verantwoordelijk voor meer dan 70% van het totale paginagewicht in bytes op het 90e percentiel. Meerdere manieren om afbeeldingen te optimaliseren vereisen een intelligente "beeldcomponent" met standaard ingebouwde prestatieoplossingen.
Het Aurora- team werkte samen met Next.js om zo'n component te bouwen. Het doel was om een geoptimaliseerd afbeeldingssjabloon te maken dat webontwikkelaars verder konden aanpassen. De component dient als een goed model en zet een standaard voor het bouwen van afbeeldingscomponenten in andere raamwerken, contentmanagementsystemen (CMS) en tech-stacks. We hebben samengewerkt aan een soortgelijk onderdeel voor Nuxt.js, en we werken met Angular aan beeldoptimalisatie in toekomstige versies. In dit bericht wordt besproken hoe we de Next.js Image-component hebben ontworpen en welke lessen we onderweg hebben geleerd.
Problemen en mogelijkheden voor beeldoptimalisatie
Afbeeldingen hebben niet alleen invloed op de prestaties, maar ook op de bedrijfsvoering. Het aantal afbeeldingen op een pagina was de op een na grootste voorspeller van conversies van gebruikers die websites bezochten. Sessies waarin gebruikers converteerden, hadden 38% minder afbeeldingen dan sessies waarin ze niet converteerden. Lighthouse somt meerdere mogelijkheden op om afbeeldingen te optimaliseren en webvitaliteit te verbeteren als onderdeel van de best practices-audit. Enkele van de meest voorkomende gebieden waar afbeeldingen van invloed kunnen zijn op de kernfuncties van het web en de gebruikerservaring zijn als volgt.
Afbeeldingen zonder formaat doen CLS pijn
Afbeeldingen die worden weergegeven zonder dat de grootte ervan is opgegeven, kunnen lay-outinstabiliteit veroorzaken en bijdragen aan een hoge Cumulatieve Layout Shift ( CLS ). Het instellen van de width
en height
op <img>
-elementen kan lay-outverschuivingen helpen voorkomen. Bijvoorbeeld:
<img src="flower.jpg" width="360" height="240">
De breedte en hoogte moeten zo worden ingesteld dat de beeldverhouding van de weergegeven afbeelding dicht bij de natuurlijke beeldverhouding ligt. Een aanzienlijk verschil in de beeldverhouding kan ertoe leiden dat het beeld er vervormd uitziet. Een relatief nieuwe eigenschap waarmee u de beeldverhouding in CSS kunt specificeren, kan helpen om afbeeldingen responsief te vergroten, terwijl CLS wordt voorkomen.
Grote afbeeldingen kunnen LCP beschadigen
Hoe groter de bestandsgrootte van een afbeelding, hoe langer het downloaden duurt. Een grote afbeelding kan de 'held'-afbeelding voor de pagina zijn of het belangrijkste element in de viewport dat verantwoordelijk is voor het activeren van de Largest Contentful Paint ( LCP ). Een afbeelding die deel uitmaakt van de kritieke inhoud en het downloaden ervan lang duurt, zal de LCP vertragen.
In veel gevallen kunnen ontwikkelaars de afbeeldingsgrootte verkleinen door betere compressie en het gebruik van responsieve afbeeldingen. De attributen srcset
sizes
van het <img>
-element helpen om afbeeldingsbestanden van verschillende formaten te voorzien. Afhankelijk van de schermgrootte en resolutie kan de browser vervolgens de juiste kiezen.
Slechte beeldcompressie kan LCP schaden
Moderne afbeeldingsformaten zoals AVIF of WebP kunnen een betere compressie bieden dan de veelgebruikte JPEG- en PNG-formaten. Betere compressie verkleint de bestandsgrootte in sommige gevallen met 25% tot 50% voor dezelfde kwaliteit van de afbeelding. Deze reductie leidt tot snellere downloads met minder dataverbruik. De app moet moderne beeldformaten aanbieden aan browsers die deze formaten ondersteunen.
Het laden van onnodige afbeeldingen doet LCP pijn
Afbeeldingen onder de vouw of niet in de viewport worden niet aan de gebruiker weergegeven wanneer de pagina wordt geladen. Ze kunnen worden uitgesteld, zodat ze niet bijdragen aan het LCP en dit vertragen. Lazy-loading kan worden gebruikt om dergelijke afbeeldingen later te laden terwijl de gebruiker ernaartoe scrollt.
Optimalisatie-uitdagingen
Teams kunnen de prestatiekosten als gevolg van de eerder genoemde problemen evalueren en best practice-oplossingen implementeren om deze te overwinnen. In de praktijk gebeurt dit echter vaak niet en inefficiënte afbeeldingen blijven het internet vertragen. Mogelijke redenen hiervoor zijn onder meer:
- Prioriteiten : Webontwikkelaars hebben meestal de neiging zich te concentreren op code, JavaScript en gegevensoptimalisatie. Als zodanig zijn ze zich mogelijk niet bewust van problemen met afbeeldingen of hoe ze deze kunnen optimaliseren. Afbeeldingen gemaakt door ontwerpers of geüpload door gebruikers staan mogelijk niet hoog op de prioriteitenlijst.
- Out-of-the-box oplossing : Zelfs als ontwikkelaars zich bewust zijn van de nuances van beeldoptimalisatie, kan het ontbreken van een alles-in-één out-of-the-box oplossing voor hun framework of tech-stack een afschrikmiddel zijn.
- Dynamische afbeeldingen : Naast statische afbeeldingen die deel uitmaken van de applicatie, worden dynamische afbeeldingen geüpload door gebruikers of afkomstig uit externe databases of CMS's. Het kan een uitdaging zijn om de grootte van dergelijke afbeeldingen te definiëren als de bron van de afbeelding dynamisch is.
- Overbelasting van markeringen : Oplossingen voor het opnemen van de afbeeldingsgrootte of
srcset
voor verschillende formaten vereisen extra markeringen voor elke afbeelding, wat vervelend kan zijn. Hetsrcset
-attribuut werd in 2014 geïntroduceerd, maar wordt tegenwoordig door slechts 26,5% van de websites gebruikt . Bij gebruik vansrcset
moeten ontwikkelaars afbeeldingen in verschillende formaten maken. Tools zoals just-gimme-an-img kunnen helpen, maar moeten voor elke afbeelding handmatig worden gebruikt. - Browserondersteuning : Moderne afbeeldingsformaten zoals AVIF en WebP creëren kleinere afbeeldingsbestanden, maar hebben speciale behandeling nodig in browsers die deze niet ondersteunen. Ontwikkelaars moeten strategieën gebruiken zoals contentonderhandeling of het
<picture
> -element, zodat afbeeldingen aan alle browsers worden aangeboden. - Complicaties voor Lazy Loading : Er zijn meerdere technieken en bibliotheken beschikbaar om lazyloading voor afbeeldingen onder de vouw te implementeren. Het kiezen van de beste kan een uitdaging zijn. Ontwikkelaars weten mogelijk ook niet wat de beste afstand tot de "vouw" is om uitgestelde afbeeldingen te laden. Verschillende viewport-groottes op apparaten kunnen dit verder compliceren.
- Veranderend landschap : Nu browsers nieuwe HTML- of CSS-functies beginnen te ondersteunen om de prestaties te verbeteren, kan het voor ontwikkelaars moeilijk zijn om ze allemaal te evalueren. Chrome introduceert bijvoorbeeld de functie Fetch Priority als een Origin-proefversie . Het kan worden gebruikt om de prioriteit van specifieke afbeeldingen op de pagina te verhogen. Over het algemeen zouden ontwikkelaars het gemakkelijker vinden als dergelijke verbeteringen op componentniveau zouden worden geëvalueerd en geïmplementeerd.
Beeldcomponent als oplossing
De beschikbare mogelijkheden om afbeeldingen te optimaliseren en de uitdagingen bij het individueel implementeren ervan voor elke toepassing brachten ons op het idee van een beeldcomponent. Een afbeeldingscomponent kan best practices inkapselen en afdwingen. Door het <img>
-element te vervangen door een afbeeldingscomponent kunnen ontwikkelaars hun problemen met de beeldprestaties beter aanpakken.
Het afgelopen jaar hebben we met het Next.js- framework gewerkt om hun Image-component te ontwerpen en te implementeren . Het kan als volgt worden gebruikt als drop-in vervanging voor de bestaande <img>
-elementen in Next.js-apps.
// Before with <img> element:
function Logo() {
return <img src="/logo.jpg" alt="logo" height="200" width="100" />
}
// After with image component:
import Image from 'next/image'
function Logo() {
return <Image src="/logo.jpg" alt="logo" height="200" width="100" />
}
De component probeert beeldgerelateerde problemen generiek aan te pakken via een rijke reeks functies en principes. Het bevat ook opties waarmee ontwikkelaars het kunnen aanpassen aan verschillende afbeeldingsvereisten.
Bescherming tegen lay-outverschuivingen
Zoals eerder besproken veroorzaken afbeeldingen zonder formaat lay-outverschuivingen en dragen ze bij aan CLS. Bij het gebruik van de Next.js Image-component moeten ontwikkelaars een afbeeldingsgrootte opgeven met behulp van de kenmerken width
en height
om eventuele lay-outverschuivingen te voorkomen. Als de grootte onbekend is, moeten ontwikkelaars layout=fill
opgeven om een afbeelding zonder grootte weer te geven die zich in een container met grootte bevindt. Als alternatief kunt u statische afbeeldingen importeren om de grootte van de daadwerkelijke afbeelding op de harde schijf tijdens het bouwen op te halen en deze in de afbeelding op te nemen.
// Image component with width and height specified
<Image src="/logo.jpg" alt="logo" height="200" width="100" />
// Image component with layout specified
<Image src="/hero.jpg" layout="fill" objectFit="cover" alt="hero" />
// Image component with image import
import Image from 'next/image'
import logo from './logo.png'
function Logo() {
return <Image src={logo} alt="logo" />
}
Omdat ontwikkelaars de afbeeldingscomponent niet zonder grootte kunnen gebruiken, zorgt het ontwerp ervoor dat ze de tijd nemen om de afbeeldingsgrootte te overwegen en lay-outverschuivingen te voorkomen.
Faciliteer het reactievermogen
Om afbeeldingen op verschillende apparaten responsief te maken, moeten ontwikkelaars de kenmerken srcset
sizes
instellen in het <img>
-element. We wilden deze inspanning verminderen met de component Afbeelding. We hebben de component Next.js Image ontworpen om de attribuutwaarden slechts één keer per toepassing in te stellen. We passen ze toe op alle exemplaren van de component Afbeelding op basis van de lay-outmodus. We hebben een driedelige oplossing bedacht:
-
deviceSizes
eigenschap: deze eigenschap kan worden gebruikt om breekpunten eenmalig te configureren op basis van de apparaten die gemeenschappelijk zijn voor het gebruikersbestand van de toepassing. De standaardwaarden voor breekpunten zijn opgenomen in het configuratiebestand. -
imageSizes
eigenschap: Dit is ook een configureerbare eigenschap die wordt gebruikt om de afbeeldingsgrootten op te halen die overeenkomen met de breekpunten van de apparaatgrootte. -
layout
-kenmerk in elke afbeelding: dit wordt gebruikt om aan te geven hoe de eigenschappendeviceSizes
enimageSizes
voor elke afbeelding moeten worden gebruikt. De ondersteunde waarden voor de lay-outmodus zijnfixed
,fill
,intrinsic
enresponsive
Wanneer een afbeelding wordt opgevraagd met de lay-outmodi responsive of fill , identificeert Next.js de afbeelding die moet worden weergegeven op basis van de grootte van het apparaat dat de pagina opvraagt en worden de srcset
en sizes
in de afbeelding op de juiste manier ingesteld.
De volgende vergelijking laat zien hoe de lay-outmodus kan worden gebruikt om de grootte van de afbeelding op verschillende schermen te regelen. We hebben een demo-afbeelding gebruikt die is gedeeld in de Next.js-documenten, bekeken op een telefoon en een standaardlaptop.
Laptopscherm | Telefoonscherm |
---|---|
Lay-out = Intrinsiek: schaalt omlaag om te passen in de breedte van de container op kleinere viewports. Schaalt niet verder dan de intrinsieke grootte van de afbeelding op een grotere viewport. Containerbreedte staat op 100% | |
![]() | ![]() |
Layout = Opgelost: afbeelding reageert niet. Breedte en hoogte worden op dezelfde manier vastgesteld als ` | |
![]() | ![]() |
Lay-out = Responsief: Schaal omlaag of omhoog, afhankelijk van de breedte van de container op verschillende viewports, waarbij de beeldverhouding behouden blijft. | |
![]() | ![]() |
Indeling = Opvulling: breedte en hoogte uitgerekt om de bovenliggende container te vullen. (De breedte van de bovenliggende <div> is in dit voorbeeld ingesteld op 300*500) | |
![]() | ![]() |
Zorg voor ingebouwde lazyloading
De component Image biedt standaard een ingebouwde, performante lazyload- oplossing. Als je het <img>
-element gebruikt, zijn er een paar opties voor lazy load, maar deze hebben allemaal nadelen waardoor ze lastig te gebruiken zijn. Een ontwikkelaar kan een van de volgende lazyload-benaderingen gebruiken:
- Geef het
loading
op: Dit wordt ondersteund in alle moderne browsers . - Gebruik de Intersection Observer API : het bouwen van een aangepaste lazy-loading-oplossing vereist inspanning en een doordacht ontwerp en implementatie. Ontwikkelaars hebben hier misschien niet altijd de tijd voor.
- Importeer een bibliotheek van derden om afbeeldingen lui te laden: Er kan extra inspanning nodig zijn om een geschikte bibliotheek van derden voor lui laden te evalueren en te integreren.
In de component Next.js Image is het laden standaard ingesteld op "lazy"
. Lazyloading wordt geïmplementeerd met behulp van Intersection Observer, dat beschikbaar is in de meeste moderne browsers . Ontwikkelaars hoeven niets extra's te doen om dit in te schakelen, maar kunnen het indien nodig uitschakelen.
Belangrijke afbeeldingen vooraf laden
Heel vaak zijn LCP-elementen afbeeldingen, en grote afbeeldingen kunnen LCP vertragen. Het is een goed idee om kritieke afbeeldingen vooraf te laden, zodat de browser die afbeelding eerder kan ontdekken. Wanneer u een <img>
-element gebruikt, kan er als volgt een preload-hint in de HTML-header worden opgenomen.
<link rel="preload" as="image" href="important.png">
Een goed ontworpen afbeeldingscomponent zou een manier moeten bieden om de laadvolgorde van afbeeldingen aan te passen, ongeacht het gebruikte raamwerk. In het geval van de Next.js Image-component kunnen ontwikkelaars een afbeelding aangeven die een goede kandidaat is voor vooraf laden met behulp van het priority
van de images-component.
<Image src="/hero.jpg" alt="hero" height="400" width="200" priority />
Het toevoegen van een priority
vereenvoudigt de opmaak en is handiger in gebruik. Ontwikkelaars van afbeeldingscomponenten kunnen ook opties verkennen om heuristieken toe te passen om het vooraf laden van afbeeldingen boven de vouw op de pagina te automatiseren die aan specifieke criteria voldoen.
Stimuleer hoogwaardige beeldhosting
Image CDN's worden aanbevolen voor het automatiseren van beeldoptimalisatie, en ze ondersteunen ook moderne beeldformaten zoals WebP en AVIF. De Next.js Image-component gebruikt standaard een image-CDN met behulp van een loader-architectuur . In het volgende voorbeeld ziet u dat de lader configuratie van het CDN in het configuratiebestand Next.js mogelijk maakt.
module.exports = {
images: {
loader: 'imgix',
path: 'https://ImgApp/imgix.net',
},
}
Met deze configuratie kunnen ontwikkelaars relatieve URL's in de afbeeldingsbron gebruiken, en het raamwerk zal de relatieve URL samenvoegen met het CDN-pad om de absolute URL te genereren. Populaire afbeeldings-CDN's zoals Imgix , Cloudinary en Akamai worden ondersteund. De architectuur ondersteunt het gebruik van een aangepaste cloudprovider door een aangepaste loader
voor de app te implementeren.
Ondersteuning van zelfgehoste afbeeldingen
Er kunnen situaties zijn waarin websites geen afbeeldings-CDN's kunnen gebruiken. In dergelijke gevallen moet een afbeeldingscomponent zelf-gehoste afbeeldingen ondersteunen. De Next.js Image-component gebruikt een afbeeldingsoptimalisatie als ingebouwde afbeeldingsserver die een CDN-achtige API biedt. De optimalisatie gebruikt Sharp voor transformaties van productieafbeeldingen als deze op de server is geïnstalleerd. Deze bibliotheek is een goede keuze voor iedereen die zijn eigen pijplijn voor beeldoptimalisatie wil opbouwen.
Ondersteuning van progressieve belasting
Progressief laden is een techniek die wordt gebruikt om de interesse van gebruikers vast te houden door een tijdelijke afbeelding weer te geven, die doorgaans van aanzienlijk lagere kwaliteit is, terwijl de daadwerkelijke afbeelding wordt geladen. Het verbetert de waargenomen prestaties en verbetert de gebruikerservaring. Het kan worden gebruikt in combinatie met lazyloading voor afbeeldingen onder de vouw of voor afbeeldingen boven de vouw.
De component Next.js Image ondersteunt progressief laden van de afbeelding via de placeholder- eigenschap. Dit kan worden gebruikt als LQIP (plaatsaanduiding voor afbeeldingen van lage kwaliteit) voor het weergeven van een afbeelding van lage kwaliteit of wazig terwijl de daadwerkelijke afbeelding wordt geladen.
Invloed
Met al deze optimalisaties hebben we succes gezien met de Next.js Image-component in productie en werken we ook samen met andere tech-stacks aan vergelijkbare afbeeldingscomponenten.
Toen Leboncoin hun oude JavaScript-frontend naar Next.js migreerde , hebben ze ook hun afbeeldingspijplijn geüpgraded om de Next.js Image-component te gebruiken. Op een pagina die van <img>
naar next/image migreerde, daalde de LCP van 2,4 s naar 1,7 s. Het totaal aantal gedownloade afbeeldingsbytes voor de pagina ging van 663 kB naar 326 kB (met ~100 kB aan lui geladen afbeeldingsbytes).
Geleerde lessen
Iedereen die een Next.js-app maakt, kan profiteren van het gebruik van de Next.js Image-component voor optimalisatie. Als u echter soortgelijke prestatieabstracties voor een ander raamwerk of CMS wilt bouwen, volgen hier enkele lessen die we onderweg hebben geleerd en die nuttig kunnen zijn.
Veiligheidskleppen kunnen meer kwaad dan goed doen
In een vroege release van de component Next.js Image hebben we een attribuut unsized
geleverd waarmee ontwikkelaars de vereiste grootte konden omzeilen en afbeeldingen met niet-gespecificeerde afmetingen konden gebruiken. We dachten dat dit nodig zou zijn in gevallen waarin het onmogelijk was om vooraf de hoogte of breedte van de afbeelding te kennen. We merkten echter dat gebruikers het unsized
attribuut in GitHub-problemen aanbeveelden als een allesomvattende oplossing voor problemen met de vereiste grootte, zelfs in gevallen waarin ze het probleem konden oplossen op een manier die CLS niet verergerde. Vervolgens hebben we het kenmerk unsized
afgeschaft en verwijderd.
Scheid nuttige wrijving van zinloze ergernis
De vereiste voor het formaat van een afbeelding is een voorbeeld van 'nuttige wrijving'. Het beperkt het gebruik van de component, maar biedt in ruil daarvoor enorme prestatievoordelen. Gebruikers zullen de beperking gemakkelijk accepteren als ze een duidelijk beeld hebben van de potentiële prestatievoordelen. Daarom is het de moeite waard om deze afweging uit te leggen in de documentatie en ander gepubliceerd materiaal over de component.
U kunt echter oplossingen voor dergelijke wrijving vinden zonder dat dit ten koste gaat van de prestaties. Tijdens de ontwikkeling van de component Next.js Image ontvingen we bijvoorbeeld klachten dat het vervelend was om formaten op te zoeken voor lokaal opgeslagen afbeeldingen. We hebben statische afbeeldingsimporten toegevoegd, die dit proces stroomlijnen door tijdens het bouwen automatisch afmetingen voor lokale afbeeldingen op te halen met behulp van een Babel-plug-in.
Zorg voor een evenwicht tussen gemaksfuncties en prestatie-optimalisaties
Als uw afbeeldingscomponent niets anders doet dan "nuttige wrijving" opleggen aan zijn gebruikers, zullen ontwikkelaars de neiging hebben om deze niet te willen gebruiken. We ontdekten dat prestatiekenmerken zoals beeldgrootte en het automatisch genereren van srcset
-waarden het belangrijkst waren. Op ontwikkelaars gerichte gemaksfuncties zoals automatisch lui laden en ingebouwde wazige tijdelijke aanduidingen wekten ook interesse in de Next.js Image-component.
Stel een routekaart op voor functies om de acceptatie te stimuleren
Het bouwen van een oplossing die perfect werkt voor alle situaties is erg moeilijk. Het kan verleidelijk zijn om iets te ontwerpen dat goed werkt voor 75% van de mensen en vervolgens tegen de andere 25% te zeggen dat "in deze gevallen dit onderdeel niets voor jou is."
In de praktijk blijkt deze strategie haaks te staan op jouw doelstellingen als componentontwerper. U wilt dat ontwikkelaars uw component adopteren om te profiteren van de prestatievoordelen ervan. Dit is moeilijk te doen als er een contingent gebruikers is die niet kunnen migreren en zich buiten het gesprek buitengesloten voelen. Ze zullen waarschijnlijk hun teleurstelling uiten, wat leidt tot negatieve percepties die de adoptie beïnvloeden.
Het is raadzaam om voor uw component een routekaart te hebben die alle redelijke gebruiksscenario's op de lange termijn dekt. Het helpt ook om in de documentatie expliciet te zijn over wat niet wordt ondersteund en waarom, om verwachtingen te scheppen over de problemen die de component moet oplossen.
Conclusie
Het gebruik en de optimalisatie van afbeeldingen zijn ingewikkeld. Ontwikkelaars moeten de balans vinden tussen prestaties en kwaliteit van afbeeldingen en tegelijkertijd een geweldige gebruikerservaring garanderen. Dit maakt beeldoptimalisatie een dure onderneming met grote impact.
In plaats van elke app elke keer het wiel opnieuw te laten uitvinden, hebben we een best practices-sjabloon bedacht die ontwikkelaars, frameworks en andere tech-stacks konden gebruiken als referentie voor hun eigen implementaties. Deze ervaring zal inderdaad waardevol blijken als we andere raamwerken ondersteunen op het gebied van hun imagocomponenten.
De Next.js Image-component heeft met succes de prestatieresultaten in Next.js-applicaties verbeterd, waardoor de gebruikerservaring is verbeterd. Wij zijn van mening dat het een geweldig model is dat goed zou werken in het bredere ecosysteem, en we horen graag van ontwikkelaars die dit model in hun projecten willen overnemen.
,Een afbeeldingscomponent omvat best practices op het gebied van prestaties en biedt een kant-en-klare oplossing om afbeeldingen te optimaliseren.
Afbeeldingen zijn een veel voorkomende bron van prestatieknelpunten voor webapplicaties en een belangrijk aandachtsgebied voor optimalisatie. Niet-geoptimaliseerde afbeeldingen dragen bij aan het opzwellen van de pagina en zijn verantwoordelijk voor meer dan 70% van het totale paginagewicht in bytes op het 90e percentiel. Meerdere manieren om afbeeldingen te optimaliseren vereisen een intelligente "beeldcomponent" met standaard ingebouwde prestatieoplossingen.
Het Aurora- team werkte samen met Next.js om zo'n component te bouwen. Het doel was om een geoptimaliseerd afbeeldingssjabloon te maken dat webontwikkelaars verder konden aanpassen. De component dient als een goed model en zet een standaard voor het bouwen van afbeeldingscomponenten in andere raamwerken, contentmanagementsystemen (CMS) en tech-stacks. We hebben samengewerkt aan een soortgelijk onderdeel voor Nuxt.js, en we werken met Angular aan beeldoptimalisatie in toekomstige versies. In dit bericht wordt besproken hoe we de Next.js Image-component hebben ontworpen en welke lessen we onderweg hebben geleerd.
Problemen en mogelijkheden voor beeldoptimalisatie
Afbeeldingen hebben niet alleen invloed op de prestaties, maar ook op de bedrijfsvoering. Het aantal afbeeldingen op een pagina was de op een na grootste voorspeller van conversies van gebruikers die websites bezochten. Sessies waarin gebruikers converteerden, hadden 38% minder afbeeldingen dan sessies waarin ze niet converteerden. Lighthouse somt meerdere mogelijkheden op om afbeeldingen te optimaliseren en webvitaliteit te verbeteren als onderdeel van de best practices-audit. Enkele van de meest voorkomende gebieden waar afbeeldingen van invloed kunnen zijn op de kernfuncties van het web en de gebruikerservaring zijn als volgt.
Afbeeldingen zonder formaat doen CLS pijn
Afbeeldingen die worden weergegeven zonder dat de grootte ervan is opgegeven, kunnen lay-outinstabiliteit veroorzaken en bijdragen aan een hoge Cumulatieve Layout Shift ( CLS ). Het instellen van de width
en height
op <img>
-elementen kan lay-outverschuivingen helpen voorkomen. Bijvoorbeeld:
<img src="flower.jpg" width="360" height="240">
De breedte en hoogte moeten zo worden ingesteld dat de beeldverhouding van de weergegeven afbeelding dicht bij de natuurlijke beeldverhouding ligt. Een aanzienlijk verschil in de beeldverhouding kan ertoe leiden dat het beeld er vervormd uitziet. Een relatief nieuwe eigenschap waarmee u de beeldverhouding in CSS kunt specificeren, kan helpen om afbeeldingen responsief te vergroten, terwijl CLS wordt voorkomen.
Grote afbeeldingen kunnen LCP beschadigen
Hoe groter de bestandsgrootte van een afbeelding, hoe langer het downloaden duurt. Een grote afbeelding kan de 'held'-afbeelding voor de pagina zijn of het belangrijkste element in de viewport dat verantwoordelijk is voor het activeren van de Largest Contentful Paint ( LCP ). Een afbeelding die deel uitmaakt van de kritieke inhoud en het downloaden ervan lang duurt, zal de LCP vertragen.
In veel gevallen kunnen ontwikkelaars de afbeeldingsgrootte verkleinen door betere compressie en het gebruik van responsieve afbeeldingen. De attributen srcset
sizes
van het <img>
-element helpen om afbeeldingsbestanden van verschillende formaten te voorzien. Afhankelijk van de schermgrootte en resolutie kan de browser vervolgens de juiste kiezen.
Slechte beeldcompressie kan LCP schaden
Moderne afbeeldingsformaten zoals AVIF of WebP kunnen een betere compressie bieden dan de veelgebruikte JPEG- en PNG-formaten. Betere compressie verkleint de bestandsgrootte in sommige gevallen met 25% tot 50% voor dezelfde kwaliteit van de afbeelding. Deze reductie leidt tot snellere downloads met minder dataverbruik. De app moet moderne beeldformaten aanbieden aan browsers die deze formaten ondersteunen.
Het laden van onnodige afbeeldingen doet LCP pijn
Afbeeldingen onder de vouw of niet in de viewport worden niet aan de gebruiker weergegeven wanneer de pagina wordt geladen. Ze kunnen worden uitgesteld, zodat ze niet bijdragen aan het LCP en dit vertragen. Lazy-loading kan worden gebruikt om dergelijke afbeeldingen later te laden terwijl de gebruiker ernaartoe scrollt.
Optimalisatie-uitdagingen
Teams kunnen de prestatiekosten als gevolg van de eerder genoemde problemen evalueren en best practice-oplossingen implementeren om deze te overwinnen. In de praktijk gebeurt dit echter vaak niet en inefficiënte afbeeldingen blijven het internet vertragen. Mogelijke redenen hiervoor zijn onder meer:
- Prioriteiten : Webontwikkelaars hebben meestal de neiging zich te concentreren op code, JavaScript en gegevensoptimalisatie. Als zodanig zijn ze zich mogelijk niet bewust van problemen met afbeeldingen of hoe ze deze kunnen optimaliseren. Afbeeldingen gemaakt door ontwerpers of geüpload door gebruikers staan mogelijk niet hoog op de prioriteitenlijst.
- Out-of-the-box oplossing : Zelfs als ontwikkelaars zich bewust zijn van de nuances van beeldoptimalisatie, kan het ontbreken van een alles-in-één out-of-the-box oplossing voor hun framework of tech-stack een afschrikmiddel zijn.
- Dynamische afbeeldingen : Naast statische afbeeldingen die deel uitmaken van de applicatie, worden dynamische afbeeldingen geüpload door gebruikers of afkomstig uit externe databases of CMS's. Het kan een uitdaging zijn om de grootte van dergelijke afbeeldingen te definiëren als de bron van de afbeelding dynamisch is.
- Overbelasting van markeringen : Oplossingen voor het opnemen van de afbeeldingsgrootte of
srcset
voor verschillende formaten vereisen extra markeringen voor elke afbeelding, wat vervelend kan zijn. Hetsrcset
-attribuut werd in 2014 geïntroduceerd, maar wordt tegenwoordig door slechts 26,5% van de websites gebruikt . Bij gebruik vansrcset
moeten ontwikkelaars afbeeldingen in verschillende formaten maken. Tools zoals just-gimme-an-img kunnen helpen, maar moeten voor elke afbeelding handmatig worden gebruikt. - Browserondersteuning : Moderne afbeeldingsformaten zoals AVIF en WebP creëren kleinere afbeeldingsbestanden, maar hebben speciale behandeling nodig in browsers die deze niet ondersteunen. Ontwikkelaars moeten strategieën gebruiken zoals contentonderhandeling of het
<picture
> -element, zodat afbeeldingen aan alle browsers worden aangeboden. - Complicaties voor Lazy Loading : Er zijn meerdere technieken en bibliotheken beschikbaar om lazyloading voor afbeeldingen onder de vouw te implementeren. Het kiezen van de beste kan een uitdaging zijn. Ontwikkelaars weten mogelijk ook niet wat de beste afstand tot de "vouw" is om uitgestelde afbeeldingen te laden. Verschillende viewport-groottes op apparaten kunnen dit verder compliceren.
- Veranderend landschap : Nu browsers nieuwe HTML- of CSS-functies beginnen te ondersteunen om de prestaties te verbeteren, kan het voor ontwikkelaars moeilijk zijn om ze allemaal te evalueren. Chrome introduceert bijvoorbeeld de functie Fetch Priority als een Origin-proefversie . Het kan worden gebruikt om de prioriteit van specifieke afbeeldingen op de pagina te verhogen. Over het algemeen zouden ontwikkelaars het gemakkelijker vinden als dergelijke verbeteringen op componentniveau zouden worden geëvalueerd en geïmplementeerd.
Beeldcomponent als oplossing
De beschikbare mogelijkheden om afbeeldingen te optimaliseren en de uitdagingen bij het individueel implementeren ervan voor elke toepassing brachten ons op het idee van een beeldcomponent. Een afbeeldingscomponent kan best practices inkapselen en afdwingen. Door het <img>
-element te vervangen door een afbeeldingscomponent kunnen ontwikkelaars hun problemen met de beeldprestaties beter aanpakken.
Het afgelopen jaar hebben we met het Next.js- framework gewerkt om hun Image-component te ontwerpen en te implementeren . Het kan als volgt worden gebruikt als drop-in vervanging voor de bestaande <img>
-elementen in Next.js-apps.
// Before with <img> element:
function Logo() {
return <img src="/logo.jpg" alt="logo" height="200" width="100" />
}
// After with image component:
import Image from 'next/image'
function Logo() {
return <Image src="/logo.jpg" alt="logo" height="200" width="100" />
}
De component probeert beeldgerelateerde problemen generiek aan te pakken via een rijke reeks functies en principes. Het bevat ook opties waarmee ontwikkelaars het kunnen aanpassen aan verschillende afbeeldingsvereisten.
Bescherming tegen lay-outverschuivingen
Zoals eerder besproken veroorzaken afbeeldingen zonder formaat lay-outverschuivingen en dragen ze bij aan CLS. Bij het gebruik van de Next.js Image-component moeten ontwikkelaars een afbeeldingsgrootte opgeven met behulp van de kenmerken width
en height
om lay-outverschuivingen te voorkomen. Als de grootte onbekend is, moeten ontwikkelaars layout=fill
opgeven om een afbeelding zonder grootte weer te geven die zich in een container met grootte bevindt. Als alternatief kunt u statische afbeeldingen importeren om de grootte van de daadwerkelijke afbeelding op de harde schijf tijdens het bouwen op te halen en deze in de afbeelding op te nemen.
// Image component with width and height specified
<Image src="/logo.jpg" alt="logo" height="200" width="100" />
// Image component with layout specified
<Image src="/hero.jpg" layout="fill" objectFit="cover" alt="hero" />
// Image component with image import
import Image from 'next/image'
import logo from './logo.png'
function Logo() {
return <Image src={logo} alt="logo" />
}
Omdat ontwikkelaars de component Afbeelding niet onverkleind kunnen gebruiken, zorgt het ontwerp ervoor dat ze de tijd nemen om de afbeeldingsgrootte te overwegen en lay-outverschuivingen te voorkomen.
Faciliteer het reactievermogen
Om afbeeldingen op verschillende apparaten responsief te maken, moeten ontwikkelaars de kenmerken srcset
sizes
instellen in het <img>
-element. We wilden deze inspanning verminderen met de component Afbeelding. We hebben de component Next.js Image ontworpen om de attribuutwaarden slechts één keer per toepassing in te stellen. We passen ze toe op alle exemplaren van de component Afbeelding op basis van de lay-outmodus. We hebben een driedelige oplossing bedacht:
-
deviceSizes
eigenschap: deze eigenschap kan worden gebruikt om breekpunten eenmalig te configureren op basis van de apparaten die gemeenschappelijk zijn voor het gebruikersbestand van de toepassing. De standaardwaarden voor breekpunten zijn opgenomen in het configuratiebestand. -
imageSizes
eigenschap: Dit is ook een configureerbare eigenschap die wordt gebruikt om de afbeeldingsgrootten op te halen die overeenkomen met de breekpunten van de apparaatgrootte. -
layout
-kenmerk in elke afbeelding: dit wordt gebruikt om aan te geven hoe de eigenschappendeviceSizes
enimageSizes
voor elke afbeelding moeten worden gebruikt. De ondersteunde waarden voor de lay-outmodus zijnfixed
,fill
,intrinsic
enresponsive
Wanneer een afbeelding wordt opgevraagd met de lay-outmodi responsive of fill , identificeert Next.js de afbeelding die moet worden weergegeven op basis van de grootte van het apparaat dat de pagina opvraagt en worden de srcset
en sizes
in de afbeelding op de juiste manier ingesteld.
De volgende vergelijking laat zien hoe de lay-outmodus kan worden gebruikt om de grootte van de afbeelding op verschillende schermen te regelen. We hebben een demo-afbeelding gebruikt die is gedeeld in de Next.js-documenten, bekeken op een telefoon en een standaardlaptop.
Laptopscherm | Telefoonscherm |
---|---|
Lay-out = Intrinsiek: schaalt omlaag om te passen in de breedte van de container op kleinere viewports. Schaalt niet verder dan de intrinsieke grootte van de afbeelding op een grotere viewport. Containerbreedte staat op 100% | |
![]() | ![]() |
Layout = Opgelost: afbeelding reageert niet. Breedte en hoogte worden op dezelfde manier vastgesteld als ` | |
![]() | ![]() |
Lay-out = Responsief: Schaal omlaag of omhoog, afhankelijk van de breedte van de container op verschillende viewports, waarbij de beeldverhouding behouden blijft. | |
![]() | ![]() |
Indeling = Opvulling: breedte en hoogte uitgerekt om de bovenliggende container te vullen. (De breedte van de bovenliggende <div> is in dit voorbeeld ingesteld op 300*500) | |
![]() | ![]() |
Zorg voor ingebouwde lazyloading
De component Image biedt standaard een ingebouwde, performante lazyload- oplossing. Als je het <img>
-element gebruikt, zijn er een paar opties voor lazy load, maar deze hebben allemaal nadelen waardoor ze lastig te gebruiken zijn. Een ontwikkelaar kan een van de volgende lazyload-benaderingen gebruiken:
- Geef het
loading
op: Dit wordt ondersteund in alle moderne browsers . - Gebruik de Intersection Observer API : het bouwen van een aangepaste lazy-loading-oplossing vereist inspanning en een doordacht ontwerp en implementatie. Ontwikkelaars hebben hier misschien niet altijd de tijd voor.
- Importeer een bibliotheek van derden om afbeeldingen lui te laden: Er kan extra inspanning nodig zijn om een geschikte bibliotheek van derden voor lui laden te evalueren en te integreren.
In de component Next.js Image is het laden standaard ingesteld op "lazy"
. Lazyloading wordt geïmplementeerd met behulp van Intersection Observer, dat beschikbaar is in de meeste moderne browsers . Ontwikkelaars hoeven niets extra's te doen om dit in te schakelen, maar kunnen het indien nodig uitschakelen.
Belangrijke afbeeldingen vooraf laden
Heel vaak zijn LCP-elementen afbeeldingen, en grote afbeeldingen kunnen LCP vertragen. Het is een goed idee om kritieke afbeeldingen vooraf te laden, zodat de browser die afbeelding eerder kan ontdekken. Wanneer u een <img>
-element gebruikt, kan er als volgt een preload-hint in de HTML-header worden opgenomen.
<link rel="preload" as="image" href="important.png">
Een goed ontworpen afbeeldingscomponent zou een manier moeten bieden om de laadvolgorde van afbeeldingen aan te passen, ongeacht het gebruikte raamwerk. In het geval van de Next.js Image-component kunnen ontwikkelaars een afbeelding aangeven die een goede kandidaat is voor vooraf laden met behulp van het priority
van de images-component.
<Image src="/hero.jpg" alt="hero" height="400" width="200" priority />
Het toevoegen van een priority
vereenvoudigt de opmaak en is handiger in gebruik. Ontwikkelaars van afbeeldingscomponenten kunnen ook opties verkennen om heuristieken toe te passen om het vooraf laden van afbeeldingen boven de vouw op de pagina te automatiseren die aan specifieke criteria voldoen.
Stimuleer hoogwaardige beeldhosting
Image CDN's worden aanbevolen voor het automatiseren van beeldoptimalisatie, en ze ondersteunen ook moderne beeldformaten zoals WebP en AVIF. De Next.js Image-component gebruikt standaard een image-CDN met behulp van een loader-architectuur . In het volgende voorbeeld ziet u dat de lader configuratie van het CDN in het configuratiebestand Next.js mogelijk maakt.
module.exports = {
images: {
loader: 'imgix',
path: 'https://ImgApp/imgix.net',
},
}
Met deze configuratie kunnen ontwikkelaars relatieve URL's in de afbeeldingsbron gebruiken, en het raamwerk zal de relatieve URL samenvoegen met het CDN-pad om de absolute URL te genereren. Populaire afbeeldings-CDN's zoals Imgix , Cloudinary en Akamai worden ondersteund. De architectuur ondersteunt het gebruik van een aangepaste cloudprovider door een aangepaste loader
voor de app te implementeren.
Ondersteuning van zelfgehoste afbeeldingen
Er kunnen situaties zijn waarin websites geen afbeeldings-CDN's kunnen gebruiken. In dergelijke gevallen moet een afbeeldingscomponent zelf-gehoste afbeeldingen ondersteunen. De Next.js Image-component gebruikt een afbeeldingsoptimalisatie als ingebouwde afbeeldingsserver die een CDN-achtige API biedt. De optimalisatie gebruikt Sharp voor transformaties van productieafbeeldingen als deze op de server is geïnstalleerd. Deze bibliotheek is een goede keuze voor iedereen die zijn eigen pijplijn voor beeldoptimalisatie wil opbouwen.
Ondersteuning van progressieve belasting
Progressive Loading is een techniek die wordt gebruikt om de interesse van gebruikers te behouden door een tijdelijke afbeelding weer te geven, meestal van aanzienlijk lagere kwaliteit, terwijl de werkelijke afbeelding wordt geladen. Het verbetert de waargenomen prestaties en verbetert de gebruikerservaring. Het kan worden gebruikt in combinatie met luie laden voor onder-de-voudige afbeeldingen of voor boven-de-voudige afbeeldingen.
De volgende.js -beeldcomponent ondersteunt progressieve lading voor de afbeelding via de placeholder -eigenschap. Dit kan worden gebruikt als LQIP (lage kwaliteit placeholder) voor het weergeven van een lage kwaliteit of wazig beeld terwijl de werkelijke afbeelding wordt geladen.
Invloed
Met al deze optimalisaties opgenomen, hebben we succes gezien met de volgende.js beeldcomponent in de productie en werken we ook samen met andere technische stapels op vergelijkbare beeldcomponenten.
Toen Leboncoin hun oude JavaScript -frontend migreerde naar Next.js , hebben ze ook hun beeldpijplijn geüpgraded om de volgende.js -beeldcomponent te gebruiken. Op een pagina die migreerde van <img>
naar Next/Image, ging LCP van 2,4S naar 1,7s. De totale afbeeldings-bytes gedownload voor de pagina gingen van 663KB naar 326 kb (met ~ 100 kb lui-geladen afbeelding bytes).
Geleerde lessen
Iedereen die een volgende.js -app maakt, kan profiteren van het gebruik van de volgende.js -beeldcomponent voor optimalisatie. Als u echter soortgelijke prestatiebegrepen wilt bouwen voor een ander raamwerk of CMS, zijn de volgende lessen die we onderweg hebben geleerd die nuttig kunnen zijn.
Veiligheidskleppen kunnen meer kwaad dan goed veroorzaken
In een vroege release van de volgende.js -beeldcomponent hebben we een unsized
attribuut verstrekt waarmee ontwikkelaars de grootte -eis konden omzeilen en afbeeldingen kunnen gebruiken met niet -gespecificeerde dimensies. We dachten dat dit een noodzakelijk zou zijn in gevallen waarin het onmogelijk was om van tevoren de hoogte of breedte van het beeld te kennen. We hebben echter opgemerkt dat gebruikers het unsized
kenmerk in GitHub-problemen aanbevelen als een catch-all-oplossing voor problemen met de grootte-eis, zelfs in gevallen waarin ze het probleem konden oplossen op manieren die geen CL's verergeren. Vervolgens hebben we het unsized
kenmerk afgeschaft en verwijderd.
Scheid nuttige wrijving van zinloze ergernis
De vereiste voor het formaat van een afbeelding is een voorbeeld van 'nuttige wrijving'. Het beperkt het gebruik van de component, maar het biedt een grote prestatievoordelen in ruil. Gebruikers zullen de beperking gemakkelijk accepteren als ze een duidelijk beeld hebben van de potentiële prestatievoordelen. Daarom is het de moeite waard om deze afweging in de documentatie en ander gepubliceerd materiaal over de component uit te leggen.
U kunt echter oplossingen voor dergelijke wrijving vinden zonder prestaties op te offeren. Tijdens de ontwikkeling van de volgende.js -beeldcomponent hebben we bijvoorbeeld klachten ontvangen dat het vervelend was om maten op te zoeken voor lokaal opgeslagen afbeeldingen. We hebben statische afbeelding -import toegevoegd, die dit proces stroomlijnen door automatisch afmetingen voor lokale afbeeldingen op te halen tijdens de bouwtijd met behulp van een Babel -plug -in.
Een balans vinden tussen gemaksfuncties en prestatie -optimalisaties
Als uw beeldcomponent niets anders doet dan "nuttige wrijving" opleggen aan zijn gebruikers, zullen ontwikkelaars het niet willen gebruiken. We hebben geconstateerd dat hoewel prestatiekenmerken zoals afbeeldingsafmetingen en automatische generatie van srcset
-waarden de belangrijkste waren. Ontwikkelaarsgerichte gemaksfuncties zoals automatische luie laden en ingebouwde wazige tijdelijke aanduidingen brachten ook interesse in de volgende.js-beeldcomponent.
Stel een routekaart in voor functies om de adoptie te stimuleren
Het bouwen van een oplossing die perfect werkt voor alle situaties is erg moeilijk. Het kan verleidelijk zijn om iets te ontwerpen dat goed werkt voor 75% van de mensen en vervolgens de andere 25% te vertellen dat "in deze gevallen deze component niet voor jou is."
In de praktijk blijkt deze strategie op gespannen voet te staan met uw doelen als componentontwerper. U wilt dat ontwikkelaars uw component aannemen om te profiteren van de prestatievoordelen. Dit is moeilijk om te doen als er een contingent van gebruikers is die niet in staat zijn om te migreren en zich buiten het gesprek te verlaten. Ze zullen waarschijnlijk teleurstelling uiten, wat leidt tot negatieve percepties die de acceptatie beïnvloeden.
Het is raadzaam om een routekaart te hebben voor uw component die alle redelijke use -cases op de lange termijn bestrijkt. Het helpt ook om expliciet te zijn in de documentatie over wat niet wordt ondersteund en waarom om verwachtingen te stellen over de problemen die de component bedoeld is om op te lossen.
Conclusie
Beeldgebruik en optimalisatie is ingewikkeld. Ontwikkelaars moeten de balans vinden tussen prestaties en kwaliteit van afbeeldingen en tegelijkertijd een geweldige gebruikerservaring waarborgen. Dit maakt beeldoptimalisatie een dure, hoge impact onderneming.
In plaats van elke app het wiel elke keer opnieuw uit te vinden, kwamen we met een best practices-sjabloon die ontwikkelaars, frameworks en andere tech-stacks konden gebruiken als referentie voor hun eigen implementaties. Deze ervaring zal inderdaad waardevol blijken te zijn omdat we andere kaders ondersteunen, op hun beeldcomponenten.
De volgende.js -beeldcomponent heeft de prestaties met succes verbeterd in volgende.js -applicaties, waardoor de gebruikerservaring wordt verbeterd. Wij geloven dat het een geweldig model is dat goed zou werken in het bredere ecosysteem, en we zouden graag horen van ontwikkelaars die dit model in hun projecten willen overnemen.
,Een beeldcomponent omvat de best practices van prestaties en biedt een out-of-the-box oplossing om afbeeldingen te optimaliseren.
Afbeeldingen zijn een veel voorkomende bron van knelpunten voor prestaties voor webtoepassingen en een belangrijk focusgebied voor optimalisatie. Niet -geoptimaliseerde afbeeldingen dragen bij aan paginablood en zijn goed voor meer dan 70% van het totale pagina -gewicht in bytes op het 90e percentiel. Meerdere manieren om afbeeldingen te optimaliseren, vragen voor een intelligente "beeldcomponent" met prestatieoplossingen ingebakken als standaard.
Het Aurora -team werkte samen met Next.js om zo'n component te bouwen. Het doel was om een geoptimaliseerde beeldsjabloon te maken die webontwikkelaars verder konden aanpassen. De component dient als een goed model en stelt een standaard voor voor het bouwen van beeldcomponenten in andere frameworks, content management systems (CMS) en tech-stacks. We hebben samengewerkt aan een soortgelijk onderdeel voor nuxt.js en we werken met Angular aan beeldoptimalisatie in toekomstige versies. Dit bericht bespreekt hoe we de volgende.js -beeldcomponent hebben ontworpen en de lessen die we onderweg hebben geleerd.
Problemen met beeldoptimalisatie en kansen
Afbeeldingen beïnvloeden niet alleen de prestaties, maar ook op zaken. Het aantal afbeeldingen op een pagina was de op een na grootste voorspeller van conversies van gebruikers die websites bezoeken. Sessies waarin gebruikers werden geconverteerd, hadden 38% minder afbeeldingen dan sessies waar ze niet converteerden. Lighthouse geeft meer dan meerdere mogelijkheden om afbeeldingen te optimaliseren en webvitals te verbeteren als onderdeel van de best practices -audit. Sommige van de gemeenschappelijke ruimtes waar afbeeldingen de kernwebvitalen kunnen beïnvloeden en gebruikerservaring als volgt zijn.
Onzijdige beelden doen CLS pijn
Afbeeldingen die worden geserveerd zonder hun gespecificeerde grootte, kunnen de instabiliteit van de lay -out veroorzaken en bijdragen aan een hoge cumulatieve lay -outverschuiving ( CLS ). Het instellen van de width
en height
-attributen op <img>
elementen kunnen helpen om lay -outverschuivingen te voorkomen. Bijvoorbeeld:
<img src="flower.jpg" width="360" height="240">
De breedte en hoogte moeten zodanig worden ingesteld dat de beeldverhouding van het weergegeven beeld dicht bij de natuurlijke beeldverhouding ligt. Een significant verschil in de beeldverhouding kan ertoe leiden dat het beeld er vervormd uitziet. Een relatief nieuwe eigenschap waarmee u aspectenversterking in CSS kunt opgeven, kan helpen om afbeeldingen reactief te vergroten en tegelijkertijd CLS te voorkomen.
Grote afbeeldingen kunnen LCP pijn doen
Hoe groter de bestandsgrootte van een afbeelding, hoe langer het duurt om te downloaden. Een grote afbeelding kan het "held" -afbeelding zijn voor de pagina of het belangrijkste element in het viewport dat verantwoordelijk is voor het activeren van de grootste contentful verf ( LCP ). Een afbeelding die deel uitmaakt van de kritieke inhoud en lang duurt om te downloaden, zal de LCP vertragen.
In veel gevallen kunnen ontwikkelaars beeldgroottes verminderen door een betere compressie en het gebruik van responsieve afbeeldingen. De srcset
en sizes
-kenmerken van het <img>
-element helpen om afbeeldingsbestanden met verschillende maten te verstrekken. De browser kan vervolgens de rechter kiezen, afhankelijk van de schermgrootte en -resolutie.
Slechte beeldcompressie kan LCP schaden
Moderne beeldformaten zoals AVIF of WEBP kunnen een betere compressie bieden dan veelgebruikte JPEG- en PNG -formaten. Betere compressie vermindert de bestandsgrootte in sommige gevallen met 25% tot 50% voor dezelfde kwaliteit van de afbeelding. Deze reductie leidt tot snellere downloads met minder gegevensverbruik. De app moet moderne beeldformaten bedienen voor browsers die deze formaten ondersteunen.
Het laden van onnodige afbeeldingen doet LCP pijn
Afbeeldingen onder de vouw of niet in het viewport worden niet aan de gebruiker weergegeven wanneer de pagina wordt geladen. Ze kunnen worden uitgesteld zodat ze niet bijdragen aan de LCP en deze vertragen. Lazy-loading kan worden gebruikt om dergelijke afbeeldingen later te laden terwijl de gebruiker naar hen toeschrijft.
Optimalisatie -uitdagingen
Teams kunnen de prestatiekosten evalueren vanwege de eerder vermelde problemen en best practices oplossingen implementeren om ze te overwinnen. Dit gebeurt echter vaak niet in de praktijk en inefficiënte afbeeldingen blijven het web vertragen. Mogelijke redenen hiervoor zijn:
- Prioriteiten : webontwikkelaars hebben de neiging zich meestal te concentreren op code, JavaScript en data -optimalisatie. Als zodanig zijn ze mogelijk niet op de hoogte van problemen met afbeeldingen of hoe ze kunnen worden geoptimaliseerd. Afbeeldingen gemaakt door ontwerpers of geüpload door gebruikers zijn mogelijk niet hoog in de lijst met prioriteiten.
- Out-of-the-box oplossing : zelfs als ontwikkelaars zich bewust zijn van de nuances van beeldoptimalisatie, kan de afwezigheid van een alles-in-één out-of-the-box oplossing voor hun kader of tech-stapel een afschrikmiddel zijn.
- Dynamische afbeeldingen : naast statische afbeeldingen die deel uitmaken van de toepassing, worden dynamische afbeeldingen geüpload door gebruikers of afkomstig van externe databases of CMS's. Het kan een uitdaging zijn om de grootte van dergelijke afbeeldingen te definiëren waar de bron van de afbeelding dynamisch is.
- Markup -overbelasting : oplossingen voor het opnemen van de beeldgrootte of
srcset
voor verschillende maten vereisen extra markup voor elke afbeelding, die vervelend kunnen zijn. Hetsrcset
-kenmerk werd in 2014 geïntroduceerd, maar wordt vandaag slechts 26,5% van de websites gebruikt . Bij het gebruik vansrcset
moeten ontwikkelaars afbeeldingen maken in verschillende maten. Tools zoals Just-Gimme-an-IMG kunnen helpen, maar moeten voor elke afbeelding handmatig worden gebruikt. - Browserondersteuning : moderne beeldformaten zoals AVIF en Webp maken kleinere afbeeldingsbestanden, maar hebben speciale afhandeling nodig voor browsers die ze niet ondersteunen. Ontwikkelaars moeten strategieën gebruiken, zoals inhoudsonderhandelingen of het element
<picture
zodat afbeeldingen aan alle browsers worden geserveerd. - Luie laadcomplicaties : er zijn meerdere technieken en bibliotheken beschikbaar om lui-loading te implementeren voor onder de voudige afbeeldingen. De beste kiezen kan een uitdaging zijn. Ontwikkelaars kennen mogelijk ook niet de beste afstand van de "vouw" om uitgestelde afbeeldingen te laden. Verschillende viewportgroottes op apparaten kunnen dit verder ingewikkelder maken.
- Veranderend landschap : omdat browsers nieuwe HTML- of CSS -functies beginnen te ondersteunen om de prestaties te verbeteren, kan het voor ontwikkelaars moeilijk zijn om elk van hen te evalueren. Chrome introduceert bijvoorbeeld de Fetch Priority -functie als een oorsprongstroef . Het kan worden gebruikt om de prioriteit van specifieke afbeeldingen op de pagina te stimuleren. Over het algemeen zouden ontwikkelaars het gemakkelijker vinden als dergelijke verbeteringen op componentniveau werden geëvalueerd en geïmplementeerd.
Beeldcomponent als oplossing
De mogelijkheden die beschikbaar zijn om afbeeldingen te optimaliseren en de uitdagingen om ze afzonderlijk te implementeren voor elke applicatie leidde ons naar het idee van een beeldcomponent. Een beeldcomponent kan best practices inkapselen en afdwingen. Door het <img>
-element te vervangen door een afbeeldingscomponent, kunnen ontwikkelaars hun beeldprestatievoorziening beter aanpakken.
In het afgelopen jaar hebben we samengewerkt met het volgende.js -framework om hun beeldcomponent te ontwerpen en te implementeren . Het kan worden gebruikt als een drop-in vervanging voor de bestaande <img>
-elementen in volgende.js-apps als volgt.
// Before with <img> element:
function Logo() {
return <img src="/logo.jpg" alt="logo" height="200" width="100" />
}
// After with image component:
import Image from 'next/image'
function Logo() {
return <Image src="/logo.jpg" alt="logo" height="200" width="100" />
}
De component probeert de beeldgerelateerde problemen in het algemeen aan te pakken via een rijke set functies en principes. Het bevat ook opties waarmee ontwikkelaars het kunnen aanpassen voor verschillende beeldvereisten.
Bescherming tegen lay -outverschuivingen
Zoals eerder besproken, veroorzaken niet -gesize beelden lay -outverschuivingen en dragen ze bij aan CLS. Wanneer u de volgende.js -afbeeldingscomponent gebruikt, moeten ontwikkelaars een beeldgrootte verstrekken met behulp van de width
en height
-attributen om lay -outverschuivingen te voorkomen. Als de grootte onbekend is, moeten ontwikkelaars layout=fill
opgeven om een niet -groot beeld te bedienen dat in een container zit. Als alternatief kunt u statische beeldimport gebruiken om de grootte van de werkelijke afbeelding op de harde schijf tijdens de bouwtijd op te halen en in de afbeelding op te nemen.
// Image component with width and height specified
<Image src="/logo.jpg" alt="logo" height="200" width="100" />
// Image component with layout specified
<Image src="/hero.jpg" layout="fill" objectFit="cover" alt="hero" />
// Image component with image import
import Image from 'next/image'
import logo from './logo.png'
function Logo() {
return <Image src={logo} alt="logo" />
}
Aangezien ontwikkelaars de beeldcomponent niet onrecht kunnen gebruiken, zorgt het ontwerp ervoor dat ze de tijd nemen om beeldomvang te overwegen en lay -outverschuivingen te voorkomen.
De responsiviteit vergemakkelijken
Om afbeeldingen op verschillende apparaten te laten responsief maken, moeten ontwikkelaars de srcset
en sizes
-attributen in het element <img>
instellen. We wilden deze inspanning verminderen met de beeldcomponent. We hebben de volgende.js -afbeeldingscomponent ontworpen om de attribuutwaarden slechts eenmaal per toepassing in te stellen. We passen ze toe op alle instanties van de beeldcomponent op basis van de lay -outmodus. We hebben een driedelige oplossing bedacht:
- Eigenschap
deviceSizes
: deze eigenschap kan worden gebruikt om breekpunten eenmalig te configureren op basis van de apparaten die gebruikelijk zijn voor het gebruikersbasis van de applicatie. De standaardwaarden voor breekpunten zijn opgenomen in het configuratiebestand. -
imageSizes
-eigenschap: dit is ook een configureerbare eigenschap die wordt gebruikt om de beeldgroottes te krijgen die overeenkomen met breekpunten van apparaatgrootte. -
layout
-kenmerk in elke afbeelding: dit wordt gebruikt om aan te geven hoe dedeviceSizes
enimageSizes
eigenschappen voor elke afbeelding kunnen worden gebruikt. De ondersteunde waarden voor de lay -outmodus zijnfixed
,fill
,intrinsic
enresponsive
Wanneer een afbeelding wordt aangevraagd met lay -outmodi die reageren of vullen , identificeert Next.js de te dienen afbeelding op basis van de grootte van het apparaat dat de pagina aanvraagt en stelt de srcset
en sizes
in de afbeelding op de juiste manier in.
De volgende vergelijking laat zien hoe de lay -outmodus kan worden gebruikt om de grootte van de afbeelding op verschillende schermen te regelen. We hebben een demo -afbeelding gebruikt gedeeld in de volgende.js -documenten, bekeken op een telefoon en een standaard laptop.
Laptopscherm | Telefoonscherm |
---|---|
Layout = intrinsiek: schalen naar beneden om de breedte van de container op kleinere viewports te passen. Schaalt niet verder dan de intrinsieke grootte van het beeld op een groter viewport. De containerbreedte is 100% | |
![]() | ![]() |
Lay -out = opgelost: afbeelding reageert niet. Breedte en hoogte zijn opgelost, vergelijkbaar met ` | |
![]() | ![]() |
Layout = responsief: schaal af of schaalt op, afhankelijk van de breedte van de container op verschillende viewports, het handhaven van de beeldverhouding. | |
![]() | ![]() |
Layout = vulling: breedte en hoogte uitgerekt om de bovenliggende container te vullen. (Ouder <div> breedte is ingesteld op 300*500 in dit voorbeeld) | |
![]() | ![]() |
Zorg voor ingebouwde luie laden
De beeldcomponent biedt standaard een ingebouwde, performante luie laadoplossing . Wanneer u het element <img>
gebruikt, zijn er een paar opties voor luie laden, maar ze hebben allemaal nadelen die ze lastig maken om te gebruiken. Een ontwikkelaar kan een van de volgende luie laadbenaderingen aannemen:
- Geef het
loading
op: dit wordt ondersteund voor alle moderne browsers . - Gebruik de Intersection Observer API : het bouwen van een op maat gemaakte oplossing voor luie laden vereist inspanning en een doordacht ontwerp en implementatie. Ontwikkelaars hebben hier misschien niet altijd de tijd voor.
- Importeer een bibliotheek van derden voor lage load-afbeeldingen: extra inspanning kan nodig zijn om een geschikte bibliotheek van derden te evalueren en te integreren voor lui laden.
In de volgende.js -afbeeldingscomponent is het laden standaard ingesteld op "lazy"
. Lazy laden wordt geïmplementeerd met behulp van Intersection Observer, die beschikbaar is voor de meeste moderne browsers . Ontwikkelaars zijn niet verplicht om iets extra's te doen om het in te schakelen, maar ze kunnen het uitschakelen wanneer dat nodig is.
Voorgeladen belangrijke afbeeldingen
Heel vaak zijn LCP -elementen afbeeldingen en kunnen grote afbeeldingen LCP vertragen. Het is een goed idee om kritieke afbeeldingen voor te laden, zodat de browser die afbeelding eerder kan ontdekken. Bij gebruik van een <img>
-element kan een voorbelastingstip als volgt worden opgenomen in de HTML -kop.
<link rel="preload" as="image" href="important.png">
Een goed ontworpen beeldcomponent moet een manier bieden om de laadvolgorde van afbeeldingen aan te passen, ongeacht het gebruikte raamwerk. In het geval van de volgende.js -beeldcomponent kunnen ontwikkelaars een afbeelding aangeven die een goede kandidaat is voor voorbelasting met behulp van het priority
van de afbeeldingencomponent.
<Image src="/hero.jpg" alt="hero" height="400" width="200" priority />
Het toevoegen van een priority
vereenvoudigt de markup en is handiger in gebruik. Ontwikkelaars van afbeeldingencomponenten kunnen ook opties verkennen om heuristieken toe te passen om vooraf laden te automatiseren voor boven-de-voudige afbeeldingen op de pagina die voldoen aan specifieke criteria.
Moedig krachtige beeldhosting aan
Afbeelding CDN's worden aanbevolen voor het automatiseren van beeldoptimalisatie en ondersteunen ook moderne beeldformaten zoals WEBP en AVIF. De volgende.js -afbeeldingscomponent gebruikt standaard een afbeelding CDN met behulp van een laderarchitectuur . Het volgende voorbeeld laat zien dat de lader de configuratie van de CDN mogelijk maakt in het volgende.js -configuratiebestand.
module.exports = {
images: {
loader: 'imgix',
path: 'https://ImgApp/imgix.net',
},
}
Met deze configuratie kunnen ontwikkelaars relatieve URL's in de beeldbron gebruiken en het framework zal de relatieve URL samenvatten met het CDN -pad om de absolute URL te genereren. Populaire afbeelding CDN's zoals Imgix , Cloudinary en Akamai worden ondersteund. De architectuur ondersteunt het gebruik van een aangepaste cloudprovider door een aangepaste loader
-functie voor de app te implementeren.
Ondersteun zelf gehoste afbeeldingen
Er kunnen situaties zijn waarin websites geen afbeelding CDN's kunnen gebruiken. In dergelijke gevallen moet een beeldcomponent zelf gehost afbeeldingen ondersteunen. De volgende.js-beeldcomponent gebruikt een afbeeldingoptimalisatie als een ingebouwde beeldserver die een CDN-achtige API biedt. De optimizer gebruikt scherp voor productiebeeldtransformaties als deze op de server is geïnstalleerd. Deze bibliotheek is een goede keuze voor iedereen die zijn eigen pijplijn voor beeldoptimalisatie wil bouwen.
Ondersteuning progressieve lading
Progressive Loading is een techniek die wordt gebruikt om de interesse van gebruikers te behouden door een tijdelijke afbeelding weer te geven, meestal van aanzienlijk lagere kwaliteit, terwijl de werkelijke afbeelding wordt geladen. Het verbetert de waargenomen prestaties en verbetert de gebruikerservaring. Het kan worden gebruikt in combinatie met luie laden voor onder-de-voudige afbeeldingen of voor boven-de-voudige afbeeldingen.
De volgende.js -beeldcomponent ondersteunt progressieve lading voor de afbeelding via de placeholder -eigenschap. Dit kan worden gebruikt als een LQIP (lage kwaliteit placeholder) voor het weergeven van een lage kwaliteit of wazig beeld terwijl de werkelijke afbeelding wordt geladen.
Invloed
Met al deze optimalisaties opgenomen, hebben we succes gezien met de volgende.js beeldcomponent in de productie en werken we ook samen met andere technische stapels op vergelijkbare beeldcomponenten.
Toen Leboncoin hun oude JavaScript -frontend migreerde naar Next.js , hebben ze ook hun beeldpijplijn geüpgraded om de volgende.js -beeldcomponent te gebruiken. Op een pagina die migreerde van <img>
naar Next/Image, ging LCP van 2,4S naar 1,7s. De totale afbeeldings-bytes gedownload voor de pagina gingen van 663KB naar 326 kb (met ~ 100 kb lui-geladen afbeelding bytes).
Geleerde lessen
Iedereen die een volgende.js -app maakt, kan profiteren van het gebruik van de volgende.js -beeldcomponent voor optimalisatie. Als u echter soortgelijke prestatiebegrepen wilt bouwen voor een ander raamwerk of CMS, zijn de volgende lessen die we onderweg hebben geleerd die nuttig kunnen zijn.
Veiligheidskleppen kunnen meer kwaad dan goed veroorzaken
In een vroege release van de volgende.js -beeldcomponent hebben we een unsized
attribuut verstrekt waarmee ontwikkelaars de grootte -eis konden omzeilen en afbeeldingen kunnen gebruiken met niet -gespecificeerde dimensies. We dachten dat dit een noodzakelijk zou zijn in gevallen waarin het onmogelijk was om van tevoren de hoogte of breedte van het beeld te kennen. We hebben echter opgemerkt dat gebruikers het unsized
kenmerk in GitHub-problemen aanbevelen als een catch-all-oplossing voor problemen met de grootte-eis, zelfs in gevallen waarin ze het probleem konden oplossen op manieren die geen CL's verergeren. Vervolgens hebben we het unsized
kenmerk afgeschaft en verwijderd.
Scheid nuttige wrijving van zinloze ergernis
De vereiste voor het formaat van een afbeelding is een voorbeeld van 'nuttige wrijving'. Het beperkt het gebruik van de component, maar het biedt een grote prestatievoordelen in ruil. Gebruikers zullen de beperking gemakkelijk accepteren als ze een duidelijk beeld hebben van de potentiële prestatievoordelen. Daarom is het de moeite waard om deze afweging in de documentatie en ander gepubliceerd materiaal over de component uit te leggen.
U kunt echter oplossingen voor dergelijke wrijving vinden zonder prestaties op te offeren. Tijdens de ontwikkeling van de volgende.js -beeldcomponent hebben we bijvoorbeeld klachten ontvangen dat het vervelend was om maten op te zoeken voor lokaal opgeslagen afbeeldingen. We hebben statische afbeelding -import toegevoegd, die dit proces stroomlijnen door automatisch afmetingen voor lokale afbeeldingen op te halen tijdens de bouwtijd met behulp van een Babel -plug -in.
Een balans vinden tussen gemaksfuncties en prestatie -optimalisaties
Als uw beeldcomponent niets anders doet dan "nuttige wrijving" opleggen aan zijn gebruikers, zullen ontwikkelaars het niet willen gebruiken. We hebben geconstateerd dat hoewel prestatiekenmerken zoals afbeeldingsafmetingen en automatische generatie van srcset
-waarden de belangrijkste waren. Ontwikkelaarsgerichte gemaksfuncties zoals automatische luie laden en ingebouwde wazige tijdelijke aanduidingen brachten ook interesse in de volgende.js-beeldcomponent.
Stel een routekaart in voor functies om de adoptie te stimuleren
Het bouwen van een oplossing die perfect werkt voor alle situaties is erg moeilijk. Het kan verleidelijk zijn om iets te ontwerpen dat goed werkt voor 75% van de mensen en vervolgens de andere 25% te vertellen dat "in deze gevallen deze component niet voor jou is."
In de praktijk blijkt deze strategie op gespannen voet te staan met uw doelen als componentontwerper. U wilt dat ontwikkelaars uw component aannemen om te profiteren van de prestatievoordelen. Dit is moeilijk om te doen als er een contingent van gebruikers is die niet in staat zijn om te migreren en zich buiten het gesprek te verlaten. Ze zullen waarschijnlijk teleurstelling uiten, wat leidt tot negatieve percepties die de acceptatie beïnvloeden.
Het is raadzaam om een routekaart te hebben voor uw component die alle redelijke use -cases op de lange termijn bestrijkt. Het helpt ook om expliciet te zijn in de documentatie over wat niet wordt ondersteund en waarom om verwachtingen te stellen over de problemen die de component bedoeld is om op te lossen.
Conclusie
Beeldgebruik en optimalisatie is ingewikkeld. Ontwikkelaars moeten de balans vinden tussen prestaties en kwaliteit van afbeeldingen en tegelijkertijd een geweldige gebruikerservaring waarborgen. Dit maakt beeldoptimalisatie een dure, hoge impact onderneming.
In plaats van elke app het wiel elke keer opnieuw uit te vinden, kwamen we met een best practices-sjabloon die ontwikkelaars, frameworks en andere tech-stacks konden gebruiken als referentie voor hun eigen implementaties. Deze ervaring zal inderdaad waardevol blijken te zijn omdat we andere kaders ondersteunen, op hun beeldcomponenten.
De volgende.js -beeldcomponent heeft de prestaties met succes verbeterd in volgende.js -applicaties, waardoor de gebruikerservaring wordt verbeterd. Wij geloven dat het een geweldig model is dat goed zou werken in het bredere ecosysteem, en we zouden graag horen van ontwikkelaars die dit model in hun projecten willen overnemen.
,Een beeldcomponent omvat de best practices van prestaties en biedt een out-of-the-box oplossing om afbeeldingen te optimaliseren.
Afbeeldingen zijn een veel voorkomende bron van knelpunten voor prestaties voor webtoepassingen en een belangrijk focusgebied voor optimalisatie. Niet -geoptimaliseerde afbeeldingen dragen bij aan paginablood en zijn goed voor meer dan 70% van het totale pagina -gewicht in bytes op het 90e percentiel. Meerdere manieren om afbeeldingen te optimaliseren, vragen voor een intelligente "beeldcomponent" met prestatieoplossingen ingebakken als standaard.
Het Aurora -team werkte samen met Next.js om zo'n component te bouwen. Het doel was om een geoptimaliseerde beeldsjabloon te maken die webontwikkelaars verder konden aanpassen. De component dient als een goed model en stelt een standaard voor voor het bouwen van beeldcomponenten in andere frameworks, content management systems (CMS) en tech-stacks. We hebben samengewerkt aan een soortgelijk onderdeel voor nuxt.js en we werken met Angular aan beeldoptimalisatie in toekomstige versies. Dit bericht bespreekt hoe we de volgende.js -beeldcomponent hebben ontworpen en de lessen die we onderweg hebben geleerd.
Problemen met beeldoptimalisatie en kansen
Afbeeldingen beïnvloeden niet alleen de prestaties, maar ook op zaken. Het aantal afbeeldingen op een pagina was de op een na grootste voorspeller van conversies van gebruikers die websites bezoeken. Sessies waarin gebruikers werden geconverteerd, hadden 38% minder afbeeldingen dan sessies waar ze niet converteerden. Lighthouse geeft meer dan meerdere mogelijkheden om afbeeldingen te optimaliseren en webvitals te verbeteren als onderdeel van de best practices -audit. Sommige van de gemeenschappelijke ruimtes waar afbeeldingen de kernwebvitalen kunnen beïnvloeden en gebruikerservaring als volgt zijn.
Onzijdige beelden doen CLS pijn
Afbeeldingen die worden geserveerd zonder hun gespecificeerde grootte, kunnen de instabiliteit van de lay -out veroorzaken en bijdragen aan een hoge cumulatieve lay -outverschuiving ( CLS ). Het instellen van de width
en height
-attributen op <img>
elementen kunnen helpen om lay -outverschuivingen te voorkomen. Bijvoorbeeld:
<img src="flower.jpg" width="360" height="240">
De breedte en hoogte moeten zodanig worden ingesteld dat de beeldverhouding van het weergegeven beeld dicht bij de natuurlijke beeldverhouding ligt. Een significant verschil in de beeldverhouding kan ertoe leiden dat het beeld er vervormd uitziet. Een relatief nieuwe eigenschap waarmee u aspectenversterking in CSS kunt opgeven, kan helpen om afbeeldingen reactief te vergroten en tegelijkertijd CLS te voorkomen.
Grote afbeeldingen kunnen LCP pijn doen
Hoe groter de bestandsgrootte van een afbeelding, hoe langer het duurt om te downloaden. Een grote afbeelding kan het "held" -afbeelding zijn voor de pagina of het belangrijkste element in het viewport dat verantwoordelijk is voor het activeren van de grootste contentful verf ( LCP ). Een afbeelding die deel uitmaakt van de kritieke inhoud en lang duurt om te downloaden, zal de LCP vertragen.
In veel gevallen kunnen ontwikkelaars beeldgroottes verminderen door een betere compressie en het gebruik van responsieve afbeeldingen. De srcset
en sizes
-kenmerken van het <img>
-element helpen om afbeeldingsbestanden met verschillende maten te verstrekken. De browser kan vervolgens de rechter kiezen, afhankelijk van de schermgrootte en -resolutie.
Slechte beeldcompressie kan LCP schaden
Moderne beeldformaten zoals AVIF of WEBP kunnen een betere compressie bieden dan veelgebruikte JPEG- en PNG -formaten. Betere compressie vermindert de bestandsgrootte in sommige gevallen met 25% tot 50% voor dezelfde kwaliteit van de afbeelding. Deze reductie leidt tot snellere downloads met minder gegevensverbruik. De app moet moderne beeldformaten bedienen voor browsers die deze formaten ondersteunen.
Het laden van onnodige afbeeldingen doet LCP pijn
Afbeeldingen onder de vouw of niet in het viewport worden niet aan de gebruiker weergegeven wanneer de pagina wordt geladen. Ze kunnen worden uitgesteld zodat ze niet bijdragen aan de LCP en deze vertragen. Lazy-loading kan worden gebruikt om dergelijke afbeeldingen later te laden terwijl de gebruiker naar hen toeschrijft.
Optimalisatie -uitdagingen
Teams kunnen de prestatiekosten evalueren vanwege de eerder vermelde problemen en best practices oplossingen implementeren om ze te overwinnen. Dit gebeurt echter vaak niet in de praktijk en inefficiënte afbeeldingen blijven het web vertragen. Mogelijke redenen hiervoor zijn:
- Prioriteiten : webontwikkelaars hebben de neiging zich meestal te concentreren op code, JavaScript en data -optimalisatie. Als zodanig zijn ze mogelijk niet op de hoogte van problemen met afbeeldingen of hoe ze kunnen worden geoptimaliseerd. Afbeeldingen gemaakt door ontwerpers of geüpload door gebruikers zijn mogelijk niet hoog in de lijst met prioriteiten.
- Out-of-the-box oplossing : zelfs als ontwikkelaars zich bewust zijn van de nuances van beeldoptimalisatie, kan de afwezigheid van een alles-in-één out-of-the-box oplossing voor hun kader of tech-stapel een afschrikmiddel zijn.
- Dynamische afbeeldingen : naast statische afbeeldingen die deel uitmaken van de toepassing, worden dynamische afbeeldingen geüpload door gebruikers of afkomstig van externe databases of CMS's. Het kan een uitdaging zijn om de grootte van dergelijke afbeeldingen te definiëren waar de bron van de afbeelding dynamisch is.
- Markup -overbelasting : oplossingen voor het opnemen van de beeldgrootte of
srcset
voor verschillende maten vereisen extra markup voor elke afbeelding, die vervelend kunnen zijn. Hetsrcset
-kenmerk werd in 2014 geïntroduceerd, maar wordt vandaag slechts 26,5% van de websites gebruikt . Bij het gebruik vansrcset
moeten ontwikkelaars afbeeldingen maken in verschillende maten. Tools zoals Just-Gimme-an-IMG kunnen helpen, maar moeten voor elke afbeelding handmatig worden gebruikt. - Browserondersteuning : moderne beeldformaten zoals AVIF en Webp maken kleinere afbeeldingsbestanden, maar hebben speciale afhandeling nodig voor browsers die ze niet ondersteunen. Ontwikkelaars moeten strategieën gebruiken, zoals inhoudsonderhandelingen of het element
<picture
zodat afbeeldingen aan alle browsers worden geserveerd. - Luie laadcomplicaties : er zijn meerdere technieken en bibliotheken beschikbaar om lui-loading te implementeren voor onder de voudige afbeeldingen. De beste kiezen kan een uitdaging zijn. Ontwikkelaars kennen mogelijk ook niet de beste afstand van de "vouw" om uitgestelde afbeeldingen te laden. Verschillende viewportgroottes op apparaten kunnen dit verder ingewikkelder maken.
- Veranderend landschap : omdat browsers nieuwe HTML- of CSS -functies beginnen te ondersteunen om de prestaties te verbeteren, kan het voor ontwikkelaars moeilijk zijn om elk van hen te evalueren. Chrome introduceert bijvoorbeeld de Fetch Priority -functie als een oorsprongstroef . Het kan worden gebruikt om de prioriteit van specifieke afbeeldingen op de pagina te stimuleren. Over het algemeen zouden ontwikkelaars het gemakkelijker vinden als dergelijke verbeteringen op componentniveau werden geëvalueerd en geïmplementeerd.
Beeldcomponent als oplossing
De mogelijkheden die beschikbaar zijn om afbeeldingen te optimaliseren en de uitdagingen om ze afzonderlijk te implementeren voor elke applicatie leidde ons naar het idee van een beeldcomponent. Een beeldcomponent kan best practices inkapselen en afdwingen. Door het <img>
-element te vervangen door een afbeeldingscomponent, kunnen ontwikkelaars hun beeldprestatievoorziening beter aanpakken.
In het afgelopen jaar hebben we samengewerkt met het volgende.js -framework om hun beeldcomponent te ontwerpen en te implementeren . Het kan worden gebruikt als een drop-in vervanging voor de bestaande <img>
-elementen in volgende.js-apps als volgt.
// Before with <img> element:
function Logo() {
return <img src="/logo.jpg" alt="logo" height="200" width="100" />
}
// After with image component:
import Image from 'next/image'
function Logo() {
return <Image src="/logo.jpg" alt="logo" height="200" width="100" />
}
De component probeert de beeldgerelateerde problemen in het algemeen aan te pakken via een rijke set functies en principes. Het bevat ook opties waarmee ontwikkelaars het kunnen aanpassen voor verschillende beeldvereisten.
Bescherming tegen lay -outverschuivingen
Zoals eerder besproken, veroorzaken niet -gesize beelden lay -outverschuivingen en dragen ze bij aan CLS. Wanneer u de volgende.js -afbeeldingscomponent gebruikt, moeten ontwikkelaars een beeldgrootte verstrekken met behulp van de width
en height
-attributen om lay -outverschuivingen te voorkomen. Als de grootte onbekend is, moeten ontwikkelaars layout=fill
opgeven om een niet -groot beeld te bedienen dat in een container zit. Als alternatief kunt u statische beeldimport gebruiken om de grootte van de werkelijke afbeelding op de harde schijf tijdens de bouwtijd op te halen en in de afbeelding op te nemen.
// Image component with width and height specified
<Image src="/logo.jpg" alt="logo" height="200" width="100" />
// Image component with layout specified
<Image src="/hero.jpg" layout="fill" objectFit="cover" alt="hero" />
// Image component with image import
import Image from 'next/image'
import logo from './logo.png'
function Logo() {
return <Image src={logo} alt="logo" />
}
Aangezien ontwikkelaars de beeldcomponent niet onrecht kunnen gebruiken, zorgt het ontwerp ervoor dat ze de tijd nemen om beeldomvang te overwegen en lay -outverschuivingen te voorkomen.
De responsiviteit vergemakkelijken
Om afbeeldingen op verschillende apparaten te laten responsief maken, moeten ontwikkelaars de srcset
en sizes
-attributen in het element <img>
instellen. We wilden deze inspanning verminderen met de beeldcomponent. We designed the Next.js Image component to set the attribute values only once per application. We apply them to all instances of the Image component based on the layout mode. We came up with a three-part solution:
-
deviceSizes
property: This property can be used to configure breakpoints one-time based on the devices common to the application user base. The default values for breakpoints are included in the config file. -
imageSizes
property: This is also a configurable property used to get the image sizes corresponding to device size breakpoints. -
layout
attribute in each image: This is used to indicate how to use thedeviceSizes
andimageSizes
properties for each image. The supported values for layout mode arefixed
,fill
,intrinsic
andresponsive
When an image is requested with layout modes responsive or fill , Next.js identifies the image to be served based on the size of the device requesting the page and sets the srcset
and sizes
in the image appropriately.
The following comparison shows how the layout mode can be used to control the size of the image on different screens. We have used a demo image shared in the Next.js docs, viewed on a phone and a standard laptop.
Laptop screen | Telefoonscherm |
---|---|
Layout = Intrinsic: Scales down to fit the container's width on smaller viewports. Does not scale up beyond the image's intrinsic size on a larger viewport. Container width is at 100% | |
![]() | ![]() |
Layout = Fixed: Image is not responsive. Width and height are fixed similar to ` | |
![]() | ![]() |
Layout = Responsive: Scale down or scale up depending on the width of the container on different viewports, maintaining aspect ratio. | |
![]() | ![]() |
Layout = Fill: Width and height stretched to fill the parent container. (Parent <div> width is set to 300*500 in this example) | |
![]() | ![]() |
Provide built-in lazy-loading
The Image component provides a built-in, performant lazy loading solution as a default. When using the <img>
element, there are a few options for lazy loading, but they all have drawbacks that make them tricky to use. A developer might adopt one of the following lazy loading approaches:
- Specify the
loading
attribute: This is supported on all modern browsers . - Use the Intersection Observer API : Building a custom lazy-loading solution requires effort and a thoughtful design and implementation. Developers may not always have the time for this.
- Import a third-party library to lazy-load images: Additional effort may be required to evaluate and integrate a suitable third-party library for lazy loading.
In the Next.js Image component, loading is set to "lazy"
by default. Lazy loading is implemented using Intersection Observer, which is available on most modern browsers . Developers are not required to do anything extra to enable it, but they can disable it when needed.
Preload important images
Quite often, LCP elements are images, and large images can delay LCP. It is a good idea to preload critical images so the browser can discover that image sooner. When using an <img>
element, a preload hint may be included in the HTML head as follows.
<link rel="preload" as="image" href="important.png">
A well-designed image component should offer a way to tweak the loading sequence of images, regardless of the framework used. In the case of the Next.js Image component, developers can indicate an image that is a good candidate for preload using the priority
attribute of the images component.
<Image src="/hero.jpg" alt="hero" height="400" width="200" priority />
Adding a priority
attribute simplifies markup and is more convenient to use. Image component developers can also explore options to apply heuristics to automate preloading for above-the-fold images on the page that meet specific criteria.
Encourage high-performance image hosting
Image CDNs are recommended for automating image optimization, and they also support modern image formats like WebP and AVIF. The Next.js Image component uses an image CDN by default using a loader architecture . The following example shows that the loader allows for configuration of the CDN in the Next.js config file.
module.exports = {
images: {
loader: 'imgix',
path: 'https://ImgApp/imgix.net',
},
}
With this configuration, developers can use relative URLs in the image source, and the framework will concatenate the relative URL with the CDN path to generate the absolute URL. Popular image CDNs like Imgix , Cloudinary , and Akamai are supported. The architecture supports the use of a custom cloud provider by implementing a custom loader
function for the app.
Support self-hosted images
There may be situations where websites cannot use image CDNs. In such cases, an image component must support self-hosted images. The Next.js Image component uses an image optimizer as a built-in image server that provides a CDN-like API. The optimizer uses Sharp for production image transformations if it is installed on the server. This library is a good choice for anyone looking to build their own image optimization pipeline.
Support progressive loading
Progressive loading is a technique used to hold users' interest by displaying a placeholder image usually of significantly lower quality while the actual image loads. It improves perceived performance and enhances the user experience. It can be used in combination with lazy loading for below-the-fold images or for above-the-fold images.
The Next.js Image component supports progressive loading for the image through the placeholder property. This can be used as an LQIP (Low-quality image placeholder) for displaying a low-quality or blurred image while the actual image loads.
Invloed
With all these optimizations incorporated, we have seen success with the Next.js Image component in production and are also working with other tech stacks on similar image components.
When Leboncoin migrated their legacy JavaScript frontend to Next.js , they also upgraded their image pipeline to use the Next.js Image component. On a page that migrated from <img>
to next/image, LCP went down from 2.4s to 1.7s. The total image bytes downloaded for the page went from 663kB to 326kB (with ~100kB of lazy-loaded image bytes).
Lessons Learned
Anyone creating a Next.js app can benefit from using the Next.js Image component for optimization. However, if you want to build similar performance abstractions for another framework or CMS, the following are a few lessons we learned along the way that could be helpful.
Safety valves can cause more harm than good
In an early release of the Next.js Image component, we provided a unsized
attribute that allowed developers to bypass the sizing requirement, and use images with unspecified dimensions. We thought this would be a necessary in instances where it was impossible to know the image's height or width in advance. However, we noticed users recommending the unsized
attribute in GitHub issues as a catch-all solution to problems with the sizing requirement, even in cases where they could solve the problem in ways that didn't worsen CLS. We subsequently deprecated and removed the unsized
attribute.
Separate useful friction from pointless annoyance
The requirement for sizing an image is an example of "useful friction." It restricts the use of the component, but it provides outsized performance benefits in exchange. Users will readily accept the constraint if they have a clear picture of the potential performance benefits. Therefore, it is worthwhile to explain this tradeoff in the documentation and other published material about the component.
However, you can find workarounds for such friction without sacrificing performance. For example, during the development of the Next.js Image component, we received complaints that it was annoying to look up sizes for locally stored images. We added static image imports , which streamline this process by automatically retrieving dimensions for local images at build time using a Babel plugin.
Strike a balance between convenience features and performance optimizations
If your image component does nothing but impose "useful friction" on its users, developers will tend to not want to use it. We found that although performance features like image sizing and automatic generation of srcset
values were the most important. Developer-facing convenience features like automatic lazy loading and built-in blurry placeholders also drove interest in the Next.js Image component.
Set a roadmap for features to drive adoption
Building a solution that works perfectly for all situations is very difficult. It can be tempting to design something that works well for 75% of people and then tell the other 25% that "in these cases, this component isn't for you."
In practice, this strategy turns out to be at odds with your goals as a component designer. You want developers to adopt your component in order to benefit from its performance benefits. This is difficult to do if there is a contingent of users that are unable to migrate and feel left out of the conversation. They are likely to express disappointment, leading to negative perceptions that affect adoption.
It is advisable to have a roadmap for your component that covers all reasonable use cases over the long term. It also helps to be explicit in the documentation about what isn't supported and why in order to set expectations about the problems the component is intended to solve.
Conclusie
Image usage and optimization is complicated. Developers have to find the balance between performance and quality of images while ensuring a great user experience. This makes image optimization a high-cost, high-impact endeavor.
Instead of having each app reinvent the wheel every time, we came up with a best practices template that developers, frameworks, and other tech-stacks could use as a reference for their own implementations. This experience will indeed prove valuable as we support other frameworks, on their image components.
The Next.js Image component has successfully improved performance outcomes in Next.js applications, thereby enhancing the user experience. We believe that it's a great model that would work well in the broader ecosystem, and we would love to hear from developers who would like to adopt this model in their projects.