Obtenha a posição de uma tag div / span

103

Alguém pode me mostrar como obter a top& leftposição de um elemento divou spanquando um não está especificado?

ie:

<span id='11a' style='top:55px;' onmouseover="GetPos(this);">stuff</span>
<span id='12a' onmouseover="GetPos(this);">stuff</span>

Acima, se eu fizer:

document.getElementById('11a').style.top

O valor de 55pxé retornado. No entanto, se eu tentar fazer isso para span'12a', nada será retornado.

Eu tenho um monte de div/ spans em uma página para a qual não posso especificar as propriedades top/ left, mas preciso exibir um divdiretamente sob esse elemento.

schmoopy
fonte

Respostas:

100

Esta função informará a posição x, y do elemento em relação à página. Basicamente, você deve percorrer todos os pais do elemento e adicionar seus deslocamentos.

function getPos(el) {
    // yay readability
    for (var lx=0, ly=0;
         el != null;
         lx += el.offsetLeft, ly += el.offsetTop, el = el.offsetParent);
    return {x: lx,y: ly};
}

No entanto, se você quiser apenas a posição x, y do elemento em relação ao seu contêiner, tudo o que você precisa é:

var x = el.offsetLeft, y = el.offsetTop;

Para colocar um elemento diretamente abaixo deste, você também precisará saber sua altura. Isso é armazenado na propriedade offsetHeight / offsetWidth.

var yPositionOfNewElement = el.offsetTop + el.offsetHeight + someMargin;
nickf
fonte
5
Infelizmente, esse método falha no Chrome quando o elemento está dentro de uma tabela com borda. Ele também falhará no modo padrão do IE6 devido às margens do BODY.
GetFree
1
Apenas um aviso para os usuários deste código. Isso é relativo à página e não à janela. Ele retorna o mesmo valor se o usuário rolar usando as barras de rolagem. Seja cuidadoso.
Isaac Bolinger
obrigado @IsaacBolinger acabei de notar. Alguém pode me dizer como faço para alterar os valores quando a janela é redimensionada ou o usuário rola?
David Fariña
@DavidFariña, usei o módulo de geometria "dom-geometry" do dojo para isso. Não sei como fazer nativamente.
Isaac Bolinger
Downvoted - Pode ser óbvio para usuários mais experientes, mas você não especificou o que exatamente precisa ser passado para el (ou seja, forneça um exemplo de uso).
Matt
184

Você pode chamar o método getBoundingClientRect()em uma referência ao elemento. Em seguida, você pode examinar os top, left, righte / ou bottompropriedades ...

var offsets = document.getElementById('11a').getBoundingClientRect();
var top = offsets.top;
var left = offsets.left;

Se estiver usando jQuery, você pode usar o código mais sucinto ...

var offsets = $('#11a').offset();
var top = offsets.top;
var left = offsets.left;
alex
fonte
11
getBoundingClientRect()Deve ser usado +1 para esta resposta - e esta deve ser a resposta aceita! Mas você não precisa de um "navegador moderno" para que isso funcione, veja a lista de compatibilidade que mostrei aqui: stackoverflow.com/questions/1480133/… . Funciona bem no IE 4.0+ (!), Chrome 1.0+, FF 3.0+, Safari 4.0+ e Opera.
Sk8erPeter
25
Observe que getBoundingClientRect()retorna valores relativos à janela de visualização, não ao documento. Para isso, você quer algo parecido top = el.getBoundingClientRect().top + window.pageYOffset - el.ownerDocument.documentElement.clientTop.
Zack Bloom
1
Observe também que getBoundingClientRectleva transformem consideração.
ExpExc
Isso não é preciso se o primeiro filho não posicionado de forma absoluta tiver margem superior ou margem esquerda. No momento, não há uma solução precisa nesta página, então se alguém souber, poste uma resposta.
Curtis de
16

Enquanto a resposta de @nickf funcionar. Se você não liga para navegadores mais antigos, pode usar esta versão Javascript puro. Funciona no IE9 + e outros

var rect = el.getBoundingClientRect();

var position = {
  top: rect.top + window.pageYOffset,
  left: rect.left + window.pageXOffset
};
Benjamin Intal
fonte
12

Como Alex observou, você pode usar jQuery offset () para obter a posição relativa ao fluxo do documento. Use position () para suas coordenadas x, y relativas ao pai.

EDIT: Alternado document.readypara window.loadporque loadespera por todos os elementos para que você obtenha seus tamanhos em vez de simplesmente preparar o DOM. Na minha experiência, loadresulta em menos elementos posicionados em Javascript incorretamente.

$(window).load(function(){ 
  // Log the position with jQuery
  var position = $('#myDivInQuestion').position();
  console.log('X: ' + position.left + ", Y: " + position.top );
});
Dylan Valade
fonte
9

Para qualquer um que precise apenas da posição superior ou esquerda, pequenas modificações no código legível de @Nickf resolvem o problema.

function getTopPos(el) {
    for (var topPos = 0;
        el != null;
        topPos += el.offsetTop, el = el.offsetParent);
    return topPos;
}

e

function getLeftPos(el) {
    for (var leftPos = 0;
        el != null;
        leftPos += el.offsetLeft, el = el.offsetParent);
    return leftPos;
}
Jens Frandsen
fonte
2

Sei que este é um tópico antigo, mas a resposta de @alex precisa ser marcada como a resposta correta

element.getBoundingClientRect() é uma correspondência exata para jQuery $(element).offset()

E é compatível com IE4 + ... https://developer.mozilla.org/en-US/docs/Web/API/Element.getBoundingClientRect

lukeed
fonte
Você precisará incluir o deslocamento de rolagem da página
Benjamin Intal