Handleiding: Scoor met een PageSpeed van 100
Geert-Jan Evers

Geert-Jan Evers

Handleiding: Scoor met een PageSpeed van 100

In Plate zijn verschillende tools geïntegreerd om de snelheid van je website te verhogen. In deze PageSpeed-handleiding zetten we de tools op een rijtje en krijg je voorbeelden over hoe je ze als developer optimaal kunt gebruiken. Ter afsluiting geven we ook nog een aantal algemene tips voor een hogere pagespeed-score. Bekijk de opnames van de Pagespeed webinar die horen bij dit artikel.

Tools om je pagespeed te analyseren

Voordat je begint met het optimaliseren van de snelheid van je website is het belangrijk dat je eerst analyseert hoe je website nu presteert. Wij gebruiken daar verschillende tools voor.

Bekende tools zijn:

Waterfall op webpagetest.org

Een waterfall overzicht van WebpageTest

De bekendste tool is Google PageSpeed. Naast het berekenen van de laadtijden geeft Google je ook aanbevelingen over hoe en waar je je website kunt verbeteren. Deze tool wordt over het algemeen gebruikt als belangrijkste maatstaf voor het beoordelen van de snelheid van je website, maar het is altijd goed om meerdere tools te gebruiken. Zo laat WebpageTest bijvoorbeeld goed zien wanneer een script wordt ingeladen en hoelang je website er over doet, waardoor je nauwkeuriger eventuele problemen kunt analyseren.

PlateSpeed tools

Caching

Met onze cachingfunctie maken we je website, -app of portal supersnel zonder dat je daar een plugin voor nodig hebt, out of the box.

Door middel van caching wordt er een kopie van de pagina gemaakt, gecomprimeerd naar pure HTML en opgeslagen. Deze kopie wordt voortaan getoond aan de bezoeker wanneer dezelfde pagina wordt opgevraagd. Als je je website wijzigt in het CMS, wordt de kopie ongeldig en begint het proces opnieuw.

Om een voorbeeld te geven wat voor impact dit kan hebben op je resultaat: de onderstaande website is van een pagespeed score van 67 (mobiel) naar 90 gegaan door enkel het activeren van de caching in Plate.

Resultaat beterduurzaam.nl voordat caching werd aangezet

Voordat caching werd toegepast.

Resultaat beterduurzaam.nl nadat caching werd aangezet

Nadat caching werd toegepast.

Meer informatie over hoe je caching het best kunt integreren in jouw Plate site lees je hier.

Afbeeldingen comprimeren

Met image compressie in Plate maak je je niet langer druk over de grootte van de afbeeldingen op je website. In plaats van originele afbeeldingen maak je gebruik van geoptimaliseerde versies van afbeeldingen die Plate automatisch voor je genereert.

Om dit goed te doen zijn hier verschillende opties voor mogelijk zoals bijsnijden, kwaliteits- en kleuraanpassingen en bestandsformaatkeuze (png, jpeg, webp).

Wil je precies weten hoe je dit goed in Plate regelt en welke opties we nog meer hebben? Kijk dan  hier.

Een voorbeeldje van wat dit kan doen:

De onderstaande afbeelding was origineel: 1908 * 4032 px en 8.8MB in PNG
(bekijk hier).

Door deze passen te maken voor de website(bijv. 1920*1080) wordt deze 3.6MB(-59%)
(bekijk hier).

Als je deze ook nog eens omzet naar JPEG wordt deze 339KB (-91% t.o.v. png) 
(bekijk hier)

In webp wordt deze 291KB(-92% t.o.v. png, -13% t.o.v. jpeg)
(bekijk hier).

000

Met de tools in Plate verklein je afbeeldingen op je website eenvoudig zodat je een optimale pagespeed krijgt. Als je verder leest, ontdek je hoe je dit toepast binnen je Plate thema.

Een PageSpeed 100 template

Starter template

Binnen Plate werken wij hard aan de ontwikkeling van een basis template voor al onze Plate websites. Hierin zitten verschillende elementen die ervoor zorgen dat de perfomance van onze websites optimaal is, waarbij we Lighthouse gebruiken als richtlijn. Met een starter template verhogen we ook de ontwikkelsnelheid van websites.

In dit hoofdstuk lichten we twee optimalisaties uit het starter template uit. Ten eerste de manier waarop wij afbeeldingen genereren en ten tweede hoe wij deze efficiënt laden door middel van lazyloading.

Let op! We hebben het hier niet over nieuwe features in Plate, maar demonstreren hoe je bestaande features optimaal kunt benutten.

Afbeeldingen in het juiste formaat

Plate biedt de mogelijkheid om je afbeeldingen om te zetten naar png, jpg of webp:

  • Webp: dit door Google ontwikkelde formaat combineert het beste van jpeg en png. Transparantie is hier mogelijk en webp heeft een grote compressie. Helaas wordt het bestandsformaat nog niet door alle browsers ondersteund (bijv. Safari), daarom blijven ook andere formaten van belang.
  • Jpeg: dit formaat heeft een grote compressie maar is gemiddeld ongeveer 30% groter dan webp. Dit zorgt ervoor dat jpeg een goed backup formaat is voor webp. Het wordt namelijk door alle browsers ondersteund. Helaas is transparantie niet mogelijk.
  • PNG: om toch een backup voor webp te hebben en ook transparante afbeeldingen te tonen, gebruiken we PNG. PNG-bestanden zijn over het algemeen erg groot en zijn dus alleen geschikt als backup formaat voor transparante afbeeldingen.
  • SVG: dit formaat wordt sterk aangeraden voor simpele op vector gebaseerde afbeeldingen (iconen, logo's). SVG’s zijn oneindig schaalbaar omdat ze een vector zijn. De code er achter is vaak kort en SVG-bestanden zijn daarom ook erg klein.

<picture>

Aan de hand van alle hiervoor genoemde kennis en features hebben wij met onze templating taal Liquid een handige functie ontwikkeld om de ideale afbeeldingen in te laden voor elk scherm.

Met de HTML <picture> tag kan je gemakkelijk voor elke browser of vensterbreedte de meest optimale afbeelding inladen.

Zo gebruiken wij dit om...

  • als de browser het ondersteund, .webp in te laden. Als het niet ondersteund wordt, gebruiken we .jpeg of .png als backup;
  • met Plate een afbeelding te genereren die geoptimaliseerd is voor de ruimte/kolom waar deze in staat.

Een beknopte weergave van hoe dit er in HTML uit ziet in ons geval:

	<picture class=" ">
    <source type="image/webp" srcset="img-1920.webp 1920w, (..) , img-576.webp 576w">
    <source srcset="img-1920.jpeg 1920w, img-1600.jpeg 1600w, (..), img-576.jpeg 576w ">
    <source type="image/webp" srcset="img-0.webp">
    <img src="img-0.jpeg" alt="alt-text">
</picture>

De basis include roep je aan met de volgende parameters en dit omschrijft ook welke functies de include heeft:

	{%- include 'includes/image/image',
    imageSource: image.image,
    imageLink: image.link,
    imageAlt: image.alt,
    imageClass: '',
    imageSizes: '$-12-40px|md-4-100%|lg-7-0',
    imageMode: 'crop',
    imageBoxed: false,
    imageLazyload: false,
    imagePng: image.png,
-%}

	imageSource:

De afbeelding

	imageLink:

Als je wilt dat de afbeelding ergens heen linkt, vul je deze in. Dan wordt er automatisch <a> met bijhorende url omheen gezet.

	imageAlt:

Als je een specifieke alt tekst wilt, voer je deze hier in. Als je dit niet doet, wordt deze samengesteld uit de bestandsnaam. Mocht je echt helemaal geen alt willen, kun je ook een lege string invullen (“”).

	imageClass:

Voor als je een specifieke class wilt geven aan het <picture> element.

	imageSizes: '$-12-40px|md-4-100%|lg-7-0',

Hier definieer je hoe je wilt dat jouw afbeelding zich gedraagt op alle schermen. Dit is gebaseerd op de benaming van de Bootstrap/Plate grid systeem.

Zo worden de instellingen voor de verschillende breakpunten gedefinieerd:

  • De verschillende breakpoint instellingen worden gescheiden door middel van een pipe (“|”).
  • De breakpoints zijn gedefinieerd van klein naar groot en moeten ook van klein naar groot gedefinieerd worden(!).
  • De eerste parameter voor een breakpoint staat voor de aanduiding van de viewport.
    - $ = min-width: 0px
    - sm = min-width: 576px
    - etc.
  • De tweede parameter staat voor de breedte. Standaard gaat dit om het aantal kolommen, maar als je dit aanduidt met px kan dat ook en is het ongerelateerd tot het aantal kolommen.
  • De derde parameter staat voor de hoogte met relatieve of absolute waardes
    - 0 = standaard relatieve hoogte
    - 10% = 10% van de breedte
    - 10px = 10px hoog
	imageMode:

Dit geeft het soort vervorming aan van de afbeelding. Standaard is dit crop, maar dit kan ook fit(overschrijft alle hoogte instellingen) of stretch zijn.

	imageBoxed:

Voer hier true in als je afbeelding in een container met een beperkte breedte zit. Vul false in als deze over de hele breedte van je scherm is.

	imageLazyload:

Als je afbeeldingen wilt lazyloaden zet je dit op true. Hier komen we op terug in de volgende paragraaf.

Afbeeldingen boven de vouw zet je bij voorkeur op false. Deze worden toch al meteen getoond en laden mooier zonder lazyloading.

	 imagePng:

Zet dit op true als je een afbeelding hebt met een transparante achtergrond. In Safari kan deze instelling gebruikt worden om de afbeeldingen goed weer te geven.

Let op! Dit gehele verhaal is niet relevant voor .svg bestanden, deze zijn namelijk al erg klein en deze wil je vector based houden. Daarom detecteert de functie ook of de url “.svg” bevat. Als dit zo is, zet hij de afbeelding in een normale <img> tag en voegt hij de afmetingen toe met inline styling.

Wil je dit ook gebruiken? Bekijk hier de code.

Let op! Kijk goed of je de bestanden op de juiste locatie plaatst!

Background images (webinar update)

Dit is een update n.a.v. de vragen na de webinar.

Hetzelfde principe kunnen we toepassen voor de achtergrond afbeeldingen. Daarvoor hebben we alleen geen <picture> element, maar lossen we het met @media op.

Een achtergrond afbeelding voeg je in met de onderstaande include:

	{%- include 'includes/image/image_background',
 imageSource: ,
 elementName: '',
 imageSizes:  '',
 imageBoxed:  true,
 imageLazyload:  true,
 imageLink: image.link,
 imageAlt: image.alt,
 imageClass: '',
 imageMode: 'crop', 
 imagePng: false,
 -%}

Zoals je ziet lijkt het aanroepen van de afbeelding veel op het aanroepen van de include met <picture>. De belangrijkste wijziging is "elementName". Hier moet je de class, het id of een andere identificatie invoeren van het element waar je de achtergrond afbeelding wilt toevoegen.

LET OP! Zorg ervoor dat deze uniek is, de afbeelding zal toegevoegd worden als achtergrond voor alle elementen met deze identificatie.

Met deze functie wordt er inline css ingevoerd met de breekpunten die ook voor het <picture> element worden gebruikt.

CSS biedt echter nog niet de mogelijkheid om te herkennen of een browser webp ondersteund. Daarvoor hebben we een gedeelte van de Modernizr javascript library nodig. Dit deel detecteert of webp wordt ondersteund door de browser en voegt een class aan de body toe. Hiermee kan met css wel de juiste afbeelding worden weergegeven.

Lazyloading vereist echter een extra stap, hiervoor moet je ook de class: "bg-lazy" toevoegen aan het element waar je achtergrond afbeelding gebruikt.

Wil je dit ook gebruiken? Bekijk de code voor de afbeelding en Modernizr.

Afbeeldingselement

De tot nu toe genoemde functies zijn handig voor ontwikkelaars om “hard coded” afbeeldingsvelden in te richten. Maar wij wilden deze functie ook doorvertalen naar het afbeeldingselement, die de gebruiker zelf kan toevoegen op zijn website.

Omdat de Plate template structuur maar 1 breekpunt heeft, is deze ook hierop gebaseerd. Afhankelijk van de kolom waar je een afbeelding in plaatst, haalt hij zelf de breedte van de kolom op en berekend hij zo de breedte.

Hieronder een voorbeeld van hoe ons contentmodel voor het afbeeldingselement eruit ziet:

content model
content model

Zo kun je de include ook in een element gebruiken. De afbeeldingen nemen altijd de kolombreedte aan, tenzij je definieert dat dit anders is. Als je desktop niet invult, neemt het de instellingen van mobiel over, net zoals bij de include.

Wil je dit ook gebruiken? Bekijk hier de code.

Lazyloading

Om afbeeldingen nog efficiënter in te laden, wil je ze naast het aanleveren in het juiste formaat alleen maar laten zien wanneer dat nodig is. Als een bezoeker de pagina bezoekt, maar niet naar beneden scrolt, hoeven de afbeeldingen buiten het zicht voor deze gebruiker niet ingeladen te worden. Als hij wel scrolt, moeten ze pas ingeladen worden als hij ze ook echt in beeld krijgt.

Om deze reden gebruiken wij binnen Plate lazyloading. Met javascript detecteren we door midden van de Javascript Intersection Observer API of een afbeelding in beeld is. Als dit het geval is passen we het src attribuut pas toe als de afbeelding zich op maximaal 200px afstand van viewport bevindt. We hebben deze marge toegepast zodat je de afbeeldingen niet contstant ziet inladen als je de pagina scrolt.

Met lazyloading klinkt het gebruik van geoptimaliseerde afbeeldingen misschien minder relevant voor de pagespeed, ze worden in de eerste instantie namelijk niet eens ingeladen. Maar juist met lazyloading is het ook belangrijk dat afbeeldingen snel inladen en dus een kleine bestandsgrootte hebben. Je wilt de afbeeldingen namelijk niet zien inladen en de kans dat dit gebeurt is groter als de afbeeldingen ook groter zijn.

Een voorbeeld van hoe dit eruit ziet in onze input html als je lazyloading hebt geactiveerd:

	<picture class=" ">
    <source class=”lazy” type="image/webp" data-srcset=" <!-- url’s + viewports in webp --> ">
    <source class=”lazy”  data-srcset=" <!-- url’s + viewports in jpeg/png -->  ">
    <source class=”lazy”  type="image/webp" data-srcset="" <!-- kleinste url in webp-->  "">
    <img class=”lazy”  data-src="<!-- kleinste url in jpeg/png-->" alt="alt-text">
</picture>

Javascript zoekt naar alle sources en images met de class lazy en kijkt of deze op maximaal 200px afstand van de viewport is. Als dit het geval is zet hij het om naar:

	<picture class=" ">
    <source class=”” type="image/webp" srcset=" <!-- url’s + viewports in webp --> " data-srcset=" <!-- url’s + viewports in webp --> ">
    <source class=”” srcset=" <!-- url’s + viewports in jpeg/png -->  "  data-srcset=" <!-- url’s + viewports in jpeg/png -->  ">
    <source class=””  type="image/webp" srcset=" <!-- kleinste url in webp-->  " data-srcset=" <!-- kleinste url in webp-->  ">
    <img class=”” src="<!-- kleinste url in jpeg/png-->" data-src="<!-- kleinste url in jpeg/png-->"  alt="alt-text">
</picture>

Omdat de source niet in alle browsers standaard goed zichtbaar is in de DOM is het belangrijk dat je deze op display: block zet.

Mocht je toch een backup afbeelding willen inladen, die wel standaard ingeladen wordt, kan je deze in de src zetten van de <img>. Deze wordt overschreven als je de afbeelding inlaad. Dit kan handig zijn als je bijvoorbeeld ook iets wilt laten zien als iemands internet verbinding opeens wegvalt. Hiervoor kan je dan het beste een kleine, geblurde afbeelding gebruiken, zodat dit zo min mogelijk impact heeft op de laadtijd van de website.

Helaas werkt lazyloading nog niet zo goed samen met de content editor van Plate. Als je lazyloading aan hebt staan en een nieuwe afbeelding toevoegt, wordt deze pas ingeladen als je de pagina ververst. Om deze reden hebben wij in ons template onder de site instellingen ook een optie toegevoegd om lazyloading in de gehele site uit te zetten. Dit is vooral handig tijdens het vullen van de website.
Let op! Hiervoor moet je dus een keuzeveld in je site instellingen toevoegen met Veld ID "lazyload"

Wil je dit ook gebruiken? Bekijk hier de code.

Extra tips & tricks

Als bovenstaande implementaties nog niet genoeg geholpen hebben, geven we hier nog een aantal extra tips.

Javascript

Websites met javascript kunnen ook last hebben van een vertraging bij het laden van de pagina.

Locatie

De eerst belangrijkste tip is om de javascript in te laden onderaan de pagina. Dan blokkeert dit niet het renderen/laden van html/css.

CDN

Probeer js/css libraries in te laden via een cdn. Als een bezoeker een andere website heeft bezocht die dezelfde cdn gebruikt, wordt deze opgeslagen in de browser cache en hoeft deze bij het bezoek aan jouw website niet meer helemaal ingeladen te worden.

Let hierbij wel op: als je bijvoorbeeld maar een gedeelte van een library gebruikt en de mogelijkheid hebt delen die je niet gebruikt weg te laten, kun deze het beste zelf uploaden. (Bijv. als je maar een aantal .scss bestanden gebruikt van bootstrap)

Conditonele code

In een ideale situatie laad je helemaal geen onnodige code in op een pagina. Als je bepaalde code/library alleen maar gebruikt bij een paar elementen/secties kan je deze conditioneel inladen. Dus dit script wordt alleen ingeladen als de pagina dit bevat. Hiervoor kan je als hack een session gebruiken.

Zet in de sectie of het element waar je de code gebruikt de volgende code:

	{% set_session “use_js”, “true” %}

Onder je footer laad je de code in door middel van:

	{% if session.use_js == “true” %}
  {{ "scripts/use_js.js" | asset_url | script_tag }}
{% endif %}
{% set_session “use_js”, “false” %}

Zo wordt de code alleen maar ingeladen als jij in een element/sectie aangeeft dat de code relevant is voor deze pagina.

Critical css

Mocht je een website hebben met heel erg veel css, waarvan het grootste deel niet meteen zichtbaar is, dan is het verstandig om in je ontwikkelproces de css/scss/sass/less, die nodig is voor het gedeelte dat meteen zichtbaar is in de website, gescheiden te houden. Zo laad je alleen deze kritische kleine css in de <head> in en de rest na de <footer>.

Compilen / splitten

Om je code zo efficiënt en compact mogelijk in te laden, is het balangrijk om je code te compilen als de website af is. Zo wordt alle onnodige code verwijderd (spaties, enters, comments, etc.).

Wij gebruiken hiervoor webpack. Webpack compiled onze Sass en javascript code naar zo klein mogelijke bestanden. In webpack gebruiken we ook Babel om tijdens het bouwen ES6 te kunnen gebruiken. Deze moderne versie van javascript wordt nog niet door alle browsers ondersteund, maar Babel zet het om naar ES5 zodat alle browsers hiermee kunnen omgaan.

Met webpack is het ook mogelijk om je code te splitten. Hiermee maak je het mogelijk om lazyloading voor je code toe te passen. Lees hier meer hierover. Dit is echter alleen nodig als je heel erg veel javascript gebruikt.

Code van derden inladen

Mocht je alle bovenstaande tips opgevolgd hebben, kan code van derden, zoals Google Analytics, Leadfeader of een chat functionaliteit, je pagespeed nog steeds flink omlaag halen.

Hoewel vaak wordt aangeraden om dit in de <head> in te laden kan dit ook in de footer of eventueel met een setTimeout() of onload javascript functie. Zo wordt eerst de hele pagina ingeladen voordat deze pas actief worden.

Let op: voor services zoals Google Analytics kan dit er wel voor zorgen dat de laadtijd niet mee berekend wordt in de gemiddelde sessie tijd!

Video’s

Probeer video’s niet direct op de pagina in te laden en probeer ze te hosten bij een hostingservice zoals Vimeo of YouTube. Vimeo doet bijvoorbeeld een hele goede compressie voor de afbeeldingen en biedt verschillende formaten aan waardoor je ze zo klein mogelijk kan inladen.

Laad andere video’s pas in als je ze wilt afspelen.

DOM

Zorg ervoor dat je DOM niet onnodig groot/diep is. Probeer dus niet te veel HTML elementen te gebruiken.

Heb je naar aanleiding van dit artikel nog vragen over pagespeed? Stuur gerust een mailtje naar geert-jan@getplate.com.

Wil je onze code bekijken/gebruiken? Bekijk dan hier de code!

Ga naar de code!

Nieuws

Meer nieuws
Interne Lancering: Maak kennis met Plate Delta CMS

Interne Lancering: Maak kennis met Plate Delta CMS


Pieter Versloot - 5 min. lezen

Update: bewerk je website nu ook vanaf tablet of smartphone

Update: bewerk je website nu ook vanaf tablet of smartphone


Elena Freudenberg - 1 min. lezen

Plate lanceert WhatsApp-kanaal voor productnieuws

Plate lanceert WhatsApp-kanaal voor productnieuws


Pieter Versloot - 1 min. lezen

Digitale toegankelijkheid van schoolwebsites: wat onderwijsorganisaties moeten weten voor 2025

Digitale toegankelijkheid van schoolwebsites: wat onderwijsorganisaties moeten weten voor 2025


Johannes Baas - 10 min. lezen

Wat leren we van de chaos bij WordPress?

Wat leren we van de chaos bij WordPress?


Pieter Versloot - 3 min. lezen

De juiste mate van flexibiliteit: whitelabel templates die werken

De juiste mate van flexibiliteit: whitelabel templates die werken


Pieter Versloot - 3 min. lezen