Passer au contenu principal




Combien de pixels y a-t-il Vraiment sur une toile?

Depuis Chrome 84, ResizeObserver prend en charge une nouvelle mesure de boîte appelée boîte-de-contenu-pixel-appareil, qui mesure la dimension de l'élément dans physique pixels. Cela permet de rendre des graphiques parfaits au pixel près, en particulier dans le contexte d'affichages haute densité.

Fondo: píxeles CSS, píxeles de lienzo y píxeles físicos

Alors que nous travaillons souvent avec des unités abstraites de longueur comme em, % ou 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 le navigateur eventualmente convertirá ese valor en píxeles (px). Ce sont des "pixels CSS", qui ont une longue histoire et n'ont qu'une relation lâche avec les pixels que vous avez sur votre écran.

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 Contenu dans la la toile 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 navigateurs ocultan la densidad de píxeles real del monitor y, en su lugar, fingen que el Nom d'utilisateur tiene una pantalla de 96 DPI. los px l'unité en CSS représente la taille d'un pixel dans ce virtuel Pantalla de 96 DPI, de ahí el nombre «CSS Pixel». Esta unidad solo se utiliza para medición y positionnement. Antes de que ocurra cualquier renderizado real, ocurre una conversion a píxeles físicos.

Comment passer de cet écran virtuel à l'écran réel de l'utilisateur? Entrer devicePixelRatio. Cette valeur globale vous indique combien physique pixels dont vous avez besoin pour former un seul pixel CSS. Oui devicePixelRatio (dPR) est 1, está trabajando en un monitor con aproximadamente 96 ppp. Si tiene una pantalla de retina, probablemente su dPR être 2. Sur les téléphones, il n'est pas rare de trouver des valeurs de dPR plus élevées (et plus étranges) comme 2, 3 ou 2.65. Il est essentiel de prendre en compte que cette valeur est exactement, mais ne vous permet pas de contourner le moniteur réel Valeur DPI. Un dPR de 2 signifie qu'un pixel CSS sera mappé sur exactement 2 pixels physiques.

Mon moniteur a un dPR de 1 selon Chrome ...

Il fait 3440 pixels de large et la zone d'affichage est de 79 cm de large. Cela conduit à une résolution de 110 DPI. Près de 96, mais pas tout à fait. C'est aussi la raison pour laquelle <div style="width: 1cm; height: 1cm">
Il ne fera pas exactement 1 cm sur la plupart des écrans.

Enfin, le dPR peut également être affecté par la fonction zoom de votre navigateur. Si vous effectuez un zoom avant, le navigateur augmente le DPR signalé, ce qui donne à tout un aspect plus grand. Si tu vois devicePixelRatio Dans une console DevTools pendant le zoom, vous pouvez voir les valeurs fractionnaires apparaître.

dprs-1305951
DevTools montrant une variété de devicePixelRatio en raison du zoom.

Ajoutons le élément au mélange. Vous pouvez spécifier le nombre de pixels que vous souhaitez que le canevas utilise largeur y la taille les attributs. Ensuite ce serait une toile de 40 x 30 pixels. Cependant, cela ne signifie pas qu'il sera déplié à 40 par 30 pixels. Par défaut, le canevas utilisera le largeur y la taille 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.

Pour résumer: les éléments du canevas sont dimensionnés pour définir la zone dans laquelle vous pouvez dessiner. Le nombre de pixels sur le canevas est totalement indépendant de la taille d'affichage du canevas, spécifiée en pixels CSS. Le nombre de pixels CSS n'est pas le même que le nombre de pixels physiques.

La perfection des pixels

Dans certains scénarios, il est souhaitable d'avoir un mappage exact des pixels du canevas sur les pixels physiques. Si ce mappage est réalisé, il est appelé «pixel parfait». Un rendu parfait au pixel est crucial pour un rendu lisible du texte, en particulier lors de l'utilisation représentation sous-pixel ou lors de l'affichage de graphiques avec des lignes très alignées de luminosité alternée.

Pour obtenir quelque chose d'aussi proche que possible d'un canevas parfait au pixel près sur le Web, c'est à peu près l'approche à adopter:

<style>
</style>
<canvas va="myCanvas"></canvas>
<scénario>
const cvs = document.querySelector('#myCanvas');
const rectangle = cvs.getBoundingClientRect();
cvs.largeur = rectangle.largeur * devicePixelRatio;
cvs.la taille = rectangle.la taille * devicePixelRatio;
</scénario>

Le lecteur avisé pourrait se demander ce qui se passe lorsque dPR n'est pas une valeur entière. C'est une bonne question et c'est exactement où se trouve le nœud de tout ce problème. De plus, si vous spécifiez la position ou la taille d'un élément à l'aide de pourcentages, vhou d'autres valeurs indirectes, elles peuvent être résolues en valeurs fractionnaires de pixels CSS. Un élément avec marge gauche: 33% vous pouvez vous retrouver avec un rectangle comme celui-ci:

fractionnaire-pixels-9178262
DevTools affichant des valeurs de pixels fractionnaires suite à une getBoundingClientRect () appel.

Les pixels CSS sont purement virtuels, donc avoir des fractions de pixel est bien en théorie, mais comment le navigateur calcule-t-il l'allocation aux pixels physiques? Parce que fractionnaire physique les pixels ne sont pas une chose.

Réglage des pixels

La partie du processus de conversion d'unité qui s'occupe d'aligner les éléments sur les pixels physiques est appelée «capture de pixels», et elle fait ce qu'elle dit sur la boîte: elle capture des valeurs de pixels fractionnaires sur des valeurs de pixels physiques entières. La façon dont cela se produit exactement est différente d'un navigateur à l'autre. Si nous avons un élément d'une largeur de 791,984 px sur un écran où dPR vaut 1, un navigateur peut rendre l'élément en 792 px pixels physiques, tandis qu'un autre navigateur peut le rendre dans 791px. C'est juste un pixel de moins, mais un seul pixel peut nuire aux rendus qui doivent être parfaits au pixel près. Cela peut provoquer un flou ou des artefacts encore plus visibles tels que Effet moiré.

côte à côte-5944113
L'image du haut est un raster de pixels de différentes couleurs. L'image du bas est la même que la précédente, mais la largeur et la hauteur ont été réduites d'un pixel en utilisant l'échelle bilinéaire. Le motif émergent s'appelle l'effet Moiré.
(Vous devrez peut-être ouvrir cette image dans un nouvel onglet pour l'afficher sans la mettre à l'échelle.)

devicePixelContentBox

devicePixelContentBox vous donne la zone de contenu d'un élément en unités de pixels de périphérique (c'est-à-dire en pixels physiques). Cela fait partie de ResizeObserver. Alors que ResizeObserver prend désormais en charge tous les principaux navigateurs depuis Safari 13.1, le devicePixelContentBox La propriété est uniquement disponible sur Chrome 84+ pour le moment.

Comme mentionné dans ResizeObserver: c'est comme document.onresize pour les éléments, la fonction de rappel d'un ResizeObserver il sera appelé avant la peinture et après la conception. Cela signifie que le entrées Le paramètre de rappel contiendra les tailles de tous les éléments observés juste avant qu'ils ne soient peints. Dans le contexte de notre problème de canevas décrit ci-dessus, nous pouvons profiter de cette opportunité pour ajuster le nombre de pixels sur notre canevas, en nous assurant que nous nous retrouvons avec un mappage un-à-un exact entre les pixels du canevas et les pixels physiques.

const observer = new ResizeObserver((entrées) => {
const entry = entrées.trouve((entry) => entry.cible === canvas);
canvas.largeur = entry.devicePixelContentBoxSize[0].inlineSize;
canvas.la taille = entry.devicePixelContentBoxSize[0].blockSize;


});
observer.observe(canvas, {boîte: ['device-pixel-content-box']});

Les boîte propriété sur l'objet d'options pour observer.observer () vous permet de définir les tailles que vous souhaitez Regardez. Alors pendant que chacun ResizeObserverEntry fournira toujours borderBoxSize, contentBoxSize y devicePixelContentBoxSize (tant que le navigateur le prend en charge), le rappel ne sera appelé que si l'un des observé les paramètres de trésorerie changent.

Toutes les mesures de trésorerie sont des matrices pour permettre ResizeObserver gérer la fragmentation à l’avenir. Au moment de la rédaction de cet article, le tableau a toujours une longueur de 1.

Avec cette nouvelle propriété, nous pouvons même animer la taille et la position de notre canevas (garantissant effectivement des valeurs de pixels fractionnaires) et ne voir aucun effet de moiré dans le rendu. Si vous voulez voir l'effet Moiré au point en utilisant getBoundingClientRect ()et comme le nouveau ResizeObserver propriété vous permet de l'éviter, jetez un œil à la manifestation sur Chrome 84 ou version ultérieure.

Détection des fonctionnalités

Pour vérifier si le navigateur d'un utilisateur est compatible avec devicePixelContentBox, nous pouvons observer n'importe quel élément et vérifier si la propriété est présente dans le ResizeObserverEntry:

une fonction hasDevicePixelContentBox() {
revenir new Promise((resolve) => {
const ro = new ResizeObserver((entrées) => {
resolve(entrées.every((entry) => 'devicePixelContentBoxSize' dans entry));
ro.déconnecter();
});
ro.observe(document.corps, {boîte: ['device-pixel-content-box']});
}).catch(() => faux);
}

si (!(attendre hasDevicePixelContentBox())) {
}

conclusion

Les pixels sont un sujet étonnamment complexe sur le Web et jusqu'à présent, il n'y avait aucun moyen de connaître le nombre exact de pixels physiques qu'un élément occupe sur l'écran de l'utilisateur. Le nouveau devicePixelContentBox propriété dans un ResizeObserverEntry vous donne ces informations et vous permet de rendre des rendus parfaits au pixel près avec . devicePixelContentBox il est compatible avec Chrome 84+.