Signatur
Beschreibung
devicePixelRatio ist eine schreibgeschützte Eigenschaft des globalen Gültigkeitsbereichs eines Paint Worklets (PaintWorkletGlobalScope). Sie entspricht window.devicePixelRatio im Hauptthread und gibt das Verhältnis von physischen Geräte-Pixeln zu logischen CSS-Pixeln an – auf einem klassischen Monitor meist 1, auf Retina- oder HiDPI-Displays 2, 3 oder auch Zwischenwerte wie 1.5 (Browser-Zoom und Betriebssystem-Skalierung eingeschlossen).
Da ein Worklet keinen Zugriff auf window hat, ist diese Eigenschaft der einzige Weg, innerhalb der paint()-Methode einer mit registerPaint() registrierten Klasse an die Pixeldichte zu gelangen. Sie ist direkt als globale Variable ansprechbar (devicePixelRatio bzw. globalThis.devicePixelRatio).
Wichtig: Der an paint() übergebene PaintRenderingContext2D ist bereits automatisch auf die Pixeldichte skaliert – man zeichnet in CSS-Pixeln und erhält trotzdem scharfe Ergebnisse. devicePixelRatio braucht man daher vor allem für Spezialfälle:
- Haarlinien exakt 1 physischer Pixel breit (
lineWidth = 1 / devicePixelRatio), - Ausrichten an Geräte-Pixeln (Pixel-Snapping), um verwaschene Kanten zu vermeiden,
- Detailgrad anpassen, z. B. feinere Muster oder mehr Partikel auf hochauflösenden Displays.
Rückgabewert
1, 1.25, 2, 3). Die Eigenschaft ist schreibgeschützt.Beispiele
Haarlinien-Raster mit exakt 1 Geräte-Pixel Breite
// hairline-grid.js – wird als Paint Worklet geladen
registerPaint('hairline-grid', class {
static get inputProperties() {
return ['--grid-size', '--grid-color'];
}
paint(ctx, size, props) {
const step = parseFloat(props.get('--grid-size')) || 20;
const color = props.get('--grid-color').toString().trim() || '#ccc';
// 1 physischer Pixel, unabhängig von der Pixeldichte
const hairline = 1 / devicePixelRatio;
ctx.strokeStyle = color;
ctx.lineWidth = hairline;
ctx.beginPath();
for (let x = 0; x <= size.width; x += step) {
// auf Geräte-Pixel ausrichten, damit die Linie nicht verschwimmt
const px = Math.round(x * devicePixelRatio) / devicePixelRatio + hairline / 2;
ctx.moveTo(px, 0);
ctx.lineTo(px, size.height);
}
for (let y = 0; y <= size.height; y += step) {
const py = Math.round(y * devicePixelRatio) / devicePixelRatio + hairline / 2;
ctx.moveTo(0, py);
ctx.lineTo(size.width, py);
}
ctx.stroke();
}
});
Worklet im Hauptthread laden und per CSS verwenden
// main.js
if ('paintWorklet' in CSS) {
CSS.paintWorklet.addModule('hairline-grid.js');
console.log('Paint Worklet geladen, DPR im Hauptthread:', window.devicePixelRatio);
} else {
// Fallback für Firefox/Safari
document.documentElement.classList.add('no-houdini');
}
/* style.css
.canvas-area {
--grid-size: 16;
--grid-color: #3a7bd5;
background-image: paint(hairline-grid);
}
.no-houdini .canvas-area {
background-image: linear-gradient(#3a7bd5 1px, transparent 1px);
background-size: 16px 16px;
}
*/
Detailgrad an die Pixeldichte anpassen
// dots.js – mehr, feinere Punkte auf HiDPI-Displays
registerPaint('dots', class {
paint(ctx, size) {
const dpr = devicePixelRatio; // bei jedem Aufruf frisch lesen
const spacing = dpr >= 2 ? 6 : 10;
const radius = dpr >= 2 ? 1.25 : 2;
ctx.fillStyle = 'rgba(0, 0, 0, 0.35)';
for (let y = spacing / 2; y < size.height; y += spacing) {
for (let x = spacing / 2; x < size.width; x += spacing) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fill();
}
}
}
});
// Wichtig · Fallstricke
- Browser-Unterstützung: Die CSS Painting API (und damit
PaintWorkletGlobalScope) gibt es nur in Chromium-basierten Browsern. Firefox und Safari unterstützen sie nicht – immer mit'paintWorklet' in CSSprüfen und einen CSS-Fallback anbieten. - Kontext ist bereits skaliert: Anders als beim normalen
<canvas>muss man den Kontext nicht manuell mitctx.scale(devicePixelRatio, devicePixelRatio)skalieren. Wer das trotzdem tut, zeichnet alles doppelt so groß. - Nicht auf Modulebene zwischenspeichern: Der Wert kann sich durch Zoom oder Wechsel auf einen anderen Monitor ändern. Außerdem kann der Browser mehrere Worklet-Scopes erzeugen und verwerfen.
devicePixelRatiodaher innerhalb vonpaint()lesen, nicht einmalig beim Laden des Moduls. - Schreibgeschützt: Zuweisungen haben keine Wirkung (im Strict Mode – Worklet-Module sind immer strikt – wird ein
TypeErrorausgelöst). - Nur im sicheren Kontext (HTTPS oder
localhost) verfügbar, daCSS.paintWorkleteinen sicheren Kontext voraussetzt.