Start · Sprachen · JavaScript · Referenz · LayoutShift.hadRecentInput

LayoutShift.hadRecentInput

Eigenschaft

Schreibgeschützter boolescher Wert: <code>true</code>, wenn die letzte Nutzereingabe vor der Layoutverschiebung weniger als 500 ms zurückliegt.

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

Signatur

LayoutShift.hadRecentInput

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

Typ
boolean
Beschreibung
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 });
Unerwartete Verschiebung: 0.0421

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 });
Aktueller CLS: 0.087

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);
  }
});
┌────────────┬────────┐ │ expected │ 0.12 │ │ unexpected │ 0.03 │ └────────────┴────────┘

// 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 mit PerformanceObserver.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 === false und 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-vitals zu empfehlen. Sie wertet hadRecentInput und die Session-Fenster korrekt aus.