Start · Sprachen · JavaScript · Referenz · LayoutShift.sources

LayoutShift.sources

Eigenschaft

Schreibgeschützte Eigenschaft, die ein Array von <code>LayoutShiftAttribution</code>-Objekten liefert, also die DOM-Elemente, die sich bei einer Layoutverschiebung bewegt haben.

seit JavaScript Chromium-Browser (Chrome/Edge 84+); nicht in Firef Kategorie: webapi

Signatur

LayoutShift.sources

Beschreibung

Die Eigenschaft sources eines LayoutShift-Eintrags zeigt, welche Elemente eine unerwartete Layoutverschiebung verursacht haben bzw. von ihr betroffen waren. Jeder Eintrag im Array ist ein LayoutShiftAttribution-Objekt mit den Eigenschaften node (das verschobene DOM-Element), previousRect (Position und Größe vorher) und currentRect (Position und Größe nachher).

Damit ist sources das wichtigste Werkzeug, um den Core-Web-Vital-Wert Cumulative Layout Shift (CLS) zu untersuchen. Der Wert value sagt nur, wie stark sich das Layout verschoben hat. Erst sources verrät, was sich bewegt hat, etwa ein Bild ohne feste Maße, ein nachgeladenes Werbebanner oder ein Wechsel der Webschrift.

Das Array enthält höchstens fünf Einträge. Der Browser wählt die Elemente aus, die am stärksten zur Verschiebung beigetragen haben, vor allem nach ihrer betroffenen Fläche. Du erhältst die Einträge über einen PerformanceObserver mit dem Typ "layout-shift".

Rückgabewert

Typ
ReadonlyArray<LayoutShiftAttribution>
Beschreibung
Ein eingefrorenes Array mit bis zu fünf LayoutShiftAttribution-Objekten (node, previousRect, currentRect). Das Array kann leer sein.

Beispiele

Verschobene Elemente in der Konsole ausgeben

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // Verschiebungen direkt nach einer Nutzereingabe zählen nicht zum CLS
    if (entry.hadRecentInput) continue;

    console.log(`Layout-Shift: ${entry.value.toFixed(4)}`);
    for (const source of entry.sources) {
      console.log('  Element:', source.node);
      console.log('  vorher:', source.previousRect.toJSON());
      console.log('  nachher:', source.currentRect.toJSON());
    }
  }
});

observer.observe({ type: 'layout-shift', buffered: true });
Layout-Shift: 0.0842 Element: <div class="ad-banner"> vorher: {x: 0, y: 120, width: 800, height: 0, ...} nachher: {x: 0, y: 120, width: 800, height: 250, ...}

Hauptverursacher für das Monitoring ermitteln

const describeNode = (node) => {
  if (!node || node.nodeType !== Node.ELEMENT_NODE) return '(unbekannt)';
  const id = node.id ? `#${node.id}` : '';
  const cls = node.classList.length ? `.${[...node.classList].join('.')}` : '';
  return `${node.tagName.toLowerCase()}${id}${cls}`;
};

const culprits = new Map();

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (entry.hadRecentInput) continue;
    for (const { node } of entry.sources) {
      const key = describeNode(node);
      culprits.set(key, (culprits.get(key) ?? 0) + entry.value);
    }
  }
}).observe({ type: 'layout-shift', buffered: true });

// Beim Verlassen der Seite an das Analyse-Backend senden
document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden' && culprits.size) {
    navigator.sendBeacon('/analytics/cls', JSON.stringify([...culprits]));
  }
});

Verschobene Elemente während der Entwicklung hervorheben

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    for (const { node } of entry.sources) {
      // node kann null oder ein Textknoten sein
      if (node instanceof HTMLElement) {
        node.style.outline = '3px solid red';
        setTimeout(() => (node.style.outline = ''), 2000);
      }
    }
  }
}).observe({ type: 'layout-shift' });

// Wichtig · Fallstricke

  • Browserunterstützung: Die Layout Instability API gibt es nur in Chromium-Browsern wie Chrome, Edge und Opera. Firefox und Safari unterstützen sie nicht. Prüfe das vorab mit PerformanceObserver.supportedEntryTypes.includes('layout-shift').
  • Höchstens fünf Einträge: Bei großen Verschiebungen fehlen weniger wichtige Elemente im Array.
  • node kann null sein, wenn das Element inzwischen aus dem DOM entfernt wurde. Es kann auch ein Textknoten sein, nicht nur ein Element. Prüfe das immer, bevor du auf Element-Eigenschaften zugreifst.
  • Die Rechtecke beziehen sich auf den Viewport, sind also nicht dokumentbezogen. Sie berücksichtigen weder Transformationen noch Scrollen.
  • Das verschobene Element ist oft nur ein Symptom. Die eigentliche Ursache ist häufig ein Element darüber, das gewachsen ist, zum Beispiel ein Bild ohne width/height.
  • Speicher: Wenn du Einträge samt node dauerhaft speicherst, bleiben entfernte DOM-Knoten im Speicher. Speichere für das Monitoring besser Selektoren als Zeichenketten.