Encontrar a posição do elemento em relação ao documento


113

Qual é a maneira mais fácil de determinar a posição de um elemento em relação ao documento / corpo / janela do navegador?

Agora estou usando .offsetLeft/offsetTop , mas este método só fornece a posição relativa ao elemento pai, então você precisa determinar quantos pais para o elemento corpo, para saber a posição relativa ao corpo / janela do navegador / posição do documento.

Este método também é complicado.

Respostas:


58

Você pode percorrer offsetParentaté o nível superior do DOM.

function getOffsetLeft( elem )
{
    var offsetLeft = 0;
    do {
      if ( !isNaN( elem.offsetLeft ) )
      {
          offsetLeft += elem.offsetLeft;
      }
    } while( elem = elem.offsetParent );
    return offsetLeft;
}

28
Não, não tem, quando qualquer pai (especialmente elemento html !!!) tem margens, preenchimentos ou bordas.
Flash Thunder de

em relação ao material de margem ... pode ajudar definir o tamanho da caixa para caixa de borda ... ou algo nesse sentido ... nada que não possa ser corrigido ...

Primeiro, você precisa decidir se deve levar em consideração a borda e a margem de acordo com o tamanho da caixa. Em segundo lugar, a margem colapsada deve ser considerada. E, por último, haverá uma situação mais complicada no futuro, o que tornará essa resposta ainda pior.
xianshenglu

6
Por que essa é a resposta aceita? Isso está desatualizado e tem um desempenho insatisfatório. Faça um favor a si mesmo e use getBoundingClientRect () conforme sugerido nas outras respostas.
Fabian von Ellerts

177

Você pode obter o topo e a esquerda sem atravessar o DOM desta forma:

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) };
}

6
Essa resposta não leva em consideração as compensações dos pais. É apenas relativo à janela de visualização
Nickey

3
@Nickey isso não é verdade - a posição da janela de visualização, mais as verificações de deslocamento de rolagem, produzem as coordenadas relativas a todo o documento.
natchiketa

1
Pode ter erros em dispositivos móveis stackoverflow.com/a/32623832/962634 Precisa de pesquisa
manjericão

1
Por que você subtrai clientTop / clientLeft?
Teemoh

1
@Teemoh clientTop / clientLeft corresponde aos valores de borda no <html>elemento.
Raphael Rafatpanah

98

Você pode usar element.getBoundingClientRect()para recuperar a posição do elemento em relação à janela de visualização.

Em seguida, use document.documentElement.scrollToppara calcular o deslocamento da janela de visualização.

A soma dos dois dará a posição do elemento em relação ao documento:

element.getBoundingClientRect().top + document.documentElement.scrollTop

10
Em relação à janela de visualização não é o mesmo que em relação ao documento. Se a página for rolada um pouco para baixo, a parte superior em relação à janela de visualização será um número menor que a parte superior em relação ao documento.
MrVimes

14
ele começa em relação à janela de visualização e adiciona scrollY para obtê-lo em relação ao documento.
Joaquin Cuenca Abela

2
document.documentElement.scrollTopnão funciona no Safari, use em window.scrollYvez disso
Fabian von Ellerts de

7

Eu sugiro usar

element.getBoundingClientRect()

conforme proposto aqui, em vez do cálculo de deslocamento manual por meio de offsetLeft , offsetTop e offsetParent . conforme proposto aqui Em algumas circunstâncias * a passagem manual produz resultados inválidos. Veja este Plunker: http://plnkr.co/pC8Kgj

* Quando o elemento está dentro de um pai rolável com posicionamento estático (= padrão).


Você também pode fazer o cálculo do deslocamento funcionar incorporando scrollLeft e scrollTop.
Ben J de

Mas eu encontrei offsetLefte offsetTopnão levo em consideração as transformações CSS3, o que getBoundingClientRect()leva. Portanto, esse é um caso em que os resultados podem ser inválidos. Se precisar, você pode obter o deslocamento de um elemento em relação ao pai (como offsetLeft) usando (element.getBoundingClientRect().left - parent.getBoundingClientRect().left).
Ben J de

deve ficar mais alto; esses valores são muito mais úteis e todos em uma chamada também!
mix3d

7

document-offset( Script de terceiros ) é interessante e parece aproveitar as abordagens das outras respostas aqui.

Exemplo:

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

5

Descobri que o método a seguir é o mais confiável ao lidar com casos extremos que deslocam offsetTop / offsetLeft.

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

4

Para aqueles que desejam obter as coordenadas xey de várias posições de um elemento, em relação ao 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')


2

Se você não se importa em usar jQuery, pode usar a offset()função. Consulte a documentação se quiser ler mais sobre esta função.


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.