MWCodebymw.de ↗
JavaScript

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 als resize.
  • 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

#JavaScript#ResizeObserver#Layout#Canvas#Browser-API

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 →