Encontrar la posición del elemento en relación con el documento

113

¿Cuál es la forma más sencilla de determinar la posición de un elemento en relación con el documento / cuerpo / ventana del navegador?

En este momento estoy usando .offsetLeft/offsetTop, pero este método solo le da la posición relativa al elemento principal, por lo que necesita determinar cuántos padres para el elemento del cuerpo, para saber la posición en relación con el cuerpo / ventana del navegador / posición del documento.

Este método también es demasiado engorroso.

Einstein
fuente

Respuestas:

60

Puede atravesar el offsetParentnivel superior del DOM.

function getOffsetLeft( elem )
{
    var offsetLeft = 0;
    do {
      if ( !isNaN( elem.offsetLeft ) )
      {
          offsetLeft += elem.offsetLeft;
      }
    } while( elem = elem.offsetParent );
    return offsetLeft;
}
KeatsKelleher
fuente
28
No, no es así, cuando cualquier padre (¡¡especialmente el elemento html !!!) tiene márgenes, rellenos o bordes.
Flash Thunder
con respecto a las cosas del margen ... podría ayudar establecer el tamaño de la caja en border-box ... o algo por el estilo ... nada que no se pueda arreglar ...
Primero, debe decidir si tomar en cuenta el borde y el margen de acuerdo con el tamaño de la caja. En segundo lugar, se debe considerar el margen colapsado. Y por último, habrá una situación más complicada en el futuro que empeoraría esta respuesta.
xianshenglu
5
¿Por qué es esta la respuesta aceptada? Esto está desactualizado y tiene un rendimiento deficiente. Hágase un favor y use getBoundingClientRect () como se sugiere en las otras respuestas.
Fabian von Ellerts
175

Puede llegar arriba y a la izquierda sin atravesar DOM de esta manera:

function getCoords(elem) { // crossbrowser version
    var box = elem.getBoundingClientRect();

    var body = document.body;
    var docEl = document.documentElement;

    var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
    var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;

    var clientTop = docEl.clientTop || body.clientTop || 0;
    var clientLeft = docEl.clientLeft || body.clientLeft || 0;

    var top  = box.top +  scrollTop - clientTop;
    var left = box.left + scrollLeft - clientLeft;

    return { top: Math.round(top), left: Math.round(left) };
}
albahaca
fuente
6
Esta respuesta no tiene en cuenta las compensaciones de los padres. Es solo relativo a la ventana
gráfica
3
@Nickey eso no es cierto: la posición de la ventana gráfica, más las comprobaciones de desplazamiento de desplazamiento, arrojan las coordenadas relativas a todo el documento.
Natchiketa
1
Puede tener errores en dispositivos móviles stackoverflow.com/a/32623832/962634 Necesito investigación
basil
1
¿Por qué resta clientTop / clientLeft?
Teemoh
1
@Teemoh clientTop / clientLeft corresponde a los valores de borde del <html>elemento.
Raphael Rafatpanah
98

Puedes usar element.getBoundingClientRect() para recuperar la posición del elemento en relación con la ventana gráfica.

Entonces usa document.documentElement.scrollTop para calcular el desplazamiento de la ventana gráfica.

La suma de los dos dará la posición del elemento en relación con el documento:

element.getBoundingClientRect().top + document.documentElement.scrollTop
dy_
fuente
10
Relativo a la ventana gráfica no es lo mismo que relativo al documento. Si la página se desplaza un poco hacia abajo, la parte superior relativa a la ventana gráfica será un número menor que la parte superior relativa al documento.
MrVimes
14
comienza en relación con la ventana gráfica y agrega scrollY para obtenerla relativa al documento.
Joaquin Cuenca Abela
2
document.documentElement.scrollTopno funciona en Safari, utilice window.scrollYen su lugar
Fabian von Ellerts
7

Sugiero usar

element.getBoundingClientRect()

como se propone aquí en lugar del cálculo de compensación manual mediante offsetLeft , offsetTop y offsetParent . como se propone aquí En algunas circunstancias * el recorrido manual produce resultados no válidos. Vea este Plunker: http://plnkr.co/pC8Kgj

* Cuando el elemento está dentro de un padre desplazable con posicionamiento estático (= predeterminado).

HANiS
fuente
Puede hacer que el cálculo de compensación funcione también incorporando scrollLeft y scrollTop en él.
Ben J
Pero encontré offsetLefty offsetTopno tomo en cuenta las transformaciones CSS3, que getBoundingClientRect()sí. Así que ese es un caso, los resultados pueden no ser válidos. Si lo necesita, puede obtener el desplazamiento de un elemento relativo al padre (como offsetLeft) usando (element.getBoundingClientRect().left - parent.getBoundingClientRect().left).
Ben J
definitivamente debería subir más alto; Estos valores son mucho más útiles, ¡y todo en una sola llamada también!
mix3d
7

document-offset( Script de terceros ) es interesante y parece aprovechar los enfoques de las otras respuestas aquí.

Ejemplo:

var offset = require('document-offset')
var target = document.getElementById('target')
console.log(offset(target))
// => {top: 69, left: 108} 
Mathieu M-Gosselin
fuente
5

He encontrado que el siguiente método es el más confiable cuando se trata de casos extremos que se disparan offsetTop / offsetLeft.

function getPosition(element) {
    var clientRect = element.getBoundingClientRect();
    return {left: clientRect.left + document.body.scrollLeft,
            top: clientRect.top + document.body.scrollTop};
}
Robin Stewart
fuente
4

Para aquellos que quieran obtener las coordenadas xey de varias posiciones de un elemento, en relación con el documento.

const getCoords = (element, position) => {
  const { top, left, width, height } = element.getBoundingClientRect();
  let point;
  switch (position) {
    case "top left":
      point = {
        x: left + window.pageXOffset,
        y: top + window.pageYOffset
      };
      break;
    case "top center":
      point = {
        x: left + width / 2 + window.pageXOffset,
        y: top + window.pageYOffset
      };
      break;
    case "top right":
      point = {
        x: left + width + window.pageXOffset,
        y: top + window.pageYOffset
      };
      break;
    case "center left":
      point = {
        x: left + window.pageXOffset,
        y: top + height / 2 + window.pageYOffset
      };
      break;
    case "center":
      point = {
        x: left + width / 2 + window.pageXOffset,
        y: top + height / 2 + window.pageYOffset
      };
      break;
    case "center right":
      point = {
        x: left + width + window.pageXOffset,
        y: top + height / 2 + window.pageYOffset
      };
      break;
    case "bottom left":
      point = {
        x: left + window.pageXOffset,
        y: top + height + window.pageYOffset
      };
      break;
    case "bottom center":
      point = {
        x: left + width / 2 + window.pageXOffset,
        y: top + height + window.pageYOffset
      };
      break;
    case "bottom right":
      point = {
        x: left + width + window.pageXOffset,
        y: top + height + window.pageYOffset
      };
      break;
  }
  return point;
};

Uso

  • getCoords(document.querySelector('selector'), 'center')

  • getCoords(document.querySelector('selector'), 'bottom right')

  • getCoords(document.querySelector('selector'), 'top center')

Raphael Rafatpanah
fuente
2

Si no le importa usar jQuery, entonces puede usar offset()function. Consulte la documentación si desea obtener más información sobre esta función.

Adán
fuente