W3docs

Coordinate in JavaScript

Scopri i due sistemi di coordinate del browser in JavaScript: viewport e documento, con getBoundingClientRect() ed elementFromPoint().

Le coordinate sono valori numerici che descrivono una posizione nella pagina. Quasi ogni funzionalità interattiva — trascinamento, disegno, tooltip, menu a comparsa, rilevamento delle collisioni — si riduce alla lettura di una coordinata e al posizionamento o confronto di qualcosa rispetto ad essa.

Il problema è che il browser espone due sistemi di coordinate diversi, e confonderli è la causa più comune dei bug del tipo "il mio elemento si sposta nel posto sbagliato". Questo capitolo spiega entrambi i sistemi, come convertire tra di essi e i principali metodi DOM (getBoundingClientRect() e elementFromPoint()) utilizzati per leggere le posizioni degli elementi.

I due sistemi di coordinate

Esistono due frame di riferimento da tenere distinti:

  • Coordinate del viewport (relative alla finestra) — misurate dall'angolo in alto a sinistra della parte visibile della pagina. Non cambiano quando si fa scorrere la pagina. Un punto in alto a sinistra di ciò che si vede è sempre (0, 0). Proprietà: clientX / clientY.
  • Coordinate del documento (relative alla pagina) — misurate dall'angolo in alto a sinistra dell'intero documento, inclusa la parte scorsa fuori dalla visualizzazione. Aumentano mentre si scorre verso il basso. Proprietà: pageX / pageY.

La relazione tra loro è semplicemente l'offset di scorrimento:

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

Quando la pagina non è scorsa, window.scrollX e window.scrollY sono entrambi 0, quindi i due sistemi forniscono numeri identici — ed è esattamente per questo che i bug di scorrimento restano nascosti finché qualcuno non scorre la pagina.

Usa le coordinate del viewport (clientX/Y) quando…Usa le coordinate del documento (pageX/Y) quando…
Posizioni un elemento con position: fixedPosizioni un elemento con position: absolute
Verifichi cosa è attualmente visibile sullo schermoMemorizzi la posizione di un click per riprodurla in seguito
Lavori con getBoundingClientRect()Disegni su un canvas scrollabile alto

Consulta Dimensioni della finestra e scorrimento in JavaScript per come vengono misurati window.scrollX/Y e la dimensione del viewport, e Scorrimento in JavaScript per spostare la posizione di scorrimento in modo programmatico.

Lettura delle coordinate da un evento mouse

Ogni evento mouse contiene entrambi i sistemi di coordinate. Per il modello completo degli eventi, consulta Fondamenti degli eventi mouse.

Coordinate del viewport: clientX / clientY

event.clientX e event.clientY forniscono la posizione del puntatore relativa al viewport, indipendentemente dallo scorrimento. L'esempio seguente si trova all'interno di una pagina alta in modo da poter scorrere e verificare che i numeri rimangano ancorati all'area visibile:

<!-- 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>

Coordinate del documento: pageX / pageY

event.pageX e event.pageY forniscono la posizione del puntatore relativa all'intero documento, quindi includono già l'offset di scorrimento. Sono standard e ampiamente supportati — non è necessario calcolarli manualmente. L'esempio seguente li mostra accanto al calcolo manuale clientX + window.scrollX in modo da poter verificare che i due coincidano:

<!-- 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>

Coordinate dello schermo: screenX / screenY

event.screenX e event.screenY misurano la posizione del puntatore rispetto all'intero schermo fisico, non solo alla finestra del browser. Sono utili per tracciare il cursore su più monitor o per posizionare un popup window.open(), ma per il lavoro nella pagina di solito si preferisce usare clientX/Y o pageX/Y.

Lettura della posizione di un elemento: getBoundingClientRect()

Per trovare dove si trova un elemento (anziché dove si trova il mouse), si chiama getBoundingClientRect(). Restituisce un DOMRect i cui valori top, right, bottom, left, width e height sono tutti in coordinate del viewport — lo stesso frame di 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

Poiché il rettangolo è relativo al viewport, cambia durante lo scorrimento. Per ottenere la posizione dell'elemento in coordinate del documento, si aggiunge l'offset di scorrimento:

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

Questa combinazione — leggere con getBoundingClientRect(), aggiungere scrollX/Y quando si hanno bisogno delle coordinate di pagina — è la conversione che si utilizzerà continuamente.

Trovare l'elemento in un punto: elementFromPoint()

La domanda inversa — "cosa c'è sotto queste coordinate?" — trova risposta in document.elementFromPoint(x, y), che accetta coordinate del viewport (corrispondenti a clientX/Y) e restituisce l'elemento più in alto in quel punto, oppure null se il punto è fuori dal viewport.

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

Un errore comune: passare pageX/pageY su una pagina scorsa restituisce l'elemento sbagliato (o null), perché il metodo si aspetta coordinate del viewport, non del documento.

Manipolazione delle posizioni degli elementi tramite coordinate

È possibile combinare questi elementi per spostare le cose. Il metodo getBoundingClientRect() ci permette di calcolare l'offset tra il puntatore e l'angolo dell'elemento in modo che l'elemento non "salti" verso il cursore all'inizio del trascinamento. Ecco un quadrato che puoi trascinare:

Esempio: elemento HTML trascinabile

<!-- 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>
Nota

Per prestazioni migliori, considera l'utilizzo di transform: translate() al posto di left / top per le animazioni, in quanto evita i ricalcoli del layout. Inoltre, per la compatibilità con i dispositivi mobili, aggiungi i listener degli eventi touchstart, touchmove e touchend insieme agli eventi del mouse.

Animazione con le coordinate

Puoi anche guidare il movimento aggiornando le coordinate di un elemento ad ogni frame con requestAnimationFrame. Moltiplicare per un delta temporale mantiene la velocità costante indipendentemente dalla frequenza di aggiornamento del display:

Esempio: oggetto animato in movimento

<!-- 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>
Informazione

Sebbene JavaScript offra potenti capacità per la creazione di animazioni dinamiche e interattive, le animazioni CSS sono spesso più adatte per animazioni semplici. Le animazioni CSS possono fornire transizioni più fluide e sono generalmente più efficienti in termini di prestazioni, poiché vengono gestite direttamente dal motore di rendering del browser, utilizzando meno CPU. Questo rende le animazioni CSS ideali per effetti come transizioni, dissolvenze e movimenti di base, specialmente quando le alte prestazioni e il basso consumo di risorse sono fondamentali.

Conclusione

Il concetto fondamentale è che il browser dispone di due frame di coordinate: viewport (clientX/Y, getBoundingClientRect(), elementFromPoint()) e documento (pageX/Y), e si converte tra di essi aggiungendo o sottraendo window.scrollX/Y. Tenendo questo presente, la maggior parte dei bug di posizionamento scompare.

Da qui, approfondisci Dimensioni della finestra e scorrimento, Scorrimento per muovere il viewport e Fondamenti degli eventi mouse per gli eventi che forniscono queste coordinate.

Pratica

Pratica
Cosa rappresentano le coordinate lato client in JavaScript?
Cosa rappresentano le coordinate lato client in JavaScript?
Was this page helpful?