Signatur
Beschreibung
Die schreibgeschützte Eigenschaft intersectionRect eines PerformanceElementTiming-Eintrags liefert ein DOMRectReadOnly. Es beschreibt, welcher Teil des Elements beim Rendern im Viewport lag. Gemeint ist die Schnittfläche aus Element-Box und Viewport, also genau der Bereich, den Nutzer tatsächlich zu sehen bekamen.
Solche Einträge gibt es nur für Elemente mit dem HTML-Attribut elementtiming. Du liest sie über einen PerformanceObserver mit dem Eintragstyp "element" aus. Die Werte sind CSS-Pixel relativ zum Viewport (x, y, width, height, top, right, bottom, left).
Wofür das praktisch ist:
- Du prüfst, ob ein wichtiges Element (Hero-Bild, Überschrift) beim ersten Rendern wirklich sichtbar war oder nur teilweise bzw. gar nicht.
- Du berechnest den sichtbaren Flächenanteil, um Messwerte zu gewichten. Das ähnelt dem Vorgehen bei Largest Contentful Paint.
- Du filterst Messungen heraus, bei denen das Element außerhalb des sichtbaren Bereichs lag.
Liegt das Element beim Rendern komplett außerhalb des Viewports, ist das Rechteck leer: width und height sind dann 0.
Rückgabewert
0.Beispiele
Sichtbares Rechteck eines Hero-Bildes ausgeben
// HTML: <img src="hero.jpg" elementtiming="hero-bild">
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
const { x, y, width, height } = entry.intersectionRect;
console.log(`${entry.identifier}: x=${x}, y=${y}, ${width}×${height}px`);
}
});
observer.observe({ type: 'element', buffered: true });
Sichtbaren Flächenanteil berechnen
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
const sichtbar = entry.intersectionRect;
const el = entry.element;
if (!el) continue; // Element evtl. schon aus dem DOM entfernt
// Gerenderte Gesamtgröße des Elements
const gesamt = el.getBoundingClientRect();
const gesamtFlaeche = gesamt.width * gesamt.height;
const anteil = gesamtFlaeche > 0
? (sichtbar.width * sichtbar.height) / gesamtFlaeche
: 0;
console.log(`${entry.identifier}: ${(anteil * 100).toFixed(1)} % sichtbar`);
}
});
observer.observe({ type: 'element', buffered: true });
Nur Einträge sichtbarer Elemente an die Analytics senden
const observer = new PerformanceObserver((list) => {
const sichtbareEintraege = list.getEntries()
.filter((e) => e.intersectionRect.width > 0 && e.intersectionRect.height > 0)
.map((e) => ({
id: e.identifier,
renderTime: Math.round(e.renderTime || e.loadTime),
flaeche: Math.round(e.intersectionRect.width * e.intersectionRect.height)
}));
if (sichtbareEintraege.length > 0) {
navigator.sendBeacon('/analytics/element-timing', JSON.stringify(sichtbareEintraege));
}
});
if (PerformanceObserver.supportedEntryTypes?.includes('element')) {
observer.observe({ type: 'element', buffered: true });
}
// Wichtig · Fallstricke
Browser-Kompatibilität: Die Element Timing API ist experimentell. Sie funktioniert nur in Chromium-Browsern (Chrome, Edge, Opera). Firefox und Safari unterstützen sie nicht. Prüfe deshalb vorher, ob PerformanceObserver.supportedEntryTypes.includes('element') wahr ist.
Fallstricke:
- Der Wert ist eine Momentaufnahme vom Zeitpunkt des Renderns. Scrollt der Nutzer später oder ändert sich das Layout, wird der Wert nicht aktualisiert. Wenn du fortlaufend wissen willst, ob ein Element sichtbar ist, nimm stattdessen den
IntersectionObserver. - Es werden nur Elemente mit dem Attribut
elementtimingerfasst. Die einzige Ausnahme sind Kandidaten, die Chromium intern selbst beobachtet. - Die Koordinaten beziehen sich auf den Viewport, nicht auf das Dokument. Um Dokument-Koordinaten zu erhalten, musst du die Scroll-Position (
scrollX/scrollY) selbst addieren. entry.elementkannnullsein, etwa wenn das Element inzwischen aus dem DOM entfernt wurde oder in einem Shadow DOM liegt.intersectionRectbleibt trotzdem verfügbar.- Ohne
buffered: trueentgehen dir Einträge, die entstanden sind, bevor der Observer registriert wurde.