Signatur
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
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' });
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' });
// Wichtig · Fallstricke
- Browser-Unterstützung: Chromium-Browser ab Version 84, Firefox ab 93 und Safari ab 15.4. Ältere Browser liefern
undefinedund werfen beiobserve(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 beicontentBoxSizeein einzelnes Objekt; beidevicePixelContentBoxSizeist es jedoch stets ein Array. - Schreibmodus: Bei vertikalen Schreibmodi (
writing-mode: vertical-rl) sindinlineSizeundblockSizegegenüber Breite und Höhe vertauscht. - Endlosschleifen vermeiden: Wenn Sie
canvas.widthbzw.canvas.heightsetzen, ä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.