Signatur
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
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 });
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.
nodekannnullsein, 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
nodedauerhaft speicherst, bleiben entfernte DOM-Knoten im Speicher. Speichere für das Monitoring besser Selektoren als Zeichenketten.