ResizeObserver
Baseline
Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since Juli 2020.
Das ResizeObserver-Interface meldet Änderungen an den Dimensionen des Inhalts- oder Rahmenbereichs eines Element oder des Umrandungsrechtecks eines SVGElement.
Hinweis: Der Inhaltsbereich ist der Bereich, in dem Inhalt platziert werden kann, das bedeutet der Rahmenbereich abzüglich der Polsterung und Rahmenbreite. Der Rahmenbereich umfasst den Inhalt, die Polsterung und den Rahmen. Siehe Das Box-Modell für weitere Erläuterungen.
Konstruktor
ResizeObserver()-
Erstellt und gibt ein neues
ResizeObserver-Objekt zurück.
Instanzeigenschaften
Keine.
Instanzmethoden
ResizeObserver.disconnect()-
Beendet die Beobachtung aller beobachteten
Element-Ziele eines bestimmten Observers. ResizeObserver.observe()-
Initiiert die Beobachtung eines bestimmten
Element. ResizeObserver.unobserve()-
Beendet die Beobachtung eines bestimmten
Element.
Beispiele
Im Beispiel resize-observer-text.html (siehe Quelle) verwenden wir den Resize-Observer, um die font-size einer Überschrift und eines Absatzes zu ändern, während sich der Wert eines Schiebereglers ändert, wodurch sich die Breite des enthaltenden <div> ändert. Dies zeigt, dass Sie auf Änderungen der Größe eines Elements reagieren können, selbst wenn sie nichts mit dem Ansichtsfenster zu tun haben.
Wir stellen auch ein Kontrollkästchen bereit, um den Observer ein- und auszuschalten. Wenn er ausgeschaltet ist, ändert sich der Text nicht, wenn sich die Breite des <div> ändert.
Der JavaScript-Code sieht folgendermaßen aus:
const h1Elem = document.querySelector("h1");
const pElem = document.querySelector("p");
const divElem = document.querySelector("body > div");
const slider = document.querySelector('input[type="range"]');
const checkbox = document.querySelector('input[type="checkbox"]');
divElem.style.width = "600px";
slider.addEventListener("input", () => {
divElem.style.width = `${slider.value}px`;
});
const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
if (entry.contentBoxSize) {
const contentBoxSize = entry.contentBoxSize[0];
h1Elem.style.fontSize = `${Math.max(
1.5,
contentBoxSize.inlineSize / 200,
)}rem`;
pElem.style.fontSize = `${Math.max(
1,
contentBoxSize.inlineSize / 600,
)}rem`;
} else {
h1Elem.style.fontSize = `${Math.max(
1.5,
entry.contentRect.width / 200,
)}rem`;
pElem.style.fontSize = `${Math.max(1, entry.contentRect.width / 600)}rem`;
}
}
console.log("Size changed");
});
resizeObserver.observe(divElem);
checkbox.addEventListener("change", () => {
if (checkbox.checked) {
resizeObserver.observe(divElem);
} else {
resizeObserver.unobserve(divElem);
}
});
Beobachtungsfehler
Implementierungen, die der Spezifikation folgen, rufen Resize-Ereignisse vor dem Malen auf (d.h. bevor der Frame dem Benutzer präsentiert wird). Wenn ein Resize-Ereignis vorlag, werden Stil und Layout neu ausgewertet – was wiederum weitere Resize-Ereignisse auslösen kann. Unendliche Schleifen aufgrund zyklischer Abhängigkeiten werden dadurch adressiert, dass während jeder Iteration nur Elemente tiefer im DOM verarbeitet werden. Resize-Ereignisse, die diese Bedingung nicht erfüllen, werden auf das nächste Malen verschoben, und ein Fehlerereignis wird im Window-Objekt ausgelöst, mit der genau definierten Nachrichtenzeichenfolge:
ResizeObserver-Schleife abgeschlossen mit nicht gelieferten Benachrichtigungen.
Beachten Sie, dass dies nur das Einfrieren des Benutzeragenten verhindert, nicht aber die unendliche Schleife selbst. Zum Beispiel wird der folgende Code dazu führen, dass die Breite von divElem unendlich wächst, wobei die obige Fehlermeldung in der Konsole jedes Frame wiederholt wird:
const divElem = document.querySelector("body > div");
const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
entry.target.style.width = `${entry.contentBoxSize[0].inlineSize + 10}px`;
}
});
resizeObserver.observe(divElem);
window.addEventListener("error", (e) => {
console.error(e.message);
});
Solange das Fehlerereignis nicht unendlich oft auftritt, wird sich der Resize-Observer stabilisieren und ein stabiles, wahrscheinlich korrektes Layout erzeugen. Besucher könnten jedoch einen kurzen Moment ein fehlerhaftes Layout sehen, da eine Reihe von Änderungen, die innerhalb eines einzelnen Frames erwartet werden, stattdessen über mehrere Frames stattfinden.
Wenn Sie diese Fehler verhindern möchten, hängt die Lösung von Ihrem beabsichtigten Effekt ab. Wenn Sie tatsächlich eine unendliche Schleife beabsichtigen, müssen Sie den Resizing-Code in Ihrem ResizeObserver-Callback einfach aufschieben, bis nach dem Browser-Redraw. Sie können ihn in einen requestAnimationFrame-Callback einfügen.
const divElem = document.querySelector("body > div");
const resizeObserver = new ResizeObserver((entries) => {
requestAnimationFrame(() => {
for (const entry of entries) {
entry.target.style.width = `${entry.contentBoxSize[0].inlineSize + 10}px`;
}
});
});
resizeObserver.observe(divElem);
window.addEventListener("error", (e) => {
console.error(e.message);
});
Wenn Sie nicht die Absicht haben, eine unendliche Schleife zu haben, sollten Sie sicherstellen, dass Ihr Resizing-Code den Resize-Observer-Callback nicht auslöst. Es gibt viele Möglichkeiten, dies zu tun, zum Beispiel indem Sie eine "erwartete Größe" festlegen und nicht neu dimensionieren, wenn die Größe bereits diesen Wert hat.
const divElem = document.querySelector("body > div");
const expectedSizes = new WeakMap();
const resizeObserver = new ResizeObserver((entries) => {
requestAnimationFrame(() => {
for (const entry of entries) {
const expectedSize = expectedSizes.get(entry.target);
if (entry.contentBoxSize[0].inlineSize === expectedSize) {
continue;
}
const newSize = entry.contentBoxSize[0].inlineSize + 10;
entry.target.style.width = `${newSize}px`;
expectedSizes.set(entry.target, newSize);
}
});
});
resizeObserver.observe(divElem);
window.addEventListener("error", (e) => {
console.error(e.message);
});
Spezifikationen
| Specification |
|---|
| Resize Observer> # resize-observer-interface> |
Browser-Kompatibilität
Siehe auch
- Lernen: Das Box-Modell
PerformanceObserverIntersectionObserver(Teil der Intersection Observer API)- Bevorstehende Containerabfragen könnten eine brauchbare Alternative zur Implementierung eines responsiven Designs sein.