Performance 16 december 2025 12 min leestijd

Hoe krijg je een 90+ PageSpeed Score

Geen standaard tips, maar echte PRO-technieken die wij dagelijks gebruiken om WordPress websites naar 90+ scores te tillen. Van Critical CSS tot Speculative Preloading - dit is hoe de experts het doen.

Rick Janssen Performance Engineer bij wpts.nl
96 Performance <link rel= "preload" as="style"> LCP: 1.2s FID: 12ms CLS: 0.02
Dit is geen beginners-gids. We gaan ervan uit dat je de basics kent (caching plugin, afbeeldingen comprimeren). Dit artikel gaat over de technieken die het verschil maken tussen een 70 en een 95+ score.

Core Web Vitals begrijpen

Google meet je website op drie cruciale metrics. Als je deze begrijpt, weet je precies waar je moet optimaliseren:

LCP (Largest Contentful Paint)

Doel: < 2.5s

Wanneer het grootste element zichtbaar is. Meestal een hero image of heading.

  • Impact: 25% van score
  • Oorzaken: trage server, render-blocking resources
  • Fix: preload, critical CSS

INP (Interaction to Next Paint)

Doel: < 200ms

Hoe snel reageert de pagina op gebruikersinteractie (vervangt FID in 2024).

  • Impact: 25% van score
  • Oorzaken: zware JavaScript
  • Fix: code splitting, defer

CLS (Cumulative Layout Shift)

Doel: < 0.1

Hoeveel verschuift de layout tijdens het laden?

  • Impact: 25% van score
  • Oorzaken: images zonder dimensies, late-loading ads
  • Fix: aspect-ratio, font-display
Pro tip: Test altijd met de "Mobile" setting in PageSpeed Insights. Google rankt op mobile-first, en mobile scores zijn altijd lager dan desktop.

Critical CSS: De #1 LCP killer

Dit is de belangrijkste optimalisatie die 90% van de WordPress sites mist. Critical CSS is de minimale CSS die nodig is om de "above the fold" content te renderen, inline in je <head>.

Waarom is dit zo belangrijk?

Standaard blokkeert je CSS-bestand de rendering. De browser wacht tot het hele bestand is gedownload voordat hij iets toont. Met Critical CSS zie je direct content.

Zonder Critical CSS (slecht)
<head>
  <link rel="stylesheet" href="style.css"> <!-- BLOKKEERT RENDERING -->
</head>

Tijdlijn: [----Download CSS----][--Parse--][RENDER]
          0ms                   800ms      1000ms   = LCP 1000ms+
Met Critical CSS (goed)
<head>
  <style>
    /* Alleen above-the-fold CSS - ~15KB */
    .header{...} .hero{...} .nav{...}
  </style>
  <link rel="preload" href="style.css" as="style"
        onload="this.onload=null;this.rel='stylesheet'">
</head>

Tijdlijn: [RENDER][----Download CSS in background----]
          200ms                                      = LCP 200ms!

Hoe genereer je Critical CSS?

WP Rocket

Automatisch

Genereert automatisch Critical CSS per pagina.

  • Instellingen → Optimize CSS
  • "Remove Unused CSS" aan
  • Automatische regeneratie

FlyingPress

Beste resultaat

Nieuwere technologie, vaak betere scores.

  • Genereert per post type
  • Unused CSS removal
  • Kleinere output

Perfmatters + CriticalCSS.com

Pro setup

Voor maximale controle.

  • API-based generatie
  • Handmatige fallback
  • Beste voor complexe sites
Let op: Na het inschakelen van Critical CSS, test elke pagina visueel. Soms mist de generator CSS voor elementen net buiten de viewport, wat tot FOUC (Flash of Unstyled Content) leidt.

JavaScript optimalisatie

JavaScript is de grootste vijand van je INP score. Elke KB JavaScript moet worden gedownload, geparsed en uitgevoerd voordat je pagina interactief is.

1. Delay JavaScript execution

Dit is de meest impactvolle JS-optimalisatie. In plaats van alle scripts te laden bij pageload, wacht je tot de gebruiker interactie heeft (scroll, click, touch).

JavaScript delay implementatie
// Handmatige delay (voor custom implementaties)
const loadScriptsOnInteraction = () => {
    // Laad je scripts hier
    const script = document.createElement('script');
    script.src = 'heavy-script.js';
    document.body.appendChild(script);
};

// Trigger op eerste interactie
['scroll', 'click', 'touchstart', 'mousemove'].forEach(event => {
    window.addEventListener(event, loadScriptsOnInteraction, { once: true });
});

// Fallback na 5 seconden
setTimeout(loadScriptsOnInteraction, 5000);

2. Scripts die je NOOIT moet delayen:

  • jQuery (als je thema het nodig heeft voor basisnavigatie)
  • Analytics/Tag Manager (voeg toe aan exclusielijst)
  • Consent management (cookie banners)
  • Chat widgets die direct zichtbaar moeten zijn

3. Specifieke plugin optimalisaties:

functions.php - Verwijder onnodige scripts
// Verwijder WooCommerce scripts van niet-shop pagina's
add_action('wp_enqueue_scripts', function() {
    if (!is_woocommerce() && !is_cart() && !is_checkout()) {
        wp_dequeue_style('woocommerce-general');
        wp_dequeue_style('woocommerce-layout');
        wp_dequeue_script('wc-cart-fragments');
        wp_dequeue_script('woocommerce');
    }
}, 99);

// Verwijder Gutenberg block CSS als je Classic Editor gebruikt
add_action('wp_enqueue_scripts', function() {
    wp_dequeue_style('wp-block-library');
    wp_dequeue_style('wp-block-library-theme');
    wp_dequeue_style('wc-blocks-style');
}, 100);

// Verwijder jQuery Migrate (meestal niet nodig)
add_action('wp_default_scripts', function($scripts) {
    if (!is_admin() && isset($scripts->registered['jquery'])) {
        $script = $scripts->registered['jquery'];
        if ($script->deps) {
            $script->deps = array_diff($script->deps, ['jquery-migrate']);
        }
    }
});

Moderne image optimalisatie

Afbeeldingen zijn meestal 50%+ van je pageweight. De juiste optimalisatie kan je LCP dramatisch verbeteren.

1. Gebruik moderne formats (AVIF > WebP > JPEG)

Picture element met fallbacks
<picture>
  <source srcset="image.avif" type="image/avif">
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" alt="..." width="800" height="600"
       loading="lazy" decoding="async">
</picture>

/* Besparingen:
   JPEG: 100KB (baseline)
   WebP: 70KB  (-30%)
   AVIF: 45KB  (-55%) */

2. Preload je LCP image

De afbeelding die je LCP bepaalt (meestal hero image) moet gepreload worden:

LCP image preloading
<head>
  <!-- Preload met moderne format support -->
  <link rel="preload" as="image" href="hero.avif"
        type="image/avif"
        imagesrcset="hero-400.avif 400w, hero-800.avif 800w, hero-1200.avif 1200w"
        imagesizes="100vw">
</head>

// Of via PHP voor dynamische hero images:
add_action('wp_head', function() {
    if (is_front_page() && has_post_thumbnail()) {
        $img = wp_get_attachment_image_src(get_post_thumbnail_id(), 'full');
        echo '<link rel="preload" as="image" href="' . $img[0] . '">';
    }
}, 1);

3. Fetchpriority voor kritieke images

Fetchpriority attribute (nieuw in 2024)
<!-- LCP image: hoge prioriteit, geen lazy loading -->
<img src="hero.webp"
     fetchpriority="high"
     decoding="sync"
     alt="Hero">

<!-- Overige images: lazy loading -->
<img src="other.webp"
     loading="lazy"
     decoding="async"
     fetchpriority="low"
     alt="Other">
Pro tip: Gebruik nooit lazy loading op images above-the-fold. Dit vertraagt je LCP! WordPress 5.9+ voegt automatisch loading="lazy" toe aan alle images - override dit voor je hero.

Font loading strategieen

Fonts zijn vaak de oorzaak van CLS (layout shift) en kunnen je LCP vertragen. Hier zijn de PRO-technieken:

1. Self-host Google Fonts

Google Fonts van fonts.googleapis.com vereist 2 extra DNS lookups en connections. Self-hosting is sneller:

Optimale font loading
/* 1. Preload je belangrijkste font weight */
<link rel="preload" href="/fonts/inter-400.woff2"
      as="font" type="font/woff2" crossorigin>

/* 2. Font-face met font-display: swap */
@font-face {
    font-family: 'Inter';
    src: url('/fonts/inter-400.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap; /* Voorkomt FOIT, maar kan CLS veroorzaken */
}

/* 3. Beter: font-display: optional (geen CLS!) */
@font-face {
    font-family: 'Inter';
    src: url('/fonts/inter-400.woff2') format('woff2');
    font-weight: 400;
    font-display: optional; /* Gebruikt systeemfont als niet in cache */
}

2. Fallback font matching

De grootste CLS-oorzaak is het verschil tussen je fallback font en web font. Match ze:

Font fallback matching met size-adjust
/* Definieer een aangepaste fallback */
@font-face {
    font-family: 'Inter-fallback';
    src: local('Arial');
    size-adjust: 107%;      /* Match de breedte */
    ascent-override: 90%;   /* Match de hoogte */
    descent-override: 22%;
    line-gap-override: 0%;
}

body {
    font-family: 'Inter', 'Inter-fallback', sans-serif;
}

/* Tool om values te berekenen: https://screenspan.net/fallback */

Geavanceerde caching

Caching is meer dan alleen een plugin installeren. Hier zijn de lagen die je nodig hebt:

De caching stack (van snel naar langzaam):

  1. 1
    Browser cache (client-side)

    Cache-Control headers voor statische assets. Stel in op 1 jaar voor assets met hash in filename.

  2. 2
    CDN Edge cache (Cloudflare/BunnyCDN)

    Serveert content vanaf locatie dichtbij de bezoeker. Reduceert TTFB drastisch.

  3. 3
    Page cache (WP Rocket/FlyingPress)

    Slaat complete HTML op. Voorkomt PHP execution voor elke request.

  4. 4
    Object cache (Redis/Memcached)

    Cached database queries. Cruciaal voor dynamic content en logged-in users.

  5. 5
    Opcode cache (OPcache)

    Cached compiled PHP. Meestal standaard aan bij goede hosts.

.htaccess - Browser caching headers
# Agressieve caching voor statische assets
<IfModule mod_expires.c>
    ExpiresActive On

    # Images
    ExpiresByType image/avif "access plus 1 year"
    ExpiresByType image/webp "access plus 1 year"
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType image/svg+xml "access plus 1 year"

    # Fonts
    ExpiresByType font/woff2 "access plus 1 year"
    ExpiresByType font/woff "access plus 1 year"

    # CSS/JS (met versioning)
    ExpiresByType text/css "access plus 1 year"
    ExpiresByType application/javascript "access plus 1 year"

    # HTML (kort)
    ExpiresByType text/html "access plus 0 seconds"
</IfModule>

# Immutable voor gehashte assets
<FilesMatch "\.[a-f0-9]{8,}\.(css|js|woff2|avif|webp)$">
    Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>

Database optimalisatie

Een opgeblazen database vertraagt elke uncached request. Dit zijn de technieken die echt helpen:

1. Verwijder bloat

Database cleanup queries
-- Verwijder post revisions (bewaar laatste 3)
DELETE FROM wp_posts WHERE post_type = 'revision'
AND ID NOT IN (
    SELECT * FROM (
        SELECT ID FROM wp_posts WHERE post_type = 'revision'
        ORDER BY post_date DESC LIMIT 3
    ) AS t
);

-- Verwijder auto-drafts ouder dan 7 dagen
DELETE FROM wp_posts WHERE post_status = 'auto-draft'
AND post_date < DATE_SUB(NOW(), INTERVAL 7 DAY);

-- Verwijder orphaned postmeta
DELETE pm FROM wp_postmeta pm
LEFT JOIN wp_posts p ON p.ID = pm.post_id
WHERE p.ID IS NULL;

-- Verwijder transients (worden toch geregenereerd)
DELETE FROM wp_options WHERE option_name LIKE '%_transient_%';

-- Optimaliseer tabellen
OPTIMIZE TABLE wp_posts, wp_postmeta, wp_options, wp_comments;

2. Beperk revisions in wp-config.php

wp-config.php
// Beperk revisions tot 3
define('WP_POST_REVISIONS', 3);

// Verleng autosave interval (default 60 seconden)
define('AUTOSAVE_INTERVAL', 300);

// Disable heartbeat op frontend (bespaart AJAX calls)
add_action('init', function() {
    if (!is_admin()) {
        wp_deregister_script('heartbeat');
    }
});

3. Autoload optimalisatie

De wp_options tabel met autoload='yes' wordt bij ELKE pageload geladen. Check welke opties je kunt uitzetten:

Check autoloaded data grootte
-- Check totale autoload grootte (moet < 1MB zijn)
SELECT SUM(LENGTH(option_value)) as autoload_size
FROM wp_options WHERE autoload = 'yes';

-- Vind de grootste autoloaded options
SELECT option_name, LENGTH(option_value) as size
FROM wp_options
WHERE autoload = 'yes'
ORDER BY size DESC LIMIT 20;

-- Zet grote opties op autoload=no (voorzichtig!)
UPDATE wp_options SET autoload = 'no'
WHERE option_name = 'example_large_option';

Server-side optimalisaties

Je kunt alles optimaliseren, maar op slechte hosting haal je nooit een goede score. Dit is wat je nodig hebt:

Minimale server requirements voor 90+ scores:

  • PHP 8.1+ met OPcache PHP 8.2 is 5-10% sneller dan 8.0
  • NVMe SSD storage 10x sneller dan traditionele SSD
  • Redis/Memcached object cache Cruciaal voor dynamic content
  • HTTP/2 of HTTP/3 (QUIC) Parallelle requests, snellere handshakes
  • Server in EU (voor NL bezoekers) Lage latency = lage TTFB

TTFB (Time to First Byte) optimaliseren

Je TTFB moet onder 200ms zijn. Check dit met:

TTFB testen via terminal
# Check TTFB (time_starttransfer)
curl -w "DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" -o /dev/null -s https://jouwsite.nl

# Verwachte output voor snelle site:
# DNS: 0.020s
# Connect: 0.040s
# TTFB: 0.150s     <-- Dit moet < 200ms zijn
# Total: 0.300s

De beste performance plugins

Na jaren testen, dit zijn onze aanbevelingen:

FlyingPress

Beste overall

Nieuwste technologie, consistent beste scores.

  • Critical CSS per page type
  • JS delay + exclude
  • Unused CSS removal
  • Image CDN optioneel
  • €60/jaar

WP Rocket

Meest populair

Betrouwbaar, goede support, breed inzetbaar.

  • Page cache + preload
  • Remove unused CSS
  • Delay JavaScript
  • Lazy loading
  • €59/jaar

Perfmatters

Aanvulling

Script manager - gebruik naast caching plugin.

  • Scripts per pagina aan/uit
  • Local Google Analytics
  • Database cleaner
  • Preloading controls
  • €25/jaar
Onze stack: FlyingPress + Perfmatters + Cloudflare (free). Dit geeft consistent 90+ scores op zowel mobile als desktop, zelfs op complexe WooCommerce sites.

Veelgestelde vragen

Waarom is mijn mobile score zoveel lager dan desktop?

PageSpeed simuleert een mid-range Android telefoon op 4G. Dit is veel trager dan je eigen telefoon. De test gebruikt CPU throttling (4x langzamer) en netwerk throttling (1.6 Mbps). Focus op mobile - als die goed scoort, is desktop automatisch goed.

Kan ik 100/100 halen?

Technisch mogelijk, maar vaak niet praktisch. 90+ is "groen" en geeft geen ranking nadeel. De laatste 10 punten kosten disproportioneel veel moeite en kunnen functionaliteit breken. Focus op echte gebruikerservaring, niet het perfecte nummer.

Wat is belangrijker: score of echte laadtijd?

Echte laadtijd (en vooral perceived performance). PageSpeed is een indicator, maar geen perfecte meting. Gebruik ook tools als WebPageTest voor real-world metingen en Google Search Console voor field data (echte gebruikers).

Mijn score fluctueert - is dat normaal?

Ja, 5-10 punten variatie is normaal. PageSpeed test vanaf Google servers die variëren in locatie en load. Test altijd meerdere keren en kijk naar het gemiddelde. GTmetrix biedt consistentere tests omdat je de testlocatie kunt fixeren.

Complete optimalisatie checklist

Print deze checklist en werk hem af voor elke website:

PageSpeed 90+ Checklist

Geen tijd voor optimalisatie?

Wij optimaliseren dagelijks WordPress websites naar 90+ scores. Laat ons het zware werk doen.

Vraag een speed audit
Deel dit artikel:

Gerelateerde artikelen

Security

SSL Certificaat Installeren: Stap-voor-Stap

E-commerce

WooCommerce Optimaliseren voor Meer Conversies

Security

10 Essentiële WordPress Security Tips

Chat met ons!