W3docs

Coordonnées JavaScript

Découvrez les deux systèmes de coordonnées du navigateur en JavaScript, comment les convertir et utiliser getBoundingClientRect() pour positionner des éléments.

Les coordonnées sont des valeurs numériques qui décrivent une position sur la page. Presque chaque fonctionnalité interactive — glisser-déposer, dessin, infobulles, menus contextuels, détection de collision — repose sur la lecture d'une coordonnée et le positionnement ou la comparaison de quelque chose par rapport à elle.

Le piège est que le navigateur expose deux systèmes de coordonnées différents, et les confondre est la source la plus fréquente de bugs du type "mon élément saute au mauvais endroit". Ce chapitre explique les deux systèmes, comment les convertir l'un en l'autre, et les méthodes DOM clés (getBoundingClientRect() et elementFromPoint()) utilisées pour lire les positions des éléments.

Les deux systèmes de coordonnées

Il y a deux référentiels à garder en tête :

  • Coordonnées du viewport (relatives à la fenêtre) — mesurées depuis le coin supérieur gauche de la partie visible de la page. Elles ne changent pas lors du défilement. Un point en haut à gauche de ce que vous voyez est toujours (0, 0). Propriétés : clientX / clientY.
  • Coordonnées du document (relatives à la page) — mesurées depuis le coin supérieur gauche du document entier, y compris la partie défilée hors de la vue. Elles augmentent lorsque vous faites défiler vers le bas. Propriétés : pageX / pageY.

La relation entre les deux est simplement le décalage de défilement :

pageX = clientX + window.scrollX;
pageY = clientY + window.scrollY;

Lorsque la page n'est pas défilée, window.scrollX et window.scrollY valent tous les deux 0, donc les deux systèmes donnent des valeurs identiques — ce qui explique exactement pourquoi les bugs liés au défilement restent cachés jusqu'à ce que quelqu'un fasse défiler la page.

Utilisez le viewport (clientX/Y) quand…Utilisez le document (pageX/Y) quand…
Positionnement d'un élément position: fixedPositionnement d'un élément position: absolute
Test de collision sur ce qui est actuellement à l'écranStockage d'un emplacement de clic pour le recréer ultérieurement
Utilisation de getBoundingClientRect()Dessin sur un grand canvas défilable

Consultez Tailles de fenêtre et défilement JavaScript pour savoir comment window.scrollX/Y et la taille du viewport sont mesurés, et Défilement JavaScript pour déplacer la position de défilement par programmation.

Lecture des coordonnées à partir d'un événement souris

Chaque événement souris transporte les deux systèmes de coordonnées. Pour le modèle d'événements complet, consultez Bases des événements souris.

Coordonnées du viewport : clientX / clientY

event.clientX et event.clientY donnent la position du pointeur par rapport au viewport, indépendamment du défilement. L'exemple ci-dessous se trouve à l'intérieur d'une page haute afin que vous puissiez faire défiler et confirmer que les valeurs restent ancrées à la zone visible :

<!-- snippet: html-result -->

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Client-Side Coordinates Example</title>
    <style>
#container {
  width: 100%;
  height: 100%;
  background-color: grey;
  min-height: 40px;
}
    </style>
</head>
<body style="height: 2000px;">
    <div id="container">Click anywhere in the grey area to see Client-Side coordinates!</div>
    <script>
        const container = document.getElementById('container');
        function showCoords(event) {
            alert("Client-Side X: " + event.clientX + ", Y: " + event.clientY);
        }
        container.addEventListener('click', showCoords);
    </script>
</body>
</html>

Coordonnées du document : pageX / pageY

event.pageX et event.pageY donnent la position du pointeur par rapport au document entier, donc ils incluent déjà le décalage de défilement. Ils sont standardisés et largement pris en charge — il n'est pas nécessaire de les calculer manuellement. L'exemple ci-dessous les affiche à côté du calcul manuel clientX + window.scrollX pour que vous puissiez confirmer que les deux correspondent :

<!-- snippet: html-result -->

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Page-Side Coordinates Example</title>
    <style>
#container {
  width: 100%;
  height: 100%;
  background-color: grey;
  min-height: 40px;
}
    </style>
</head>
<body style="height: 2000px;">
    <div id="container">Click anywhere in this area to see Page-Side coordinates!</div>
    <script>
        const container = document.getElementById('container');
        function showPageCoords(event) {
            // pageX/pageY already include scroll; the manual version must match
            const manualX = event.clientX + window.scrollX;
            const manualY = event.clientY + window.scrollY;
            alert("pageX/Y: " + event.pageX + ", " + event.pageY +
                  "\nclientX+scrollX: " + manualX + ", " + manualY);
        }
        container.addEventListener('click', showPageCoords);
    </script>
</body>
</html>

Coordonnées d'écran : screenX / screenY

event.screenX et event.screenY mesurent la position du pointeur par rapport à l'écran physique entier, et pas seulement à la fenêtre du navigateur. Ils sont utiles pour suivre le curseur sur plusieurs moniteurs ou pour positionner une fenêtre contextuelle window.open(), mais pour le travail dans la page, vous voudrez presque toujours utiliser clientX/Y ou pageX/Y à la place.

Lecture de la position d'un élément : getBoundingClientRect()

Pour trouver où se trouve un élément (plutôt que la position de la souris), appelez getBoundingClientRect(). Elle renvoie un DOMRect dont top, right, bottom, left, width et height sont tous en coordonnées du viewport — le même référentiel que clientX/Y.

const rect = element.getBoundingClientRect();
// rect.left, rect.top   → top-left corner, relative to the viewport
// rect.width, rect.height → rendered size including borders/padding

Comme le rect est relatif au viewport, il change lors du défilement. Pour obtenir la position de l'élément en coordonnées du document, ajoutez le décalage de défilement :

function getDocumentCoords(el) {
  const rect = el.getBoundingClientRect();
  return {
    top: rect.top + window.scrollY,
    left: rect.left + window.scrollX,
  };
}

Cette combinaison — lecture avec getBoundingClientRect(), ajout de scrollX/Y pour les coordonnées de page — est la conversion que vous utiliserez constamment.

Trouver l'élément à un point : elementFromPoint()

La question inverse — "qu'est-ce qui se trouve sous ces coordonnées ?" — est résolue par document.elementFromPoint(x, y), qui prend des coordonnées de viewport (correspondant à clientX/Y) et renvoie l'élément le plus en avant à cet endroit, ou null si le point est en dehors du viewport.

document.addEventListener('click', (event) => {
  const el = document.elementFromPoint(event.clientX, event.clientY);
  console.log('You clicked on:', el.tagName);
});

Un piège courant : lui passer pageX/pageY sur une page défilée retourne le mauvais élément (ou null), car la méthode attend des coordonnées du viewport, pas des coordonnées du document.

Manipulation des positions d'éléments avec les coordonnées

Vous pouvez combiner ces éléments pour déplacer des choses. La méthode getBoundingClientRect() nous permet de calculer le décalage entre le pointeur et le coin de l'élément afin que l'élément ne "saute" pas vers le curseur au début du glissement. Voici un carré que vous pouvez faire glisser :

Exemple : Élément HTML déplaçable

<!-- snippet: html-result -->

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Draggable Element Example</title>
    <style>
        #draggable {
            width: 100px;
            height: 100px;
            background-color: red;
            position: absolute;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div id="draggable"></div>
    <script>
        const elem = document.getElementById('draggable');
        let shiftX, shiftY;

        function onMouseDown(event) {
            shiftX = event.clientX - elem.getBoundingClientRect().left;
            shiftY = event.clientY - elem.getBoundingClientRect().top;

            function moveAt(pageX, pageY) {
                elem.style.left = pageX - shiftX + 'px';
                elem.style.top = pageY - shiftY + 'px';
            }

            function onMouseMove(event) {
                moveAt(event.clientX + window.scrollX, event.clientY + window.scrollY);
            }

            document.addEventListener('mousemove', onMouseMove);
            document.addEventListener('mouseup', function stopDrag() {
                document.removeEventListener('mousemove', onMouseMove);
                document.removeEventListener('mouseup', stopDrag);
                elem.removeEventListener('mousedown', onMouseDown);
            });
        }

        elem.addEventListener('mousedown', onMouseDown);
        elem.addEventListener('dragstart', function() { return false; });
    </script>
</body>
</html>
Note

Pour de meilleures performances, envisagez d'utiliser transform: translate() plutôt que left / top pour les animations, car cela évite les recalculs de mise en page. De plus, pour la compatibilité mobile, ajoutez des écouteurs d'événements touchstart, touchmove et touchend aux côtés des événements souris.

Animation avec les coordonnées

Vous pouvez également piloter le mouvement en mettant à jour les coordonnées d'un élément à chaque image avec requestAnimationFrame. La multiplication par un delta de temps permet de maintenir une vitesse constante quelle que soit la fréquence de rafraîchissement de l'écran :

Exemple : Objet animé en mouvement

<!-- snippet: html-result -->

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Animation Using Coordinates</title>
</head>
<body>
    <div id="animateMe" style="width: 50px; height: 50px; background: blue; position: absolute;"></div>
    <button id="stopBtn">Stop Animation</button>
    <script>
        const target = document.getElementById('animateMe');
        const stopBtn = document.getElementById('stopBtn');
        let pos = 0;
        let isRunning = true;
        let lastTime = performance.now();

        function animate(currentTime) {
            if (!isRunning) return;
            const delta = (currentTime - lastTime) / 16; // Normalize to ~60fps
            lastTime = currentTime;
            if (pos >= 350) {
                pos = 0;
            }
            pos += delta;
            target.style.left = pos + 'px';
            requestAnimationFrame(animate);
        }

        stopBtn.addEventListener('click', () => { isRunning = false; });
        requestAnimationFrame(animate);
    </script>
</body>
</html>
Info

Bien que JavaScript offre de puissantes capacités pour créer des animations dynamiques et interactives, les animations CSS sont souvent mieux adaptées aux animations simples. Les animations CSS peuvent offrir des transitions plus fluides et sont généralement plus efficaces en termes de performances, car elles sont gérées directement par le moteur de rendu du navigateur, ce qui sollicite moins le CPU. Les animations CSS sont donc idéales pour des effets tels que les transitions, les fondus et les mouvements basiques, notamment lorsque la haute performance et la faible consommation de ressources sont essentielles.

Conclusion

L'essentiel à retenir est que le navigateur dispose de deux référentiels de coordonnées : le viewport (clientX/Y, getBoundingClientRect(), elementFromPoint()) et le document (pageX/Y), et vous les convertissez en ajoutant ou soustrayant window.scrollX/Y. Gardez cela à l'esprit et la plupart des bugs de positionnement disparaissent.

À partir de là, explorez Tailles de fenêtre et défilement, Défilement pour déplacer le viewport, et Bases des événements souris pour les événements qui fournissent ces coordonnées.

Pratique

Pratique
Que représentent les coordonnées côté client en JavaScript ?
Que représentent les coordonnées côté client en JavaScript ?
Was this page helpful?