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

Arrière-plan: pixels CSS, pixels du canevas et pixels physiques

Alors que nous travaillons souvent avec des unités abstraites de longueur comme em, % ou vh, tout se résume aux pixels. Chaque fois que nous spécifions la taille ou la position d'un élément dans CSS, le moteur de mise en page du navigateur finira par convertir cette valeur en pixels (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.

Pendant longtemps, il était tout à fait raisonnable d'estimer la densité de pixels de l'écran de n'importe qui à 96 dpi («points par pouce»), ce qui signifie que tout moniteur ferait environ 38 pixels par cm. Au fil du temps, les moniteurs ont grandi et / ou rétréci ou ont commencé à avoir plus de pixels sur la même surface. Combinez cela avec le fait qu'une grande partie du contenu sur le Web définit ses dimensions, y compris les tailles de police, dans px, et nous nous retrouvons avec du texte déformé sur ces écrans haute densité ("HiDPI"). En guise de contre-mesure, les navigateurs masquent la densité de pixels réelle du moniteur et prétendent à la place que l'utilisateur dispose d'un écran de 96 DPI. Les px l'unité en CSS représente la taille d'un pixel dans ce virtuel Affichage 96 DPI, d'où le nom "CSS Pixel". Cet appareil n'est utilisé que pour la mesure et le positionnement. Avant tout rendu réel, une conversion en pixels physiques se produit.

igraal_fr-fr

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, vous travaillez sur un moniteur avec environ 96 ppp. Si vous avez un écran Retina, votre dPR est probablement 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


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 pour définir sa taille intrinsèque, mais vous pouvez redimensionner arbitrairement le canevas en utilisant toutes les propriétés CSS que vous connaissez et aimez. Avec tout ce que nous avons appris jusqu'à présent, il se peut que ce ne soit pas idéal dans tous les scénarios. Un pixel sur le canevas peut finir par couvrir plusieurs pixels physiques ou juste une fraction d'un pixel physique. Cela peut conduire à des artefacts visuels désagréables.

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 id = " myCanvas " >
toile >
< script >
const cvs = document . querySelector ( '#myCanvas' ) ;
rectangle const = cvs . getBoundingClientRect ( ) ;
cvs . largeur = rectangle . width * devicePixelRatio ;
cvs . hauteur = rectangle . height * devicePixelRatio ;
script >

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 ) => {
entrée const = entrées . find ( ( entrée ) => entrée . target === canevas ) ;
toile . largeur = entrée . devicePixelContentBoxSize [ 0 ] . inlineSize ;
toile . hauteur = entrée . devicePixelContentBoxSize [ 0 ] . blockSize ;


} ) ;
observer . observer ( canevas , { box : [ '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:

function hasDevicePixelContentBox ( ) {
retourner une nouvelle promesse ( ( résoudre ) => {
const ro = nouveau ResizeObserver ( ( entrées ) => {
résoudre ( entries . every ( ( entry ) => 'devicePixelContentBoxSize' dans l' entrée ) ) ;
ro . déconnecter ( ) ;
} ) ;
ro . observer ( document . corps , { box : [ 'device-pixel-content-box' ] } ) ;
} ) . catch ( ( ) => faux ) ;
}

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

Erreur: Attention: Contenu protégé.