ResizeObserver – auf die Größe eines Elements reagieren, nicht auf die des Fensters
window.onresize feuert nur, wenn sich das Fenster ändert – nicht, wenn eine Seitenleiste aufklappt oder Text nachlädt. ResizeObserver meldet dir die Größe des Elements selbst, und zwar ohne Endlosschleife.
Ein Canvas, das immer den ganzen verfügbaren Platz ausfüllen soll. Der naheliegende Weg:
window.addEventListener('resize', anpassen);Das funktioniert — bis jemand die Seitenleiste aufklappt, ein Bild nachlädt und den Container verschiebt oder eine Schriftart ankommt und alles einen Tick höher wird. Das Fenster hat sich dabei nie geändert, das Element sehr wohl. resize schweigt.
ResizeObserver beobachtet das Element
const box = document.querySelector('#brett');
const beobachter = new ResizeObserver((eintraege) => {
for (const e of eintraege) {
const { width, height } = e.contentRect;
zeichneNeu(width, height);
}
});
beobachter.observe(box);Das war es im Kern. Der Callback läuft bei jeder Größenänderung des beobachteten Elements — egal, wodurch sie entstanden ist.
Zwei Dinge, die man wissen muss
Ganz wichtig: aufräumen. Ein Observer hält eine Referenz auf das Element. Verschwindet dein Bauteil, muss auch er weg:
beobachter.disconnect(); // alle Beobachtungen beenden
// oder gezielt:
beobachter.unobserve(box);In einer Single-Page-Anwendung, die Ansichten austauscht, sind vergessene Observer eine der häufigsten Ursachen dafür, dass eine Seite nach einer Stunde Benutzung träge wird.
Nicht im Callback dieselbe Größe ändern. Wenn du im Handler das beobachtete Element breiter machst, feuert der Observer erneut — der Browser bricht das nach ein paar Runden mit „ResizeObserver loop completed with undelivered notifications" ab. Zeichne, rechne, setze *andere* Elemente — aber verändere nicht die Maße dessen, was du gerade misst.
Für Canvas mit scharfer Darstellung
Hier lohnt devicePixelContentBoxSize, weil es die echte Pixelzahl liefert statt der CSS-Größe:
const beobachter = new ResizeObserver(([e]) => {
const dpr = window.devicePixelRatio || 1;
const w = e.contentRect.width, h = e.contentRect.height;
canvas.width = Math.round(w * dpr); // interne Auflösung
canvas.height = Math.round(h * dpr);
canvas.style.width = w + 'px'; // dargestellte Größe
canvas.style.height = h + 'px';
ctx.setTransform(dpr, 0, 0, dpr, 0, 0); // in CSS-Pixeln zeichnen
zeichne();
});Ohne den devicePixelRatio-Teil sieht ein Canvas auf jedem modernen Handy unscharf aus — das ist der häufigste Grund für „warum ist mein Spiel so matschig".
Wann resize, wann Observer?
- Das Fenster interessiert dich wirklich (etwa: ab welcher Breite wechsle ich das Layout)? Dann reicht
matchMedia— noch sparsamer alsresize. - Ein bestimmtes Element interessiert dich? Dann
ResizeObserver. - Es geht nur ums Aussehen, nicht um Rechnen? Dann Container Queries in CSS, ganz ohne JavaScript.
In meinen Canvas-Spielen läuft die Größenanpassung genau über diesen Weg — das Spielfeld muss auf dem Handy im Hoch- und Querformat, im Browser und im aufgeklappten Vollbild jeweils sofort stimmen, und window.resize erwischt davon nur einen Teil.
Du hast ein Layout, das erst nach einem manuellen Neuladen richtig sitzt? Das ist oft genau diese Lücke. Melde dich.
Quellen
Du brauchst mehr als ein Snippet?
Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.
Projekt anfragen →Verwandte Snippets
requestAnimationFrame – die Animationsschleife, die zum Bildschirm passt
setInterval(schritt, 16) läuft auf einem 144-Hz-Monitor anders als auf einem alten Handy – und im Hintergrundtab einfach weiter. requestAnimationFrame löst beides, wenn man die verstrichene Zeit mitrechnet statt Bilder zu zählen.
In die Zwischenablage kopieren mit der Clipboard API
Ein Kopieren-Button ist eine Kleinigkeit, die Nutzer sofort bemerken – Rechnungsnummer, Gutscheincode, Link. document.execCommand ist dafür veraltet; navigator.clipboard ist der heutige Weg, braucht aber HTTPS und eine echte Nutzergeste.
Aufzählungen richtig verketten mit Intl.ListFormat
"a, b und c" von Hand zusammenzubauen geht fast immer schief – bei einem Element, bei zwei Elementen, beim letzten Komma. Intl.ListFormat macht es richtig, in jeder Sprache, ganz ohne Bibliothek.