Start · Sprachen · JavaScript · Referenz · PerformancePaintTiming

PerformancePaintTiming

Schnittstelle

Stellt Zeitstempel für Paint-Meilensteine wie <code>first-paint</code> und <code>first-contentful-paint</code> während des Seitenaufbaus bereit.

seit JavaScript Chrome/Edge 60+, Firefox 84+, Safari 14.1+ (Safari Kategorie: webapi

Signatur

interface PerformancePaintTiming extends PerformanceEntry

Beschreibung

PerformancePaintTiming ist Teil der Paint Timing API und liefert Leistungseinträge vom Typ "paint". Jeder Eintrag steht für einen Render-Meilenstein beim Laden einer Seite. Zwei gibt es:

  • first-paint (FP): Zeitpunkt, zu dem der Browser zum ersten Mal irgendetwas zeichnet, das sich vom Standardhintergrund unterscheidet, z. B. eine Hintergrundfarbe.
  • first-contentful-paint (FCP): Zeitpunkt, zu dem erstmals DOM-Inhalt gezeichnet wird, also Text, Bilder (auch Hintergrundbilder), nicht-weiße <canvas>-Elemente oder SVG.

Das Interface hat keinen eigenen Konstruktor und keine zusätzlichen Methoden. Es erbt alles von PerformanceEntry: name ist "first-paint" oder "first-contentful-paint", entryType ist immer "paint", startTime ist der Zeitpunkt des Paints in Millisekunden relativ zu performance.timeOrigin, und duration ist immer 0.

Einsatzbereich ist vor allem das Real User Monitoring (RUM): FCP gehört zu den zentralen Web-Vitals-Kennzahlen dafür, wie schnell eine Seite wahrgenommen wird. Die Einträge liest man am besten mit einem PerformanceObserver und der Option buffered: true aus. So bekommt man auch Paints mit, die schon vor der Registrierung des Observers passiert sind. Alternativ geht performance.getEntriesByType("paint").

Parameter

Name Typ Default Beschreibung
$name string Geerbte Eigenschaft (nur lesbar): "first-paint" oder "first-contentful-paint".
$entryType string "paint" Geerbte Eigenschaft (nur lesbar): immer "paint".
$startTime DOMHighResTimeStamp Geerbte Eigenschaft (nur lesbar): Zeitpunkt des Paints in ms seit performance.timeOrigin.
$duration number 0 Geerbte Eigenschaft (nur lesbar): bei Paint-Einträgen immer 0.

Rückgabewert

Typ
PerformancePaintTiming
Beschreibung
Instanzen entstehen nur durch den Browser und werden über PerformanceObserver oder performance.getEntriesByType("paint") abgerufen. toJSON() liefert eine JSON-fähige Darstellung des Eintrags.

Beispiele

FCP mit PerformanceObserver messen

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log(`${entry.name}: ${entry.startTime.toFixed(1)} ms`);
  }
});

// buffered: true liefert auch Einträge, die schon vor dem Registrieren entstanden sind
observer.observe({ type: "paint", buffered: true });
first-paint: 412.3 ms first-contentful-paint: 412.3 ms

Paint-Einträge nachträglich abfragen

window.addEventListener("load", () => {
  const paints = performance.getEntriesByType("paint");
  const fcp = paints.find((e) => e.name === "first-contentful-paint");

  if (fcp) {
    console.log(fcp instanceof PerformancePaintTiming); // true
    console.log(fcp.toJSON());
  } else {
    console.log("Noch kein FCP erfasst");
  }
});
true { name: "first-contentful-paint", entryType: "paint", startTime: 412.3, duration: 0 }

FCP an einen Analytics-Endpunkt senden

const reportFCP = () => {
  const observer = new PerformanceObserver((list) => {
    const fcp = list.getEntriesByName("first-contentful-paint")[0];
    if (!fcp) return;

    const payload = JSON.stringify({
      metric: "FCP",
      value: Math.round(fcp.startTime),
      page: location.pathname,
    });
    navigator.sendBeacon("/analytics/vitals", payload);
    observer.disconnect(); // FCP tritt nur einmal auf
  });

  observer.observe({ type: "paint", buffered: true });
};

if (PerformanceObserver.supportedEntryTypes?.includes("paint")) {
  reportFCP();
}

// Wichtig · Fallstricke

  • Browser-Unterstützung: Chromium-Browser unterstützen beide Einträge, Firefox seit Version 84. Safari (ab 14.1) meldet nur first-contentful-paint, kein first-paint. Vorher mit PerformanceObserver.supportedEntryTypes prüfen, ob "paint" unterstützt wird.
  • Hintergrund-Tabs: Wird die Seite im Hintergrund geladen (document.visibilityState === "hidden"), erzeugt der Browser eventuell gar keine Paint-Einträge, oder sie liefern stark verzerrte Werte. Für RUM-Messungen solche Seitenaufrufe herausfiltern.
  • Ohne buffered: true verpasst der Observer oft den FCP, weil er meist schon vor dem Registrieren des Observers passiert ist.
  • Ein Eintrag entsteht nur einmal pro Seitenladevorgang. Bei SPA-Routenwechseln gibt es keine neuen Paint-Einträge; dafür eignen sich largest-contentful-paint oder eigene performance.mark()-Marken.
  • Neuere Chromium-Versionen ergänzen experimentell die Eigenschaften paintTime und presentationTime. Diese sind noch nicht browserübergreifend verfügbar.
  • Die Werte werden aus Datenschutzgründen (Timing-Angriffe) gröber aufgelöst. Sie reichen für Kennzahlen, aber nicht für Messungen im Mikrosekundenbereich.