Signatur
Beschreibung
Die Eigenschaft hadRecentInput eines LayoutShift-Eintrags zeigt an, ob die Layoutverschiebung kurz nach einer Nutzereingabe passiert ist. Das heißt: lastInputTime liegt weniger als 500 Millisekunden vor der Verschiebung. Die Eigenschaft ist schreibgeschützt und liefert immer einen booleschen Wert.
Wichtig ist sie für den Cumulative Layout Shift (CLS), eine der Core Web Vitals. Verschiebungen, die direkt auf eine Nutzeraktion folgen, gelten als erwartet. Das ist etwa der Fall, wenn ein Akkordeon nach einem Klick aufklappt. Solche Verschiebungen sollen nicht in den CLS-Wert einfließen. Wer CLS selbst misst, filtert deshalb alle Einträge mit hadRecentInput === true heraus.
Als „Eingabe“ zählen einzelne Aktionen wie Klicks, Tippen (Tap) und Tastendrücke. Scrollen, Mausbewegungen und Pinch-Zoom zählen nicht. Bei einer Verschiebung während des Scrollens bleibt hadRecentInput also false.
Rückgabewert
true, wenn innerhalb der letzten 500 ms vor der Verschiebung eine einzelne Nutzereingabe stattfand, sonst false.Beispiele
Unerwartete Layoutverschiebungen protokollieren
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Verschiebungen direkt nach einer Nutzereingabe überspringen
if (entry.hadRecentInput) continue;
console.log('Unerwartete Verschiebung:', entry.value.toFixed(4));
}
});
observer.observe({ type: 'layout-shift', buffered: true });
CLS nach dem Session-Window-Verfahren berechnen
let clsValue = 0;
let sessionValue = 0;
let sessionEntries = [];
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.hadRecentInput) continue; // erwartete Verschiebung
const first = sessionEntries[0];
const last = sessionEntries.at(-1);
// Neues Fenster: Lücke über 1 s oder Fensterdauer über 5 s
if (
sessionEntries.length &&
(entry.startTime - last.startTime > 1000 ||
entry.startTime - first.startTime > 5000)
) {
sessionValue = 0;
sessionEntries = [];
}
sessionValue += entry.value;
sessionEntries.push(entry);
clsValue = Math.max(clsValue, sessionValue);
}
console.log('Aktueller CLS:', clsValue.toFixed(3));
});
observer.observe({ type: 'layout-shift', buffered: true });
Erwartete und unerwartete Verschiebungen getrennt zählen
const stats = { expected: 0, unexpected: 0 };
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
stats[entry.hadRecentInput ? 'expected' : 'unexpected'] += entry.value;
}
}).observe({ type: 'layout-shift', buffered: true });
// Beim Verlassen der Seite ausgeben bzw. an ein Analyse-Backend senden
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
console.table(stats);
}
});
// Wichtig · Fallstricke
- Browser-Unterstützung: Die Layout Instability API gibt es nur in Chromium-Browsern (Chrome, Edge, Opera). Firefox und Safari liefern keine
layout-shift-Einträge. Prüfe die Unterstützung vorher mitPerformanceObserver.supportedEntryTypes.includes('layout-shift'). - Experimentelle API: Die Spezifikation ist ein Entwurf der WICG und kein fertiger W3C-Standard.
- Scrollen zählt nicht als Eingabe: Verschiebungen beim Scrollen, etwa durch nachladende Bilder, haben
hadRecentInput === falseund gehen in den CLS ein. - Die 500-ms-Grenze ist fest: Dauert eine Animation nach einem Klick länger, zählen spätere Verschiebungen wieder als unerwartet. Nutze für Animationen besser
transform, denn das löst keine Layoutverschiebung aus. - Verwende
buffered: true. Sonst fehlen Einträge, die vor der Registrierung des Observers entstanden sind. - Für den Produktionseinsatz ist die Bibliothek
web-vitalszu empfehlen. Sie wertethadRecentInputund die Session-Fenster korrekt aus.