Layout-Shifts durch CSS-Transitions

Erfahre, wie du CSS-Transitions findest und entfernst, die Layout-Shifts verursachen

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-10-17

Warum CSS-Transitions Layout-Shifts verursachen

Cumulative Layout Shifts durch CSS-Transitions passieren meist früh, während der Ladephase der Seite. Eine Transition auf width oder height animiert die Größenänderung, wenn ein spätes Stylesheet oder Script den Style ändert. Der Inhalt darunter bewegt sich mit. Diese Shifts treten nicht bei jedem Seitenaufruf auf. Das macht sie schwer zu debuggen.

Zuletzt überprüft von Arjen Karel im März 2026

Das Problem mit transition: all

Die Ursache, die ich am häufigsten finde, ist transition: all. Es ist überall. Laut dem CSS-Kapitel des Web Almanac 2022 nutzen es 53 % der Seiten – mehr als jede andere Transition-Eigenschaft. Damit werden auch width und height animiert und verschieben den Inhalt um das Element herum.

Eine CSS-Transition besteht aus vier Teilen: Eigenschaft, Dauer, Timing-Funktion und Verzögerung. In der Kurzschreibweise:

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

Das Problem beginnt mit transition: all .3s ease an einem Element, bei dem der Entwickler eigentlich nur eine Hover-Farbe überblenden wollte.

Eine Transition greift nie beim ersten Style, den der Browser für ein Element berechnet. Sie greift erst, wenn sich dieser Style später ändert. Beim Laden der Seite passiert das ständig: ein Stylesheet, das spät eintrifft, oder ein Script, das dem Navigationsmenü eine Klasse hinzufügt. Mit transition: all animiert der Browser auch die Größenänderung. Das Menü Above the Fold wächst über 300 Millisekunden an seinen Platz und schiebt alles darunter nach unten. Ein Layout-Shift, der nur beim Laden passiert. Viel Glück beim Reproduzieren.

Welche CSS-Eigenschaften verursachen Layout-Shifts?

Nicht jede CSS-Transition verursacht Layout-Shifts. Nur wenn eine Eigenschaft Größe oder Position eines Elements ändert, berechnet der Browser das Layout neu. Und nur das Layout verschiebt den Inhalt um das Element herum. Laut Googles Daten bestehen Seiten, die layout-auslösende CSS-Eigenschaften animieren, den CLS mit 15 % geringerer Wahrscheinlichkeit. Margin und border-width sind noch schlimmer. Seiten, die diese Eigenschaften animieren, haben fast doppelt so oft einen schlechten CLS.

Jede dieser Eigenschaften zwingt den Browser, das Layout neu zu berechnen. Eine Transition darauf kann das Element selbst oder den umgebenden Inhalt verschieben: width, height, margin, padding, top, left, right, bottom, border-width, font-size.

Sicher für den CLS: transform und opacity können auf dem Compositor laufen. Filter und clip-path kosten höchstens einen Repaint. Keines der Paare löst ein Layout aus.

Nur Paint, also ebenfalls sicher für den CLS: background-color, color, box-shadow, outline.

Entscheidend sind transform und opacity. Ein Transform ändert die Position des Elements im Layout nicht. Der CLS zählt das daher nie als Layout-Shift. Du musst ein Element bewegen? Nutze transform: translate() statt top und left. Um es größer oder kleiner wirken zu lassen, nutze transform: scale() statt width und height.

Hover ist ebenfalls keine Ausrede. Der CLS ignoriert Shifts in den 500 ms nach einem Klick, einem Tap oder einem Tastendruck. Die Maus über ein Element zu bewegen, gilt jedoch nicht als solche Interaktion. Eine Hover-Transition auf width zählt also voll.

Das Video unten zeigt eine Transition, die das Layout während der Ladephase verschiebt. Das sehe ich ständig. Um das zu finden, muss man etwas genauer hinschauen.

CSS-Transitions finden und beheben

Um jeden Layout-Shift durch eine CSS-Transition zu finden, liste zuerst alle Transitions auf der Seite auf. Prüfe, welche davon eine layout-relevante Eigenschaft animieren. Deaktiviere oder ändere sie und miss nach, ob der CLS verschwindet.

Core-Web-Vitals-Tipp: Diese Shifts passieren früh beim Laden der Seite und nicht bei jedem Besuch. Emuliere ein Mobilgerät, drossle das Netzwerk und deaktiviere den Cache. Bei einem langsamen Ladevorgang rendert der Browser die Seite, bevor das späte Stylesheet oder Script eintrifft. So zeigt sich der Shift deutlich häufiger.

Schritt 1: CSS-Transitions finden

Du kannst CSS-Transitions von Hand suchen: Öffne jedes Stylesheet und suche nach dem Wort „transition“. Zehn Minuten, vielleicht. Schneller: Füge dieses Snippet in die Konsole ein und drücke 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>`);

})()

Es gibt eine Tabelle mit allen Transitions auf der Seite und dem jeweiligen Element aus.

Lies jetzt die Spalte „transition“ ab. Beginne mit jeder Zeile, in der all steht: Das deckt jede Eigenschaft ab, die animiert werden kann – inklusive width und height. Suche dann nach Zeilen, die width oder height direkt nennen. Auch margin und padding verschieben Inhalte, genau wie top und left.

Schritt 2: CSS-Transitions anpassen

Das Snippet gibt auch direkt das CSS aus, um diese Transitions abzuschalten. Für einen schnellen Test mach es dir einfach und deaktiviere jede Transition mit einer Zeile:

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

Auf einer Live-Seite brauchst du etwas mehr Feingefühl. Entferne nur die Transition-Eigenschaften, die du nicht brauchst – Selektor für Selektor. Ändere zum Beispiel #button{transition: all .2s} zu #button{transition: background-color .2s}.

Schritt 3: Layout-Shifts nach der Änderung messen

Letzter Schritt: Messen. Meine Chrome-Extension Core Web Vitals Visualizer zeigt die Shifts auf deinem eigenen Bildschirm. Ein RUM-Tool wie CoreDash zeigt, ob sie auch bei echten Besuchern verschwunden sind. In CoreDash kannst du den CLS nach dem verschobenen Element aufschlüsseln. Nach der Änderung sollte das Menü oder Banner aus der Liste verschwinden – und der mobile p75 folgen.

Best Practices für Transitions

  1. Nenne die genaue Eigenschaft. Schreibe transition: background-color .2s ease statt transition: all. So kann keine Eigenschaft, die du gar nicht animieren wolltest, etwas verschieben.
  2. Animiere transform und opacity. Der Browser kann beides auf dem Compositor ausführen, und keines von beiden löst ein Layout aus. Nutze transform: translate(), um ein Element zu bewegen, und transform: scale(), um seine Größe zu ändern. Opacity blendet es weich über. Genau das empfiehlt auch Google.
  3. Gib einem Element, das eine Transition durchläuft, sowohl vor als auch nach der Transition eine explizite width und height oder ein Seitenverhältnis, damit der Inhalt drumherum an Ort und Stelle bleibt. Mehr dazu unter Layout-Shifts durch Bilder mit automatischer Größenanpassung beheben.
  4. Geh sparsam mit will-change um. Es weist den Browser an, sich auf eine Animation vorzubereiten, und hebt das Element auf einen eigenen Compositor-Layer. Das hat seinen Preis. Mit will-change: transform bekommt das Element einen neuen Stacking-Context und wird zum Containing-Block für seine positionierten Kindelemente. Und jeder zusätzliche Layer kostet GPU-Speicher. Setze es mit JavaScript kurz vor dem Start der Animation und entferne es, sobald sie beendet ist. Lass es nicht dauerhaft im Stylesheet.

Viele Websites machen das immer noch falsch. Der Web Almanac 2025 findet auf 40 % der mobilen Seiten nicht-kompositierte Animationen. Der CLS ist der Core Web Vital mit der höchsten Bestehensquote: 81 % auf Mobilgeräten. Gehört deine Seite zu den 19 %, die durchfallen, sind CSS-Transitions vielleicht die Ursache, die du noch nicht geprüft hast.

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.

Arjen Karel

Brauchst du eine schnellere Website?

Ich bin Arjen und mache seit 17 Jahren langsame Websites schnell. Wenn du auf Probleme stößt, die du nicht selbst lösen kannst, schick mir deine URL und wir reden darüber.

Schick mir deine URL
Arjen Karel
Arjen Karel, Web-Performance-Consultant seit 2009

Warum funktioniert unser Fix nicht?

Manchmal liefert das CDN noch das alte HTML aus, oder der Fix steckt im Desktop-Template und Mobilgeräte nutzen ein anderes. Schick mir deine URL und das Problem, dann antworte ich mit ein paar Terminvorschlägen. Ich prüfe zuerst deine Field Data, dann arbeiten wir eine Stunde an deiner Website, und innerhalb eines Tages hast du meine Notizen schriftlich. 350 € zzgl. MwSt.

Schick mir deine URL

Kein Entwickler für den Fix? Ich mache die Arbeit selbst, auf einer Kopie deiner Website.

Layout-Shifts durch CSS-Transitions Core Web Vitals Layout-Shifts durch CSS-Transitions