Layout Shift veroorzaakt door CSS transitions

Leer hoe je CSS transitions die layout shifts veroorzaken kunt vinden en verwijderen

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-03-27

Waarom CSS transitions layout shifts veroorzaken

Cumulative Layout Shifts veroorzaakt door CSS transitions treden vaak vroeg op tijdens de laadfase van de pagina. Deze layout shifts gebeuren niet consistent, wat ze lastig te debuggen maakt.

Laatst beoordeeld door Arjen Karel in maart 2026

Het transition: all probleem

De meest voorkomende oorzaak van transition-gerelateerde layout shifts is transition: all. Volgens het CSS-hoofdstuk van de Web Almanac 2022 gebruikt 53% van de pagina's transition: all. Dat betekent dat elke property-wijziging wordt geanimeerd, inclusief degene die de layout beïnvloeden, zoals width, height, margin en padding.

Een CSS transition heeft een property, duration, timing-function en een delay. De steno (shorthand) ziet er zo uit:

/* property | duration | timing-function | delay */
transition: margin-right 4s ease-in-out 1s;

Het probleem begint wanneer developers transition: all .3s ease schrijven in plaats van de exacte property op te geven die ze willen animeren. Tijdens het laden van de pagina gaat een above-the-fold element, zoals een navigatiemenu, over van de initiële (ongestijlde) status naar de uiteindelijke (gestijlde of zelfs verborgen) status. Als de transition property all is, omvat dit width, height en zelfs visibility. Het resultaat: een layout shift die alleen tijdens het laden plaatsvindt en bijna onmogelijk consistent te reproduceren is.

Welke CSS properties veroorzaken layout shift?

Niet alle CSS transitions veroorzaken layout shifts. Alleen properties die de geometrie of positie van een element veranderen, triggeren de layout-stap van de browser. Volgens onderzoek van Google hebben pagina's die layout-inducerende CSS properties animeren 15% minder kans om voor CLS te slagen. Pagina's die margin of border-width animeren, hebben bijna twee keer zo vaak een slechte CLS.

Properties die layout shift veroorzaken: width, height, margin, padding, top, left, right, bottom, border-width, font-size, display

Veilige properties (alleen composite, geen layout shift): transform, opacity, filter, clip-path

Veilige properties (alleen paint, geen layout shift): background-color, color, box-shadow, outline

Het belangrijkste inzicht: transform en opacity worden volledig afgehandeld door de compositor-thread van de browser. Ze triggeren nooit een herberekening van de layout, dus ze tellen nooit mee voor CLS. Als je een element moet verplaatsen, gebruik dan transform: translate() in plaats van top/left. Als je de visuele grootte wilt aanpassen, gebruik dan transform: scale() in plaats van width/height.

Bekijk het onderstaande voorbeeld. Dit demonstreert een layout shift veroorzaakt door CSS transitions die optreden tijdens de laadfase van een pagina. Ik zie dit patroon constant, en het vinden en oplossen van dit soort problemen kan lastig zijn.

Vind en fix CSS transitions

Om alle layout shifts veroorzaakt door CSS transitions te vinden en op te lossen, moeten we een snelle test uitvoeren. Eerst zoeken we alle CSS transitions op de pagina. Vervolgens controleren we of een van deze transitions layout-beïnvloedende properties wijzigt. Tot slot meten we de impact van het uitschakelen of aanpassen van die transitions om te bevestigen dat ze CLS veroorzaakten.

Core Web Vitals tip: Cumulative Layout Shifts die worden veroorzaakt door CSS transitions, treden vaak vroeg op tijdens de laadfase van de pagina. Deze layout shifts gebeuren niet consistent, wat ze lastig te debuggen maakt. Het vertragen van je netwerk door een mobiel apparaat te emuleren en je cache uit te schakelen, maakt het vinden ervan makkelijker!

Stap 1: Vind CSS transitions

Het vinden van CSS transitions kan handmatig worden gedaan: inspecteer alle stylesheets en zoek naar het woord 'transition'. Dat zou niet meer dan 10 minuten werk moeten zijn, maar er is een betere manier! Plak deze snippet in de console en druk op enter.

(() => {

  let nodeTable = [];
  let nodeArray = [];

  // Get the name of the node
  function getName(node) {
    const name = node.nodeName;
    return node.nodeType === 1
      ? name.toLowerCase()
      : name.toUpperCase().replace(/^#/, '');
  }

  // Get the selector
  const getSelector = (node) => {
    let sel = '';

    try {
      while (node && node.nodeType !== 9) {
        const el = node;
        const part = el.id
          ? '#' + el.id
          : getName(el) +
          (el.classList &&
            el.classList.value &&
            el.classList.value.trim() &&
            el.classList.value.trim().length
            ? '.' + el.classList.value.trim().replace(/\s+/g, '.')
            : '');
        if (sel.length + part.length > (100) - 1) return sel || part;
        sel = sel ? part + '>' + sel : part;
        if (el.id) break;
        node = el.parentNode;
      }
    } catch (err) {
      // Do nothing...
    }
    return sel;
  };

  const getNodesWithTransition = (node) => {

    // Get the computed style
    let cs = window.getComputedStyle(node);
    let tp = cs['transition-property'];
    let td = cs['transition-duration'];

    // If there is a transition, add it to the table
    if (tp !== '' && tp !== 'none' && td != '0s') {
      nodeTable.push({ selector: getSelector(node), transition: cs['transition'] });
      nodeArray.push(node);
    }

    // Recursively call this function for each child node
    for (let i = 0; i < node.children.length; i++) {
      getNodesWithTransition(node.children[i]);
    }
  }

  // find all transitions
  getNodesWithTransition(document.body);

  // Display the results in the console
  console.log('%cReadable table of selectors and their transitions', 'color: red; font-weight: bold;');
  console.table(nodeTable);

  console.log('%cNodeList for you to inspect (harder to read but more info)', 'color: red; font-weight: bold;');
  console.log(nodeArray);


  // styles to temporarity override the transitions
  let selectors = nodeTable.map((item) => item.selector).join(', ');

  console.log('%cSpecific CSS to disable all transitions on this page', 'color: red; font-weight: bold;');
  console.log(`<style>${selectors}{transition-property: none !important;}</style>`);

  console.log('%cGlobal CSS to disable all transitions on this page (not suggested on production)', 'color: red; font-weight: bold;');
  console.log(`<style>*{transition-property: none !important;}</style>`);

})()

Het toont je een tabel met alle transitions, de elementen waarop ze werken en meer details over de transitions.

Om layout shifts te vinden, zoek je naar transition properties zoals width, height, margin, padding, top, left, display en vooral all (aangezien all elke geldige transition property omvat).

Stap 2: Pas CSS transitions aan

De bovenstaande JavaScript snippet toont alle transitions en geeft voorbeeldcode om deze uit te schakelen. Voor snelle testdoeleinden raad ik aan de makkelijke weg te kiezen en alle transitions uit te schakelen met één simpele regel CSS-code:

<style>*{transition-property: none !important;}</style>

Natuurlijk is voor live-omgevingen iets meer finesse vereist. Verwijder zorgvuldig alleen onnodige transition-properties per selector. Verander bijvoorbeeld #button{transition: all .2s} in #button{transition: background-color .2s}.

Stap 3: Meet de verandering in layout shift

De volgende en laatste stap is om de impact te meten. Je kunt mijn Chrome-extensie Core Web Vitals Visualizer of een RUM-tool zoals CoreDash gebruiken om de real-life impact van deze codewijzigingen te meten. In de monitoringdata van CoreDash zagen sites die transition: all vervingen door specifieke properties hun CLS gemiddeld met 40% verbeteren.

Transition best practices

  1. Specificeer altijd de exacte property: Gebruik nooit transition: all. Schrijf in plaats daarvan transition: background-color .2s ease. Dit voorkomt onbedoelde layout shifts door properties die je niet wilde animeren.
  2. Gebruik transform en opacity voor animaties: Deze twee properties worden afgehandeld door de compositor en triggeren nooit een layout. Gebruik transform: translate() om elementen te verplaatsen, transform: scale() om hun visuele grootte aan te passen, en opacity om ze te laten infaden of uitfaden. Dit is wat Google aanbeveelt voor high-performance animaties.
  3. Stel expliciete afmetingen in op geanimeerde elementen: Als een element een transition nodig heeft, zorg er dan voor dat het een expliciete width en height (of een aspect-ratio) heeft voor en na de transition. Dit voorkomt dat omliggende content verschuift. Voor meer informatie hierover, zie layout shifts oplossen die worden veroorzaakt door auto-sizing afbeeldingen.
  4. Wees voorzichtig met will-change: De CSS property will-change vertelt de browser om zich voor te bereiden op een animatie door het element naar een eigen compositor-laag te promoveren. Maar er zijn trade-offs: het creëert een nieuwe stacking context, verhoogt het GPU-geheugengebruik en vestigt een containing block voor gepositioneerde descendants. Pas het dynamisch toe met JavaScript net voordat de animatie begint, en verwijder het wanneer de animatie eindigt. Laat will-change niet permanent in je stylesheet staan.

Ondanks dit alles meldt de Web Almanac 2025 dat 40% van de mobiele pagina's nog steeds niet-gecomposited animaties uitvoert. Het goede nieuws: CLS is de Core Web Vital met het hoogste slagingspercentage van 81% op mobiel. Het slechte nieuws: als jouw site in de falende 19% zit, zijn CSS transitions mogelijk de oorzaak die je nog niet hebt gecontroleerd.

About the author

Arjen Karel is a web performance consultant and the creator of CoreDash, a Real User Monitoring platform that tracks Core Web Vitals data across hundreds of sites. He also built the Core Web Vitals Visualizer Chrome extension. He has helped clients achieve passing Core Web Vitals scores on over 925,000 mobile URLs.

Search Console flagged your site?

I deliver a prioritized fix list backed by field data. Not a 50 page PDF.

Request audit
Layout Shift veroorzaakt door CSS transitionsCore Web Vitals Layout Shift veroorzaakt door CSS transitions