Signatur
Beschreibung
Die schreibgeschützte Eigenschaft paintTime eines LargestContentfulPaint-Eintrags gibt den Zeitpunkt an, an dem der Browser die Renderphase des Frames abgeschlossen und mit der Malphase begonnen hat. Das ist der Frame, in dem das größte sichtbare Inhaltselement (Bild, Textblock, Video-Poster usw.) zum ersten Mal gezeichnet wurde. Der Wert ist ein DOMHighResTimeStamp in Millisekunden, relativ zu performance.timeOrigin.
paintTime kommt aus dem PaintTimingMixin der Paint-Timing-Spezifikation und steht zusammen mit presentationTime zur Verfügung. paintTime markiert den Beginn des Malens auf dem Hauptthread. presentationTime dagegen gibt an, wann die Pixel tatsächlich auf dem Bildschirm zu sehen waren (nach Rasterung, Compositing und VSync). Der Abstand zwischen beiden Werten zeigt, wie viel Zeit im Compositor bzw. in der GPU-Pipeline vergeht.
Nützlich ist die Eigenschaft vor allem für genaue Core-Web-Vitals-Analysen: Zieht man loadTime (Ressource geladen) von paintTime ab, sieht man die Render-Verzögerung des LCP-Elements, also z. B. Wartezeit durch blockierende Skripte, Layout oder Stylesheets. Das hilft beim Unterscheiden, ob ein schlechter LCP-Wert am Netzwerk oder am Rendering liegt.
Rückgabewert
performance.timeOrigin), an dem die Renderphase endete und die Malphase für das LCP-Element begann. Bei ursprungsfremden Bildern ohne Timing-Allow-Origin-Header kann der Wert vergröbert sein.Beispiele
paintTime des LCP-Kandidaten protokollieren
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if ('paintTime' in entry) {
console.log('LCP-Element:', entry.element?.tagName);
console.log('paintTime:', entry.paintTime.toFixed(1), 'ms');
} else {
console.log('paintTime nicht unterstützt, startTime:', entry.startTime);
}
}
});
observer.observe({ type: 'largest-contentful-paint', buffered: true });
Render-Verzögerung und Präsentationsdauer berechnen
new PerformanceObserver((list) => {
const entries = list.getEntries();
const lcp = entries[entries.length - 1]; // letzter = aktueller LCP-Kandidat
if (!('paintTime' in lcp)) return;
// loadTime ist bei Text-Elementen 0
const renderDelay = lcp.loadTime > 0 ? lcp.paintTime - lcp.loadTime : null;
const presentationDelay = lcp.presentationTime
? lcp.presentationTime - lcp.paintTime
: null;
console.table({
loadTime: lcp.loadTime,
paintTime: lcp.paintTime,
presentationTime: lcp.presentationTime,
renderDelay,
presentationDelay,
});
}).observe({ type: 'largest-contentful-paint', buffered: true });
Wert mit Fallback an ein Analytics-Backend senden
let lastLcp;
new PerformanceObserver((list) => {
lastLcp = list.getEntries().at(-1);
}).observe({ type: 'largest-contentful-paint', buffered: true });
// Beim Verlassen der Seite endgültigen Wert senden
document.addEventListener('visibilitychange', () => {
if (document.visibilityState !== 'hidden' || !lastLcp) return;
const payload = {
lcp: lastLcp.startTime,
paintTime: lastLcp.paintTime ?? null, // null in nicht unterstützenden Browsern
url: lastLcp.url || null,
};
navigator.sendBeacon('/analytics/lcp', JSON.stringify(payload));
});
// Wichtig · Fallstricke
- Experimentell:
paintTime(undpresentationTime) werden derzeit nur von neueren Chromium-Browsern unterstützt. Prüfe vor der Nutzung mit'paintTime' in entryund greife sonst aufstartTimebzw.renderTimezurück. paintTimeist nicht der Zeitpunkt, an dem der Nutzer die Pixel sieht. Dafür istpresentationTimegedacht, dessen Genauigkeit aber vom Browser abhängt und das auch fehlen kann.- Bei ursprungsfremden Bildern ohne
Timing-Allow-Origin-Antwortheader können Zeitwerte aus Sicherheitsgründen (Timing-Angriffe) vergröbert werden. - Pro Seitenaufruf können mehrere LCP-Einträge entstehen. Maßgeblich ist der letzte vor der ersten Nutzereingabe bzw. bevor der Tab in den Hintergrund wechselt.
- Bei Text-Elementen ist
loadTimegleich0. Rechnungen wiepaintTime - loadTimeergeben dort keinen Sinn.