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.

Hintergrund: CSS-Pixel, Canvas-Pixel und physische Pixel

Während wir oft mit abstrakten Längeneinheiten arbeiten wie em, % oder vhEs kommt alles auf Pixel an. Immer wenn wir die Größe oder Position eines Elements in CSS angeben, konvertiert die Layout-Engine des Browsers diesen Wert schließlich in Pixel (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.

Lange Zeit war es durchaus sinnvoll, die Pixeldichte eines Bildschirms auf 96 dpi ("Punkte pro Zoll") zu schätzen, was bedeutet, dass jeder Monitor ungefähr 38 Pixel pro cm groß sein würde. Im Laufe der Zeit wuchsen und / oder schrumpften die Monitore oder hatten mehr Pixel auf derselben Oberfläche. Kombinieren Sie dies mit der Tatsache, dass viele Inhalte im Web ihre Abmessungen, einschließlich der Schriftgrößen, in definieren pxund wir erhalten verstümmelten Text auf diesen Displays mit hoher Dichte ("HiDPI"). Als Gegenmaßnahme verbergen Browser die tatsächliche Pixeldichte des Monitors und tun stattdessen so, als hätte der Benutzer einen 96-DPI-Bildschirm. das px Einheit in CSS repräsentiert die Größe eines Pixels in diesem virtuell 96 DPI-Anzeige, daher der Name "CSS Pixel". Dieses Gerät dient nur zur Messung und Positionierung. Bevor ein tatsächliches Rendern erfolgt, erfolgt eine Konvertierung in physische Pixel.

igraal_de-de

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 1Sie arbeiten an einem Monitor mit ca. 96 dpi. Wenn Sie ein Retina-Display haben, ist Ihr dPR wahrscheinlich 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


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, um die intrinsische Größe zu definieren. Sie können jedoch die Größe der Zeichenfläche mithilfe aller CSS-Eigenschaften, die Sie kennen und lieben, beliebig ändern. Bei allem, was wir bisher gelernt haben, kann Ihnen der Gedanke kommen, dass dies nicht in allen Szenarien ideal ist. Ein Pixel auf der Leinwand kann mehrere physische Pixel oder nur einen Bruchteil eines physischen Pixels bedecken. Dies kann zu unangenehmen visuellen Artefakten führen.

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:

< style >
Stil >
< canvas id = " myCanvas " >
Leinwand >
< skript >
const cvs = document . querySelector ( '#myCanvas' ) ;
const Rechteck = cvs . getBoundingClientRect ( ) ;
cvs . Breite = Rechteck . width * devicePixelRatio ;
cvs . Höhe = Rechteck . height * 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 = neuer ResizeObserver ( ( Einträge ) => {
const entry = Einträge . find ( ( entry ) => entry . target === canvas ) ;
Leinwand . width = entry . devicePixelContentBoxSize [ 0 ] . inlineSize ;
Leinwand . Höhe = Eintrag . devicePixelContentBoxSize [ 0 ] . blockSize ;


} ) ;
beobachten . beobachten ( 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 ( ) {
return new Promise ((Entschlossenheit) => {
const ro = neuer ResizeObserver ( ( Einträge ) => {
auflösen ( Einträge . every ( ( Eintrag ) => 'devicePixelContentBoxSize' im Eintrag ) ) ;
ro . trennen ( ) ;
} ) ;
ro . beobachten ( document . body , { box : [ 'Gerätepixel-Inhaltsbox' ] } ) ;
} ) . catch ( ( ) => false ) ;
}}

if ( ! ( warte auf 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+.

Error: Beachtung: Geschützter Inhalt.