Layout Shift veroorzaakt door CSS transitions
Leer hoe je CSS transitions vindt en verwijdert die layout shifts veroorzaken
Waarom CSS transitions layout shifts veroorzaken
Cumulative Layout Shifts door CSS transitions ontstaan meestal vroeg, tijdens de laadfase van de pagina. Een transition op width of height animeert de verandering in grootte als een laat stylesheet of script de styles aanpast, en de content daaronder beweegt mee. Deze shifts gebeuren niet bij elke pageview. Dat maakt ze lastig te debuggen.
Laatst gecontroleerd door Arjen Karel in maart 2026
Het probleem met transition: all
De oorzaak die ik het vaakst tegenkom is transition: all. Je ziet het overal. Volgens het CSS-hoofdstuk van de Web Almanac 2022 gebruikt 53% van de pagina's dit, meer dan elke andere transition-property. Width en height animeren dus ook mee, en die verplaatsen de content rond het element.
Een CSS transition bestaat uit vier onderdelen: de property, de duration, de timing function en een delay. In shorthand:
/* property | duration | timing-function | delay */
transition: margin-right 4s ease-in-out 1s; Het probleem begint met transition: all .3s ease op een element waar de developer alleen de hover-kleur wilde laten faden.
Een transition draait nooit op de eerste style die de browser voor een element berekent. Hij draait pas als die style later verandert, en tijdens het laden van de pagina gebeurt dat vaak: een stylesheet dat laat binnenkomt, of een script dat een class toevoegt aan het navigatiemenu. Met transition: all animeert de browser ook de verandering in grootte. Het menu above the fold groeit dan in 300 milliseconden op zijn plek en duwt alles eronder naar beneden. Een layout shift die alleen tijdens het laden ontstaat. Zie dat maar eens te reproduceren.
Welke CSS-properties veroorzaken layout shifts?
Niet elke CSS transition veroorzaakt layout shifts. Alleen een property die de grootte of positie van een element verandert zorgt dat de browser layout opnieuw berekent, en alleen layout verplaatst de content eromheen. Volgens onderzoek van Google hebben pagina's die layout-triggerende CSS-properties animeren 15% minder kans om voor CLS te slagen. Margin en border-width zijn nog erger. Pagina's die deze animeren hebben bijna twee keer zo vaak een slechte CLS.
Elk van deze properties triggert een layout-herberekening, dus een transition hierop kan het element zelf of de content eromheen verplaatsen: width, height, margin, padding, top, left, right, bottom, border-width, font-size.
Veilig voor CLS: transform en opacity kunnen op de compositor draaien. Filter en clip-path kosten hooguit een repaint. Geen van beide paren triggert layout.
Alleen paint, dus ook veilig voor CLS: background-color, color, box-shadow, outline.
Transform en opacity zijn de twee die ertoe doen. Een transform verandert de positie van het element in de layout niet, dus telt CLS dit nooit mee als een layout shift. Moet je een element verplaatsen? Gebruik transform: translate() in plaats van top en left. Wil je het groter of kleiner laten lijken, gebruik dan transform: scale() in plaats van width en height.
Hover is ook geen excuus. CLS negeert shifts binnen 500 ms na een klik, tik of toetsaanslag, maar met de muis over een element bewegen valt daar niet onder. Een hover-transition op width telt dus volledig mee.
De video hieronder laat zien hoe een transition de layout verschuift tijdens de laadfase. Ik zie dit voortdurend. Je moet even graven om het te vinden.
CSS transitions vinden en fixen
Om elke layout shift door een CSS transition te vinden, breng je eerst alle transitions op de pagina in kaart en controleer je welke een property animeren die de layout beïnvloedt. Schakel die uit of pas ze aan, en meet of de CLS verdwijnt.
Core Web Vitals tip: deze shifts gebeuren vroeg tijdens het laden van de pagina, en niet bij elk bezoek. Emuleer een mobiel apparaat, throttle het netwerk en schakel de cache uit. Bij een trage laadtijd paint de browser de pagina voordat dat late stylesheet of script binnenkomt, waardoor de shift veel vaker opduikt.
Stap 1: CSS transitions vinden
Je kunt CSS transitions met de hand opzoeken: open elk stylesheet en zoek op het woord 'transition'. Kost je misschien tien minuten. Sneller: plak dit 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 print een tabel met elke transition op de pagina en het element waar die op zit.

Bekijk nu de transition-kolom. Begin bij elke rij met all: die dekt elke property af die geanimeerd kan worden, inclusief width en height. Zoek daarna naar rijen die width of height direct noemen. Margin en padding verplaatsen ook content, net als top en left.
Stap 2: CSS transitions aanpassen
Het snippet print ook de CSS om die transitions uit te schakelen. Kies voor een snelle test de makkelijke weg en schakel elke transition uit met één regel:
<style>*{transition-property: none !important;}</style>Op een live site heb je wat meer finesse nodig. Verwijder alleen de transition-properties die je niet nodig hebt, selector voor selector. Verander bijvoorbeeld #button{transition: all .2s} in #button{transition: background-color .2s}.
Stap 3: De verandering in layout shift meten

Best practices voor transitions
- Noem de exacte property. Schrijf
transition: background-color .2s easein plaats vantransition: all, dan kan een property die je niet wilde animeren niets verschuiven. - Animeer transform en opacity. De browser kan beide op de compositor draaien en geen van beide triggert layout. Gebruik
transform: translate()om een element te verplaatsen entransform: scale()om het te schalen. Opacity laat het faden. Dat is ook wat Google aanbeveelt. - Geef een element met een transition een expliciete width en height, of een aspect ratio, zowel vóór als na de transition, zodat de content eromheen op zijn plek blijft. Meer daarover in layout shifts door auto-sizing afbeeldingen fixen.
- Wees terughoudend met
will-change. Het vertelt de browser om zich voor te bereiden op een animatie door het element naar een eigen compositor layer te promoveren. Dat heeft een prijs. Metwill-change: transformkrijgt het element een nieuwe stacking context en wordt het het containing block voor zijn gepositioneerde descendants, en elke extra layer kost GPU-geheugen. Zet het met JavaScript vlak voor de animatie start aan en verwijder het zodra de animatie klaar is. Laat het niet permanent in je stylesheet staan.
Genoeg sites doen dit nog steeds verkeerd. Het Web Almanac 2025 vindt non-composited animaties op 40% van de mobiele pagina's. CLS is de Core Web Vital met het hoogste slagingspercentage: 81% op mobiel. Zit je site bij de 19% die het niet haalt, dan zijn CSS transitions misschien de oorzaak die je nog niet hebt gecheckt.

Een snellere site nodig?
Ik ben Arjen en ik maak al 17 jaar trage sites snel. Loop je tegen iets aan dat je zelf niet opgelost krijgt? Stuur me je URL, dan praten we even.
Stuur me je URL
Waarom werkt onze fix niet?
Soms serveert het CDN nog de oude HTML, of de fix zit in het desktop-template terwijl mobiel een ander template gebruikt. Stuur me je URL en het probleem, dan stuur ik je een paar momenten. Ik bekijk eerst je field data, daarna besteden we een uur aan je site, en binnen een dag heb je mijn notities op schrift. €350 excl. btw.
Stuur me je URLGeen developer om de fix te bouwen? Ik doe het werk zelf, op een kopie van je site.