Start · Sprachen · JavaScript · Referenz · ResizeObserverEntry.devicePixelContentBoxSize

ResizeObserverEntry.devicePixelContentBoxSize

Eigenschaft

Liefert ein schreibgeschütztes Array von <code>ResizeObserverSize</code>-Objekten mit der Content-Box-Größe des beobachteten Elements in echten Geräte-Pixeln.

seit JavaScript Chrome 84+, Edge 84+, Firefox 93+, Safari 15.4+ (B Kategorie: webapi

Signatur

ResizeObserverEntry.devicePixelContentBoxSize

Beschreibung

Die schreibgeschützte Eigenschaft devicePixelContentBoxSize eines ResizeObserverEntry gibt die Größe der Content-Box des beobachteten Elements in Geräte-Pixeln an, also in physischen Bildschirmpixeln und nicht in CSS-Pixeln. Der Wert berücksichtigt window.devicePixelRatio, Browser-Zoom und das Einrasten auf das Pixelraster (Pixel-Snapping). Mit einer eigenen Multiplikation von CSS-Größe und devicePixelRatio lässt sich das nicht zuverlässig nachbilden.

Gedacht ist die Eigenschaft vor allem für <canvas>-Rendering (2D, WebGL, WebGPU). Wenn der Zeichenpuffer eines Canvas genau so viele Pixel hat, wie das Gerät tatsächlich darstellt, entsteht ein gestochen scharfes Bild ohne Unschärfe oder Moiré-Muster, auch bei gebrochenen Pixelverhältnissen wie 1,25 oder 1,5.

Rückgabewert ist ein Array von ResizeObserverSize-Objekten mit den Eigenschaften inlineSize und blockSize. Die Werte sind ganze Zahlen und hängen vom Schreibmodus ab: Bei horizontalem Text entspricht inlineSize der Breite und blockSize der Höhe. Das Array ist für künftige mehrteilige Fragmente gedacht, etwa bei mehrspaltigem Layout. Derzeit enthält es immer genau einen Eintrag, deshalb greift man mit [0] darauf zu.

Damit der Rückruf auch bei Änderungen in Geräte-Pixeln ausgelöst wird, zum Beispiel beim Zoomen, sollte man das Element mit observer.observe(el, { box: 'device-pixel-content-box' }) beobachten.

Rückgabewert

Typ
ReadonlyArray<ResizeObserverSize>
Beschreibung
Schreibgeschütztes Array mit (derzeit) genau einem ResizeObserverSize-Objekt. Dessen Eigenschaften inlineSize und blockSize enthalten die Content-Box-Maße in ganzen Geräte-Pixeln.

Beispiele

Canvas pixelgenau auf die Geräteauflösung anpassen

const canvas = document.querySelector('#chart');
const ctx = canvas.getContext('2d');

const draw = () => {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.lineWidth = 1;
  ctx.strokeRect(0.5, 0.5, canvas.width - 1, canvas.height - 1);
};

const observer = new ResizeObserver((entries) => {
  for (const entry of entries) {
    const { inlineSize, blockSize } = entry.devicePixelContentBoxSize[0];
    canvas.width = inlineSize;   // Zeichenpuffer in Geräte-Pixeln
    canvas.height = blockSize;
    console.log(`Puffer: ${inlineSize}×${blockSize}`);
    draw();
  }
});

// Wichtig: Box-Option setzen, damit auch Zoom-Änderungen gemeldet werden
observer.observe(canvas, { box: 'device-pixel-content-box' });
Puffer: 600×300 (z. B. bei 300×150 CSS-Pixeln und devicePixelRatio 2)

Fallback für Browser ohne Unterstützung

const getDeviceSize = (entry) => {
  if (entry.devicePixelContentBoxSize) {
    const { inlineSize, blockSize } = entry.devicePixelContentBoxSize[0];
    return { width: inlineSize, height: blockSize };
  }
  // Näherung: CSS-Pixel × devicePixelRatio
  const dpr = window.devicePixelRatio || 1;
  const box = entry.contentBoxSize?.[0];
  const width = box ? box.inlineSize : entry.contentRect.width;
  const height = box ? box.blockSize : entry.contentRect.height;
  return { width: Math.round(width * dpr), height: Math.round(height * dpr) };
};

const canvas = document.querySelector('canvas');
const ro = new ResizeObserver(([entry]) => {
  const { width, height } = getDeviceSize(entry);
  canvas.width = width;
  canvas.height = height;
});

try {
  ro.observe(canvas, { box: 'device-pixel-content-box' });
} catch {
  ro.observe(canvas, { box: 'content-box' }); // ältere Browser
}

WebGL-Viewport mit Geräte-Pixeln synchronisieren

const canvas = document.querySelector('#gl');
const gl = canvas.getContext('webgl2');

new ResizeObserver(([entry]) => {
  const [size] = entry.devicePixelContentBoxSize;
  canvas.width = size.inlineSize;
  canvas.height = size.blockSize;
  gl.viewport(0, 0, canvas.width, canvas.height);
  gl.clearColor(0.1, 0.1, 0.1, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);
  console.log('Viewport:', canvas.width, canvas.height);
}).observe(canvas, { box: 'device-pixel-content-box' });
Viewport: 1920 1080

// Wichtig · Fallstricke

  • Browser-Unterstützung: Chromium-Browser ab Version 84, Firefox ab 93 und Safari ab 15.4. Ältere Browser liefern undefined und werfen bei observe(el, { box: 'device-pixel-content-box' }) gegebenenfalls einen Fehler. Prüfen Sie die Unterstützung deshalb vorher und sehen Sie einen Fallback vor.
  • Kein einfaches CSS × DPR: Der Wert berücksichtigt das Pixel-Snapping des Browsers. Math.round(cssWidth * devicePixelRatio) kann um ein Pixel abweichen und dadurch Unschärfe verursachen.
  • Array statt Objekt: Greifen Sie immer mit [0] zu. Einige ältere Implementierungen lieferten bei contentBoxSize ein einzelnes Objekt; bei devicePixelContentBoxSize ist es jedoch stets ein Array.
  • Schreibmodus: Bei vertikalen Schreibmodi (writing-mode: vertical-rl) sind inlineSize und blockSize gegenüber Breite und Höhe vertauscht.
  • Endlosschleifen vermeiden: Wenn Sie canvas.width bzw. canvas.height setzen, ändert sich nur der Zeichenpuffer, nicht die CSS-Größe. Verändern Sie im Rückruf nicht die CSS-Maße des beobachteten Elements, sonst meldet der Browser „ResizeObserver loop completed with undelivered notifications“.
  • Nur für Elemente mit Layout-Box sinnvoll. Bei SVG-Elementen ohne CSS-Box sind die Werte meist nicht aussagekräftig.