Rendu de toile net sur les écrans haute résolution et Retina
Pourquoi les graphiques sur toile semblent flous sur les écrans Retina et haute DPI, et comment y remédier avec devicePixelRatio, y compris la gestion du redimensionnement et les limites de performances.
À retenir
Un canevas semble flou sur les écrans haute densité lorsque sa taille en pixels correspond à sa taille CSS, car chaque pixel du canevas est étiré sur plusieurs pixels physiques. Corrigez-le en définissant la largeur et la hauteur du canevas sur la taille CSS multipliée par window.devicePixelRatio, en gardant la taille CSS inchangée et en mettant à l'échelle le contexte de dessin selon le même rapport. Mettez-le à jour lors du redimensionnement et du zoom.
Pourquoi les toiles sont floues
MDN décrit devicePixelRatio comme le rapport entre les pixels physiques et les pixels CSS sur l'affichage actuel : 1 sur un écran classique de 96 DPI et 2 sur les écrans HiDPI ou Retina typiques. Un canevas possède son propre tampon de pixels. Si ce tampon mesure 300 x 150 pixels mais s'affiche à 300 x 150 pixels CSS sur un écran avec un rapport de 2, le navigateur l'étire sur 600 x 300 pixels physiques, ce qui semble doux.
Le correctif
L'approche recommandée par MDN consiste à utiliser devicePixelRatio pour ajouter la densité de pixels supplémentaire : définissez le tampon de canevas sur la taille CSS multipliée par le rapport, conservez la même taille CSS et redimensionnez le contexte 2D afin que votre code de dessin puisse continuer à utiliser les pixels CSS. Voir le code ci-dessous.
Gérer les redimensionnements et le zoom
Le rapport change lorsqu'une fenêtre se déplace vers un autre moniteur ou que l'utilisateur effectue un zoom sur la page. Recalculez lors du redimensionnement et écoutez les modifications apportées à la requête multimédia de résolution afin de pouvoir redessiner à la nouvelle densité. Un ResizeObserver sur l'élément canvas est un moyen fiable de synchroniser la taille avec la mise en page.
Limites de performances
Doubler le rapport quadruple les pixels à dessiner. Sur de très grandes toiles ou sur des appareils bas de gamme, plafonnez le ratio, par exemple à 2, et mesurez les temps d'image. Les environnements d'exécution d'animation qui dessinent sur le canevas, tels que le moteur de rendu de canevas de Lottie, Rive et ExodeUI, gèrent cette mise à l'échelle pour vous, mais le même compromis s'applique.
Extrait d’implémentation en production
function setupCanvas(canvas) {
const ctx = canvas.getContext('2d');
function resize() {
const ratio = Math.min(window.devicePixelRatio || 1, 2); // cap for performance
const { width, height } = canvas.getBoundingClientRect(); // CSS size
canvas.width = Math.round(width * ratio); // backing store in device pixels
canvas.height = Math.round(height * ratio);
ctx.setTransform(ratio, 0, 0, ratio, 0, 0); // draw in CSS pixels
draw(ctx, width, height);
}
new ResizeObserver(resize).observe(canvas);
resize();
}
function draw(ctx, width, height) {
ctx.clearRect(0, 0, width, height);
ctx.lineWidth = 1;
ctx.strokeRect(0.5, 0.5, width - 1, height - 1); // crisp 1px border
}Principes clés à retenir
- devicePixelRatio = pixels physiques par pixel CSS (2 sur les écrans Retina typiques)
- Définissez canvas.width/height sur le rapport taille × CSS ; conserver la taille CSS
- Mettez à l'échelle le contexte pour que le code de dessin utilise les pixels CSS
- Recalculer lors du redimensionnement, du changement de moniteur et du zoom
- Limitez le ratio sur les grandes toiles pour plus de performances
Questions fréquentes
Sources
- Window: devicePixelRatio property — Documents Web MDN