Signatur
Beschreibung
Die schreibgeschützte Eigenschaft styleAndLayoutStart gehört zu PerformanceLongAnimationFrameTiming, dem Eintragstyp "long-animation-frame" der Long Animation Frames API (LoAF). Sie gibt den Zeitpunkt in Millisekunden relativ zu performance.timeOrigin an, an dem der Browser im betroffenen Frame mit der Neuberechnung von Stilen und Layout begonnen hat.
Zusammen mit startTime, renderStart und duration lässt sich ein langer Frame in Phasen zerlegen:
- Skript-/Aufgabenphase: von
startTimebisrenderStart - Vorbereitung des Renderings (
requestAnimationFrame-Callbacks,ResizeObserverusw.): vonrenderStartbisstyleAndLayoutStart - Stil und Layout: von
styleAndLayoutStartbisstartTime + duration
Die Eigenschaft eignet sich, um herauszufinden, ob ein ruckelnder Frame oder eine schlechte INP-Metrik (Interaction to Next Paint) durch aufwendige CSS-Selektoren, große DOM-Bäume oder erzwungene Layout-Neuberechnungen verursacht wird. Hat im Frame kein Rendering stattgefunden, ist der Wert 0.
Rückgabewert
performance.timeOrigin, an dem die Stil- und Layoutphase begonnen hat, oder 0, wenn im Frame nicht gerendert wurde.Beispiele
Stil- und Layoutdauer langer Frames messen
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!entry.styleAndLayoutStart) continue; // kein Rendering im Frame
const frameEnde = entry.startTime + entry.duration;
const layoutDauer = frameEnde - entry.styleAndLayoutStart;
console.log(`Frame: ${entry.duration.toFixed(1)} ms, davon Stil/Layout: ${layoutDauer.toFixed(1)} ms`);
}
});
observer.observe({ type: 'long-animation-frame', buffered: true });
Frame in Phasen aufschlüsseln
const phasen = (entry) => {
const ende = entry.startTime + entry.duration;
const renderStart = entry.renderStart || ende;
const layoutStart = entry.styleAndLayoutStart || ende;
return {
skripte: Math.round(renderStart - entry.startTime),
renderVorbereitung: Math.round(layoutStart - renderStart),
stilUndLayout: Math.round(ende - layoutStart)
};
};
new PerformanceObserver((list) => {
list.getEntries().forEach((e) => console.table(phasen(e)));
}).observe({ type: 'long-animation-frame', buffered: true });
Layout-lastige Frames mit Feature-Erkennung an ein Monitoring senden
if (PerformanceObserver.supportedEntryTypes?.includes('long-animation-frame')) {
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!entry.styleAndLayoutStart) continue;
const layoutMs = entry.startTime + entry.duration - entry.styleAndLayoutStart;
if (layoutMs > 50) {
navigator.sendBeacon('/rum/layout', JSON.stringify({
url: location.pathname,
layoutMs: Math.round(layoutMs),
frameMs: Math.round(entry.duration)
}));
}
}
}).observe({ type: 'long-animation-frame', buffered: true });
} else {
console.log('Long Animation Frames API wird nicht unterstützt.');
}
// Wichtig · Fallstricke
- Kompatibilität: Nur in Chromium-Browsern (Chrome/Edge ab 123) verfügbar; Firefox und Safari unterstützen die Long Animation Frames API nicht. Vorher immer
PerformanceObserver.supportedEntryTypesprüfen. - Der Wert ist
0, wenn im Frame kein Rendering stattfand – ohne Prüfung entstehen unsinnig große Dauern. - Erzwungene synchrone Layouts (z. B. Lesen von
offsetHeightdirekt nach DOM-Änderungen) fallen nicht in diese Phase, sondern in die Skriptzeit; siehe dazuforcedStyleAndLayoutDurationder einzelnenPerformanceScriptTiming-Einträge inscripts. - Einträge werden nur für Frames über 50 ms erzeugt; kurze Frames lassen sich damit nicht analysieren.
- Die Zeitauflösung kann aus Sicherheitsgründen (Schutz vor Timing-Angriffen) reduziert sein, besonders ohne Cross-Origin-Isolation.