Zum Hauptinhalt springen




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 ...

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.

dprs-1305951
DevTools zeigt eine Vielzahl von 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, vhoder 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:

Bruchpixel-9178262
DevTools, die gebrochene Pixelwerte als Ergebnis von a anzeigen 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.

Seite an Seite-5944113
Das obere Bild ist ein Raster von Pixeln verschiedener Farben. Das untere Bild ist das gleiche wie das vorherige, jedoch wurden Breite und Höhe mithilfe der bilinearen Skala um ein Pixel reduziert. Das entstehende Muster wird als Moiré-Effekt bezeichnet.
(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 devicePixelContentBoxkö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+.