Wie viele Pixel gibt es? Ja wirklich auf einer Leinwand?
Seit Chrome 84 unterstützt ResizeObserver eine neue Box-Kennzahl namens Geräte-Pixel-Content-Box
, die die Abmessung des Elements in misst physisch Pixel. Dies ermöglicht die Wiedergabe pixelgenauer Grafiken, insbesondere im Zusammenhang mit Displays mit hoher Dichte.
Fondo: píxeles CSS, píxeles de lienzo y píxeles físicos
Während wir oft mit abstrakten Längeneinheiten arbeiten wie em
, %
oder vh
, todo se reduce a píxeles. Siempre que especifiquemos el tamaño o la posición de un elemento en CSS, el motor de diseño del Browser eventualmente convertirá ese valor en píxeles (px
). Dies sind "CSS-Pixel", die eine lange Geschichte haben und nur eine lose Beziehung zu den Pixeln haben, die Sie auf Ihrem Bildschirm haben.
Durante mucho tiempo, fue bastante razonable estimar la densidad de píxeles de la pantalla de cualquier persona con 96 ppp («puntos por pulgada»), lo que significa que cualquier monitor tendría aproximadamente 38 píxeles por cm. Con el tiempo, los monitores crecieron y / o encogieron o empezaron a tener más píxeles en la misma superficie. Combine eso con el hecho de que una gran cantidad de Inhalt auf der Netz define sus dimensiones, incluidos los tamaños de fuente, en px
, y terminamos con texto ilegible en estas pantallas de alta densidad («HiDPI»). Como contramedida, los Browser ocultan la densidad de píxeles real del monitor y, en su lugar, fingen que el Nutzername tiene una pantalla de 96 DPI. los px
Einheit in CSS repräsentiert die Größe eines Pixels in diesem virtuell Pantalla de 96 DPI, de ahí el nombre «CSS Pixel». Esta unidad solo se utiliza para medición y Positionierung. Antes de que ocurra cualquier renderizado real, ocurre una Umwandlung a píxeles físicos.
Wie gelangen wir von diesem virtuellen Bildschirm zum realen Bildschirm des Benutzers? Reinkommen devicePixelRatio
. Dieser globale Wert gibt an, wie viele physisch Pixel, die Sie benötigen, um ein einzelnes CSS-Pixel zu bilden. Ja devicePixelRatio
(dPR) ist 1
, está trabajando en un monitor con aproximadamente 96 ppp. Si tiene una pantalla de retina, probablemente su dPR Sein 2
. Auf Telefonen ist es nicht ungewöhnlich, höhere (und seltsamere) dPR-Werte wie zu finden 2
, 3
oder auch 2.65
. Es ist wichtig zu berücksichtigen, dass dieser Wert ist genau, erlaubt Ihnen jedoch nicht, den Monitor zu umgehen echt DPI-Wert. Ein dPR von 2
bedeutet, dass 1 CSS-Pixel zugeordnet wird genau 2 physische Pixel.
Mein Monitor hat einen DVR von 1
laut Chrome ...
1
laut Chrome ... Es ist 3440 Pixel breit und der Anzeigebereich ist 79 cm breit. Das führt zu einer Auflösung von 110 DPI. Nahe an 96, aber nicht ganz. Das ist auch der Grund warum <div style="width: 1cm; height: 1cm">
Auf den meisten Bildschirmen ist die Größe nicht genau 1 cm.
Schließlich kann dPR auch durch die Zoomfunktion Ihres Browsers beeinflusst werden. Wenn Sie hineinzoomen, erhöht der Browser den gemeldeten dPR, sodass alles größer aussieht. Wenn du siehst devicePixelRatio
In einer DevTools-Konsole werden beim Zoomen Bruchwerte angezeigt.

devicePixelRatio
aufgrund von Zoom.Fügen wir das hinzu Element zur Mischung. Sie können angeben, wie viele Pixel die Leinwand verwenden soll
Breite
y Höhe
Attribute. Dann Es wäre eine 40 x 30 Pixel große Leinwand. Dies bedeutet jedoch nicht, dass dies der Fall sein wird entfaltet bei 40 mal 30 Pixel. Standardmäßig verwendet die Zeichenfläche die
Breite
y Höhe
Attribut para definir su tamaño intrínseco, pero puede cambiar el tamaño del lienzo arbitrariamente utilizando todas las propiedades CSS que conoce y ama. Con todo lo que hemos aprendido hasta ahora, se le puede ocurrir que esto no será ideal en todos los escenarios. Un píxel en el lienzo puede terminar cubriendo varios píxeles físicos o solo una fracción de un píxel físico. Esto puede generar artefactos visuales desagradables.
Zusammenfassend: Elemente auf der Leinwand werden so dimensioniert, dass sie den Bereich definieren, in dem Sie zeichnen können. Die Anzahl der Pixel auf der Zeichenfläche ist völlig unabhängig von der in CSS-Pixeln angegebenen Anzeigegröße der Zeichenfläche. Die Anzahl der CSS-Pixel entspricht nicht der Anzahl der physischen Pixel.
Pixel Perfektion
In einigen Szenarien ist eine genaue Zuordnung der Canvas-Pixel zu den physischen Pixeln wünschenswert. Wenn diese Zuordnung erreicht wird, wird sie als "pixelgenau" bezeichnet. Das pixelgenaue Rendern ist entscheidend für das lesbare Rendern von Text, insbesondere bei Verwendung Subpixel-Darstellung oder wenn Grafiken mit sehr ausgerichteten Linien mit wechselnder Helligkeit angezeigt werden.
Um im Web eine möglichst pixelgenaue Leinwand zu erreichen, war dies der folgende Ansatz:
<Stil>
</Stil>
<canvas gehen="myCanvas"></canvas>
<Skript>
const cvs = Dokument.querySelector('#myCanvas');
const rectangle = cvs.getBoundingClientRect();
cvs.Breite = rectangle.Breite * devicePixelRatio;
cvs.Höhe = rectangle.Höhe * devicePixelRatio;
</Skript>
Der kluge Leser könnte sich fragen, was passiert, wenn dPR kein ganzzahliger Wert ist. Das ist eine gute Frage und genau dort, wo der Kern dieses ganzen Problems liegt. Wenn Sie die Position oder Größe eines Elements in Prozent angeben, vh
oder andere indirekte Werte können sie in gebrochene CSS-Pixelwerte aufgelöst werden. Ein Element mit Rand links: 33%
Sie können mit einem Rechteck wie diesem enden:

getBoundingClientRect ()
Anruf.CSS-Pixel sind rein virtuell, daher ist es theoretisch in Ordnung, Bruchteile eines Pixels zu haben. Wie berechnet der Browser jedoch die Zuordnung zu physischen Pixeln? Weil gebrochen physisch Pixel sind keine Sache.
Pixelanpassung
Der Teil des Einheitenumrechnungsprozesses, der sich um das Ausrichten von Elementen an physischen Pixeln kümmert, wird als "Pixel-Snapping" bezeichnet und macht das, was es verspricht: Er fängt gebrochene Pixelwerte an ganze physische Pixelwerte. Wie genau dies geschieht, ist von Browser zu Browser unterschiedlich. Wenn wir ein Element mit einer Breite von haben 791,984px
Auf einem Bildschirm, auf dem dPR 1 ist, kann ein Browser das Element in rendern 792px
physische Pixel, während ein anderer Browser sie möglicherweise rendern kann 791px
. Das ist nur ein Pixel weniger, aber ein einzelnes Pixel kann sich nachteilig auf Renderings auswirken, die pixelgenau sein müssen. Dies kann zu Unschärfe oder noch mehr sichtbaren Artefakten führen, wie z Moiré-Effekt.

(Möglicherweise müssen Sie dieses Bild in einer neuen Registerkarte öffnen, um es anzuzeigen, ohne es zu skalieren.)
devicePixelContentBox
devicePixelContentBox
gibt Ihnen das Inhaltsfeld eines Elements in Einheiten von Gerätepixeln (dh physischen Pixeln). Es ist ein Teil von ResizeObserver
. Während ResizeObserver unterstützt jetzt alle gängigen Browser seit Safari 13.1 hat die devicePixelContentBox
Die Eigenschaft ist derzeit nur auf Chrome 84+ verfügbar.
Wie in erwähnt ResizeObserver
: es ist wie document.onresize
für Elemente die Rückruffunktion von a ResizeObserver
Es wird vor dem Malen und nach dem Entwerfen aufgerufen. Das heißt das Einträge
Der Rückrufparameter enthält die Größen aller beobachteten Elemente unmittelbar vor dem Zeichnen. Im Zusammenhang mit unserem oben beschriebenen Canvas-Problem können wir diese Gelegenheit nutzen, um die Anzahl der Pixel auf unserer Canvas anzupassen und sicherzustellen, dass wir eine exakte Eins-zu-Eins-Zuordnung zwischen den Canvas-Pixeln und den physischen Pixeln erhalten.
const observer = new ResizeObserver((Einträge) => {
const entry = Einträge.finden((entry) => entry.Ziel === canvas);
canvas.Breite = entry.devicePixelContentBoxSize[0].inlineSize;
canvas.Höhe = entry.devicePixelContentBoxSize[0].blockSize;
});
observer.observe(canvas, {Box: ['device-pixel-content-box']});
das Box
Eigenschaft auf dem Optionsobjekt für watch.observe ()
Hier können Sie festlegen, welche Größen Sie möchten sehen. Also während jeder ResizeObserverEntry
wird immer zur Verfügung stellen borderBoxSize
, contentBoxSize
y devicePixelContentBoxSize
(solange der Browser dies unterstützt), wird der Rückruf nur aufgerufen, wenn einer der beobachteten Bargeldkennzahlen ändern sich.
Alle Cash-Metriken sind Matrizen, die zulässig sind ResizeObserver
Fragmentierung in der Zukunft zu behandeln. Zum Zeitpunkt des Schreibens dieses Artikels hat das Array immer eine Länge von 1.
Mit dieser neuen Eigenschaft können wir sogar die Größe und Position unserer Leinwand animieren (wodurch effektiv gebrochene Pixelwerte garantiert werden) und keine Moiré-Effekte im Rendering sehen. Wenn Sie den Moiré-Effekt im Fokus sehen möchten, verwenden Sie getBoundingClientRect ()
und wie das neue ResizeObserver
Eigenschaft ermöglicht es Ihnen, es zu vermeiden, werfen Sie einen Blick auf die Manifestation auf Chrome 84 oder höher.
Funktionserkennung
Um zu überprüfen, ob der Browser eines Benutzers mit kompatibel ist devicePixelContentBox
können wir jedes Element beobachten und prüfen, ob die Eigenschaft in der vorhanden ist ResizeObserverEntry
:
Funktion hasDevicePixelContentBox() {
Rückkehr new Promise((resolve) => {
const ro = new ResizeObserver((Einträge) => {
resolve(Einträge.every((entry) => 'devicePixelContentBoxSize' im entry));
ro.trennen();
});
ro.observe(Dokument.Körper, {Box: ['device-pixel-content-box']});
}).catch(() => falsch);
}wenn (!(erwarten hasDevicePixelContentBox())) {
}
Fazit
Pixel sind ein überraschend komplexes Thema im Web, und bis jetzt gab es keine Möglichkeit, die genaue Anzahl der physischen Pixel zu ermitteln, die ein Element auf dem Bildschirm des Benutzers belegt. Das neue devicePixelContentBox
Eigentum in einem ResizeObserverEntry
gibt Ihnen diese Informationen und ermöglicht es Ihnen, pixelgenaue Renderings mit zu rendern .
devicePixelContentBox
Es ist kompatibel mit Chrome 84+.