Pixels CSS vs Physiques : Guide Technique des Coordonnées d'Écran pour DPI et Retina
Si vous avez déjà mappé une coordonnée d'un navigateur web vers un outil d'automatisation de bureau et cliqué dans le vide, vous avez déjà rencontré la différence entre pixels CSS et pixels physiques. Ce guide explique ce que signifie réellement le Ratio de Pixels de l'Appareil (DPR), pourquoi les systèmes d'exploitation mettent les écrans à l'échelle, et exactement comment écrire du code d'automatisation qui fonctionne correctement sur tout, depuis un moniteur de bureau 1080p jusqu'à un portable 4K avec mise à l'échelle Retina.
Ouvrir l'outil gratuitPixels CSS vs Physiques : Quelle est la Différence ?
Les pixels physiques sont les points microscopiques LED (ou OLED) réels sur le panneau de votre moniteur. Un écran 4K de 3840 x 2160 a exactement 8 294 400 pixels physiques disposés en une grille. Les outils d'automatisation de bureau comme AutoHotkey, PyAutoGUI et AppleScript opèrent exclusivement dans cet espace de pixels physiques car ils interagissent avec le système d'exploitation au niveau matériel.
Quand vous dites à PyAutoGUI de cliquer à la coordonnée (1920, 1080) sur un écran 4K, il vise le pixel physique de la colonne 1920, rangée 1080. Si l'élément cible est en réalité rendu à la coordonnée physique (3840, 2160) à cause de la mise à l'échelle, le clic échouera.
Règle de base : Tout outil qui déplace le curseur physique de la souris (AutoHotkey, PyAutoGUI, SikuliX) doit utiliser des coordonnées de pixels physiques ou compenser la mise à l'échelle explicitement.
Que sont les pixels CSS ?
Les pixels CSS (aussi appelés pixels logiques ou pixels indépendants de la densité) sont une abstraction créée par les navigateurs web pour garder le texte lisible sur tous les appareils. Sans pixels CSS, une police de 16px sur un smartphone 4K serait microscopique, et un site web mobile conçu à 375px de large n'occuperait qu'une infime fraction d'un moniteur 4K de bureau.
Un pixel CSS ne correspond pas à une seule LED physique. Au lieu de cela, il représente une unité d'angle visuel — approximativement la taille d'un pixel sur un moniteur de 96 DPI tenu à bout de bras. Sur les écrans haute densité, un pixel CSS se mappe à un bloc de plusieurs pixels physiques :
- Moniteur de bureau standard (96 DPI) : 1 pixel CSS = 1 pixel physique
- MacBook Retina d'Apple (220+ DPI) : 1 pixel CSS = 4 pixels physiques (bloc 2x2)
- Téléphone flagship moderne (450+ DPI) : 1 pixel CSS = 9+ pixels physiques (bloc 3x3 ou plus)
En JavaScript, vous pouvez lire le mappage actuel avec window.devicePixelRatio. Sur un moniteur externe standard cela retourne 1. Sur un MacBook Pro cela retourne 2. Sur certains appareils Android cela peut être 2,5, 3 ou même plus élevé.
Ratio de Pixels de l'Appareil (DPR) Expliqué
Le Ratio de Pixels de l'Appareil est le pont entre les pixels CSS et les pixels physiques. Il répond à la question : "Combien de pixels physiques composent un pixel CSS ?"
// JavaScript
const dpr = window.devicePixelRatio; // ex. 1, 1.25, 1.5, 2, 3
const cssWidth = window.innerWidth; // viewport en pixels CSS
const physWidth = cssWidth * dpr; // viewport en pixels physiques
La formule est simple, mais les implications sont de grande portée :
Coordonnée Physique = Coordonnée CSS × Ratio de Pixels de l'Appareil
Coordonnée CSS = Coordonnée Physique / Ratio de Pixels de l'Appareil
Voici un exemple du monde réel. Vous testez une application web et utilisez les DevTools de Chrome pour mesurer qu'un bouton "Envoyer" est à la coordonnée CSS (400, 600). Vous écrivez un script PyAutoGUI pour cliquer là. Sur votre moniteur externe 1080p (DPR = 1), cela fonctionne parfaitement. Puis vous exécutez le même script sur votre MacBook Pro (DPR = 2). PyAutoGUI clique à la coordonnée physique (400, 600), mais le bouton est en réalité à la coordonnée physique (800, 1200). Le clic échoue par une marge massive.
Piège courant : Les DevTools de Chrome reportent des coordonnées en pixels CSS par défaut. Si vous copiez ces nombres directement dans un script d'automatisation au niveau du SO, le script ne fonctionnera que sur les écrans avec un DPR exactement égal à 1.
Valeurs de DPR fractionnaires
Le DPR n'est pas toujours un nombre entier propre. Les portables Windows utilisent couramment une mise à l'échelle de 125%, ce qui produit un DPR de 1,25. Certaines distributions Linux avec mise à l'échelle fractionnaire utilisent 1,5 ou 1,75. Cela signifie qu'un pixel CSS se mappe à un bloc non rectangulaire de pixels physiques, et les algorithmes d'anti-aliasing doivent mélanger les couleurs à travers les limites de pixels. Pour les besoins d'automatisation, arrondissez toujours les coordonnées physiques à l'entier le plus proche avant de les passer à une fonction de clic.
Comment la Mise à l'Échelle DPI Affecte les Coordonnées d'Écran sur Windows
Les portables modernes comprennent souvent des résolutions 1080p ou 4K dans des panneaux de 13 ou 14 pouces. À une échelle native 1:1, le texte et les éléments de l'interface seraient illisiblement petits. Pour résoudre cela, les systèmes d'exploitation appliquent une mise à l'échelle DPI (aussi appelée mise à l'échelle de l'affichage ou de l'interface).
Comment Windows gère la mise à l'échelle
Windows propose des options de mise à l'échelle typiquement étiquetées 100%, 125%, 150% et 200%. Quand vous sélectionnez 125%, Windows dit aux applications que l'écran est plus petit qu'il ne l'est réellement. Un moniteur de 1920 x 1080 à 125% de mise à l'échelle reporte une résolution logique de 1536 x 864 à la plupart des applications. Le SO met ensuite à l'échelle la sortie de l'application par 1,25x avant de l'envoyer au moniteur.
Il existe trois façons dont les applications Windows peuvent répondre à la mise à l'échelle :
- Système (inconscient du DPI) : L'application pense que l'écran est 1536 x 864. Windows met à l'échelle bitmap de toute la fenêtre, la rendant floue mais de taille correcte.
- Système (conscient du DPI) : L'application connaît la résolution réelle mais rend les éléments de l'interface plus grands pour qu'ils restent lisibles. C'est le mode le plus courant pour les applications de bureau modernes.
- Conscient du DPI par moniteur : L'application gère la mise à l'échelle indépendamment pour chaque moniteur dans une configuration multi-écran. C'est nécessaire pour un rendu net quand les moniteurs ont des DPI différents.
Comment macOS gère la mise à l'échelle
macOS utilise une approche différente. Sur un MacBook Pro Retina avec une résolution native de 2880 x 1800, macOS utilise par défaut un mode de mise à l'échelle "Ressemble à 1440 x 900". Le système rend le bureau à 2880 x 1800 (DPR 2x) en utilisant des ressources 2x, mais le présente à l'utilisateur comme s'il était 1440 x 900. Le résultat est un texte et une interface utilisateur d'une netteté extrême à une taille confortable.
L'outil de capture de macOS (Cmd + Shift + 4) montre des coordonnées de points logiques, pas de pixels physiques. Si votre script d'automatisation nécessite des pixels physiques, vous devez multiplier par le ratio de pixels de l'appareil (généralement 2x sur Retina, mais vérifiez avec ns_screen backingScaleFactor en Objective-C ou NSScreen.main?.backingScaleFactor en Swift).
Coordonnées d'Écran sur les Écrans Retina et Haute DPI
La plupart des langages de programmation et bibliothèques d'automatisation lisent la résolution logique par défaut. Si votre écran de 1920 x 1080 est mis à l'échelle à 125%, le PyAutoGUI de Python pourrait penser que votre écran n'est que de 1536 x 864. Essayer de cliquer à la coordonnée (1900, 1000) lancera une erreur "Hors limites" car la bibliothèque croit que l'écran se termine en (1535, 863).
La solution pour Windows (Python + PyAutoGUI)
Vous devez déclarer votre processus Python comme conscient du DPI avant d'importer PyAutoGUI ou toute autre bibliothèque qui interroge les dimensions de l'écran :
import ctypes
import pyautogui
# Déclarer la conscience du DPI AVANT d'utiliser pyautogui
ctypes.windll.user32.SetProcessDPIAware()
# Maintenant pyautogui.size() retourne des PIXELS PHYSIQUES
width, height = pyautogui.size()
print(f"Taille physique de l'écran : {width}x{height}")
# Clic utilisant des coordonnées physiques
pyautogui.click(x=960, y=540)
Important : SetProcessDPIAware() doit être appelé avant que toute bibliothèque initialise ses métriques d'écran. Si PyAutoGUI met en cache la taille logique à l'importation, l'appeler après ne servira à rien. Pour les configurations multi-moniteur avec des DPI différents, utilisez SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) à la place.
La solution pour Windows (AutoHotkey v2)
; Forcer AutoHotkey à utiliser des pixels physiques
#Requires AutoHotkey v2.0
DllCall("SetProcessDPIAware")
; Obtenir les dimensions physiques de l'écran
width := A_ScreenWidth
height := A_ScreenHeight
; Clic à la coordonnée physique
Click(960, 540)
La solution pour macOS (AppleScript + Python)
Sur macOS, le défi est généralement l'inverse : les outils natifs reportent des points logiques, mais votre script a besoin de pixels physiques. Si vous utilisez Python avec PyAutoGUI sur macOS, la bibliothèque gère généralement correctement les écrans Retina car l'API Quartz de macOS reporte les tailles physiques aux processus non mis à l'échelle. Cependant, si vous lisez des coordonnées depuis une capture d'écran ou depuis la croix de Cmd+Shift+4, multipliez par le facteur d'échelle de support :
# macOS : convertir des points logiques en pixels physiques
logical_x = 720
logical_y = 450
# Déterminer le facteur d'échelle de support (généralement 2.0 sur Retina)
# Vous pouvez détecter cela en comparant pyautogui.size() aux dimensions de NSScreen
# ou simplement supposer 2.0 pour les Macs modernes et vérifier manuellement.
dpr = 2.0
physical_x = int(logical_x * dpr)
physical_y = int(logical_y * dpr)
Comment Convertir les Pixels CSS en Pixels Physiques
| Plateforme | API / Méthode | Ce que cela fait |
|---|---|---|
| Windows (Python) | ctypes.windll.user32.SetProcessDPIAware() | Fait que le processus lise des pixels physiques au lieu de logiques |
| Windows (C#) | SetProcessDPIAware() ou paramètre dpiAware dans app.manifest | Idem ci-dessus ; le manifeste est préféré pour les apps de production |
| Windows (AHK) | DllCall("SetProcessDPIAware") | Force AHK à utiliser des dimensions d'écran physiques |
| macOS (Swift) | NSScreen.main?.backingScaleFactor | Retourne le DPR de l'écran principal (généralement 2.0) |
| macOS (Python) | PyAutoGUI (aucune configuration supplémentaire nécessaire) | PyAutoGUI utilise Quartz qui reporte des coordonnées physiques |
| Linux (X11) | xrandr --dpi 96 ou paramètres spécifiques au toolkit | La mise à l'échelle Linux est très variable selon la distribution et le DE |
| Web (JavaScript) | window.devicePixelRatio | Retourne le DPR du viewport actuel ; change avec le zoom |
Zoom du navigateur vs mise à l'échelle du SO
Ces deux concepts sont souvent confondus, mais ils affectent les coordonnées de façons complètement différentes.
Mise à l'échelle de l'affichage du SO
La mise à l'échelle du SO change la relation entre pixels CSS et pixels physiques globalement. Elle affecte chaque application du système. Quand Windows est réglé à 125%, un pixel CSS devient 1,25 pixel physique de large, et window.devicePixelRatio dans le navigateur reportera 1,25. La grille de coordonnées physiques de votre moniteur ne change pas ; seule la couche de mappage change.
Zoom du navigateur
Le zoom du navigateur (Ctrl + Plus ou Cmd + Plus) change la taille d'un pixel CSS relativement au viewport sans toucher la couche de mise à l'échelle du SO. Si vous zoomez à 150% dans Chrome, window.devicePixelRatio augmente de 1,5x, mais la grille de pixels physiques de votre moniteur reste inchangée. Un événement click() JavaScript dispatché en (100, 100) touchera toujours le même pixel physique ; seule la taille rendue des éléments change.
Critique pour l'automatisation : Le zoom du navigateur ne change pas les coordonnées globales du moniteur que voient PyAutoGUI ou AutoHotkey. Cependant, si vous avez mesuré la position d'un élément en utilisant un navigateur zoomé et avez ensuite essayé de cliquer dessus avec un outil au niveau du SO à 100% de zoom, la cible aura décalé. Réinitialisez toujours le zoom du navigateur à 100% avant d'enregistrer des coordonnées pour les flux de travail multi-outils.
Table de référence rapide
Utilisez cette table pour diagnostiquer rapidement les divergences de coordonnées basées sur votre configuration matérielle et logicielle.
| Écran | Résolution native | Mise à l'échelle typique du SO | Résolution logique | DPR |
|---|---|---|---|---|
| Moniteur standard 24" | 1920 x 1080 | 100% | 1920 x 1080 | 1,0 |
| Portable gaming 15" | 1920 x 1080 | 125% | 1536 x 864 | 1,25 |
| Ultrabook 13" | 2560 x 1440 | 150% | 1707 x 960 | 1,5 |
| MacBook Pro 14" | 3024 x 1964 | "Ressemble à 1512 x 982" | 1512 x 982 | 2,0 |
| Moniteur 4K 27" | 3840 x 2160 | 150% ou 200% | 2560 x 1440 (à 150%) | 1,5 ou 2,0 |
| iPhone 15 Pro | 1179 x 2556 | Géré par le système | 393 x 852 (CSS) | 3,0 |
Rappelez-vous : La résolution logique est ce que la plupart des applications croient être la taille de votre écran. La résolution physique est ce que votre moniteur a réellement. Le DPR est le ratio entre elles. Chaque fois que vous passez de coordonnées web à des coordonnées du SO, vous devez tenir compte de ce ratio.