Layout Shift causato dalle transizioni CSS

Scopri come trovare e rimuovere le transizioni CSS che creano layout shift

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

Perché le transizioni CSS causano layout shift

I Cumulative Layout Shift causati dalle transizioni CSS si verificano spesso all'inizio della fase di caricamento della pagina. Questi layout shift non si verificano in modo coerente, il che li rende difficili da eseguire il debug.

Ultima revisione di Arjen Karel nel marzo 2026

Il problema di transition: all

La causa più comune dei layout shift correlati alle transizioni è transition: all. Secondo il capitolo CSS del Web Almanac 2022, il 53% delle pagine utilizza transition: all. Ciò significa che ogni modifica di proprietà viene animata, comprese quelle che influiscono sul layout come width, height, margin e padding.

Una transizione CSS ha una proprietà (property), una durata (duration), una funzione di temporizzazione (timing-function) e un ritardo (delay). La scorciatoia ha questo aspetto:

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

Il problema inizia quando gli sviluppatori scrivono transition: all .3s ease invece di specificare l'esatta proprietà che vogliono animare. Durante il caricamento della pagina, un elemento above-the-fold come un menu di navigazione passa dal suo stato iniziale (senza stile) al suo stato finale (con stile o persino nascosto). Se la proprietà di transizione è all, ciò include larghezza, altezza e persino visibilità. Il risultato: un layout shift che si verifica solo durante il caricamento ed è quasi impossibile da riprodurre in modo coerente.

Quali proprietà CSS causano layout shift?

Non tutte le transizioni CSS causano layout shift. Solo le proprietà che modificano la geometria o la posizione di un elemento attivano il passaggio di layout (layout step) del browser. Secondo la ricerca di Google, le pagine che animano le proprietà CSS che inducono il layout hanno il 15% di probabilità in meno di superare il CLS. Le pagine che animano margin o border-width hanno un CLS scarso a quasi il doppio del tasso normale.

Proprietà che causano layout shift: width, height, margin, padding, top, left, right, bottom, border-width, font-size, display

Proprietà sicure (solo composite, nessun layout shift): transform, opacity, filter, clip-path

Proprietà sicure (solo paint, nessun layout shift): background-color, color, box-shadow, outline

L'intuizione chiave: transform e opacity sono gestiti interamente dal thread compositore del browser. Non attivano mai il ricalcolo del layout, quindi non contano mai ai fini del CLS. Se devi spostare un elemento, usa transform: translate() invece di top/left. Se devi ridimensionarlo visivamente, usa transform: scale() invece di width/height.

Dai un'occhiata all'esempio qui sotto. Questo dimostra un layout shift causato da transizioni CSS che si verificano durante la fase di caricamento di una pagina. Vedo questo pattern continuamente e trovare e risolvere questo tipo di problemi può essere difficile.

Trovare e risolvere le transizioni CSS

Per trovare e risolvere tutti i layout shift causati dalle transizioni CSS dobbiamo eseguire un rapido test. Prima troviamo tutte le transizioni CSS sulla pagina. Poi controlliamo se qualcuna di esse modifica le proprietà che influenzano il layout. Infine misuriamo l'impatto della disabilitazione o modifica di quelle transizioni per confermare che stavano causando il CLS.

Suggerimento per i Core Web Vitals: i Cumulative Layout Shift causati dalle transizioni CSS si verificano spesso all'inizio della fase di caricamento della pagina. Questi layout shift non si verificano in modo coerente, il che li rende difficili da eseguire il debug. Rallentare la tua rete emulando un dispositivo mobile e disabilitando la cache renderà più facile trovarli!

Passaggio 1: Trovare le transizioni CSS

La ricerca delle transizioni CSS può essere eseguita manualmente: ispeziona tutti i fogli di stile e cerca la parola "transition". Non dovrebbero volerci più di 10 minuti di lavoro, ma c'è un modo migliore! Incolla semplicemente questo snippet nella console e premi invio

(() => {

  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>`);

})()

Ti mostrerà una tabella di tutte le transizioni, degli elementi su cui stanno lavorando e maggiori dettagli sulle transizioni.

Per trovare i layout shift, cerca proprietà di transizione come width, height, margin, padding, top, left, display e in particolare all (poiché all include ogni proprietà di transizione valida).

Passaggio 2: Modificare le transizioni CSS

Lo snippet JavaScript qui sopra mostrerà tutte le transizioni e fornirà un codice di esempio su come disabilitarle. Per scopi di test rapidi ti suggerisco di prendere la strada più semplice e disabilitare tutte le transizioni con una semplice riga di codice CSS

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

Naturalmente per gli ambienti live (di produzione) è necessaria un po' più di finezza. Rimuovi attentamente solo le proprietà di transizione non necessarie per ciascun selettore. Ad esempio, cambia #button{transition: all .2s} in #button{transition: background-color .2s}

Passaggio 3: Misurare il cambiamento nel layout shift

Il prossimo e ultimo passaggio consiste nel misurare l'impatto. Puoi usare la mia estensione per chrome Core Web Vitals Visualizer o uno strumento RUM come CoreDash per misurare l'impatto nella vita reale di questi cambiamenti nel codice. Nei dati di monitoraggio di CoreDash, i siti che hanno sostituito transition: all con proprietà specifiche hanno visto migliorare il loro CLS in media del [CD:placeholder]% .

Migliori pratiche per le transizioni

  1. Specifica sempre l'esatta proprietà: Non usare mai transition: all. Scrivi invece transition: background-color .2s ease. Ciò impedisce layout shift accidentali da proprietà che non intendevi animare.
  2. Usa transform e opacity per le animazioni: Queste due proprietà sono gestite dal compositore e non attivano mai il layout. Usa transform: translate() per spostare gli elementi, transform: scale() per ridimensionarli visivamente e opacity per dissolverli. Questo è ciò che Google raccomanda per animazioni ad alte prestazioni.
  3. Imposta dimensioni esplicite sugli elementi animati: Se un elemento ha bisogno di una transizione, assicurati che abbia una larghezza e un'altezza esplicite (o un aspect ratio) prima e dopo la transizione. Ciò impedisce al contenuto circostante di spostarsi. Per saperne di più, vedi risolvere i layout shift causati da immagini con ridimensionamento automatico.
  4. Fai attenzione con will-change: La proprietà CSS will-change dice al browser di prepararsi per un'animazione promuovendo l'elemento a un proprio livello (layer) compositore. Ma ha dei compromessi: crea un nuovo contesto di impilamento (stacking context), aumenta l'utilizzo della memoria GPU e stabilisce un blocco contenitore (containing block) per i discendenti posizionati. Applicala dinamicamente con JavaScript appena prima dell'inizio dell'animazione e rimuovila al termine dell'animazione. Non lasciare will-change nel tuo foglio di stile in modo permanente.

Nonostante tutto questo, il Web Almanac 2025 riporta che il 40% delle pagine mobile esegue ancora animazioni non composite. La buona notizia: il CLS è il Core Web Vital con il tasso di superamento più alto con l'81% su dispositivi mobili. La cattiva notizia: se il tuo sito rientra nel 19% che fallisce, le transizioni CSS potrebbero essere la causa che non hai ancora controllato.

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.

Pinpoint the route, device, and connection that fails.

CoreDash segments every metric by route, device class, browser, and connection type. Real time data. Not the 28 day average Google gives you.

Explore Segmentation
Layout Shift causato dalle transizioni CSSCore Web Vitals Layout Shift causato dalle transizioni CSS