Recuperar la posición (X, Y) de un elemento HTML en relación con la ventana del navegador

Quiero saber cómo obtener la posición X e Y de elementos HTML como img y div en JavaScript en relación con la ventana del navegador.

preguntado el 14 de enero de 09 a las 07:01

había estado usando estas 7 líneas de código que funcionan en todos los navegadores con discrepancias en ie5,6,7 (no recordaba haber tenido ningún problema ... puede ser el tipo de documento) ... quirksmode.org/js/findpos.html y lo había estado usando mucho durante tantos años. Puede ser que una sola persona pueda señalar los defectos, si los hay. -

@AnthonyWJones, supongo que necesitabas el placer pedante, pero es obvio, como siempre ocurre cuando no se especifica, que el OP se refiere al caso más general, o se refiere a las coordenadas de la ventana del navegador. -

@Mote, No, no es tan obvio. Dejemos a un lado la inferencia, la subjetividad y los falsos axiomas. Puede ser relativo a la ventana gráfica o la parte superior de la página (también conocido como document.documentElement). -

Por defecto, la opción más general no es una inferencia, es la progresión lógica, por lo que sería relativo a la ventana, o "parte superior de la página" podría ser el término como lo pones. En la teoría de juegos, se codifica como un concepto llamado punto de Schelling. Asegúrese de especificar cuándo no se refiere al caso más general. -

El punto es que lo obvio para algunos no lo es para otros. Incluso si en teoría sabemos cuál es el caso, debido al conocimiento empírico, la claridad no lastima a nadie aquí, especialmente a aquellos que recién comienzan a programar. -

27 Respuestas

El enfoque correcto es utilizar element.getBoundingClientRect():

var rect = element.getBoundingClientRect();
console.log(rect.top, rect.right, rect.bottom, rect.left);

Internet Explorer ha admitido esto desde que es probable que le interese y finalmente se estandarizó en Vistas CSSOM. Todos los demás navegadores lo adoptaron hace mucho tiempo.

Algunos navegadores también devuelven propiedades de alto y ancho, aunque esto no es estándar. Si le preocupa la compatibilidad de navegadores más antiguos, consulte las revisiones de esta respuesta para una implementación degradante optimizada.

Los valores devueltos por element.getBoundingClientRect() son relativas a la ventana gráfica. Si lo necesita en relación con otro elemento, simplemente reste un rectángulo del otro:

var bodyRect = document.body.getBoundingClientRect(),
    elemRect = element.getBoundingClientRect(),
    offset   = elemRect.top - bodyRect.top;

alert('Element is ' + offset + ' vertical pixels from <body>');

Respondido el 10 de enero de 18 a las 13:01

A artículo muy interesante sobre coordenadas JS. Este artículo no se menciona en ninguna parte de SO, debería .. - e2-e4

No funciona ... tiene 8 píxeles vertical y horizontalmente, debido al margen de 8 px en el cuerpo. La solución de Meouw funciona perfectamente. Si quieres tengo una pequeña prueba para demostrar el problema. - CpnCrunch

En realidad, creo que depende de lo que realmente quieras obtener las coordenadas. La pregunta es un poco ambigua. Su respuesta es correcta si solo desea las coordenadas relativas a la ventana gráfica o relativas al elemento del cuerpo, pero eso no lo ayuda en el caso en que desea la posición absoluta del elemento (que imagino que es lo que la mayoría de la gente quiere) . La respuesta de meouw tampoco le da eso, a menos que elimine los bits '-scrollLeft' y '-scrollTop'. - CpnCrunch

@CpnCrunch: Veo a qué te refieres ahora; No me di cuenta de que te estabas refiriendo a la última parte de mi respuesta. Cuando el cuerpo tiene un margen, su cuadro delimitador se compensará con ese número de píxeles en cada lado respectivo. En ese caso, también tendría que restar el estilo de margen calculado de las coordenadas del cuerpo. Vale la pena señalar que los restablecimientos de CSS eliminan el margen de <body>, aunque. - Andy E.

element.getBoundingClientRect().top no devuelve el desplazamiento superior correcto en caso de un position: fixed elemento en iOS (iPhone 8) si contiene un elemento de entrada enfocado y el teclado virtual se ha deslizado hacia arriba. Por ejemplo, si el desplazamiento real desde la parte superior de la ventana es 200px, lo informaría como 420px, donde 220px es la altura del teclado virtual. Si configura el elemento position: absolute y colóquelo en la misma posición que si estuviera fijo, entonces obtendrá los 200px correctos. No conozco una solución para esto. - Janis Elmeris

Las bibliotecas hacen todo lo posible para obtener compensaciones precisas para un elemento.
aquí hay una función simple que hace el trabajo en todas las circunstancias que he probado.

function getOffset( el ) {
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
        _x += el.offsetLeft - el.scrollLeft;
        _y += el.offsetTop - el.scrollTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}
var x = getOffset( document.getElementById('yourElId') ).left; 

Respondido el 27 de Septiembre de 15 a las 02:09

cambie: el = el.parentNode por: el = el.offsetParent; y parece funcionar para iframes anidados ahora ... ¿Estoy pensando que eso es lo que pretendías? - Adam

Esta solución está incompleta. Intente poner un borde grueso en un div y anímelo varias veces. En cualquier versión de Firefox (2-5) estará desfasado por el ancho del borde (incluso en el modo de cumplimiento de estándares). - ck_

¿No hay una forma más limpia de hacer eso, como una función el.totalOffsetLeft y totalOffsetTop? jQuery ciertamente tiene esta opción, pero es una pena que no haya un método oficial para esto, ¿tenemos que esperar DOM4? Estoy construyendo una aplicación de lienzo HTML5, así que creo que la mejor solución sería insertar un elemento de lienzo en un iframe para poder obtener coordenadas reales con clientX y clientY cuando hagamos clic en el elemento. - bautismo

Entonces, @Adam y meouw, ¿están diciendo que el primer bloque de código está mal? Entonces, ¿por qué no eliminar eso por completo? (Esta pregunta ha visto a muchos espectadores a lo largo de los años; ¿sería bueno eliminar cosas si están mal?) - Arjan

@baptx: Sé que esta es una respuesta tardía, pero no vi tu comentario antes. Vea mi respuesta a continuación para obtener una alternativa más compatible con los estándares; en realidad, ni siquiera necesita el código de respaldo, ya que los navegadores lo han admitido durante mucho tiempo. - Andy E.

Esta función devuelve la posición de un elemento en relación con todo el documento (página):

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

Usando esto podemos obtener la posición X:

getOffset(element).left

... o la posición Y:

getOffset(element).top

Respondido el 03 de diciembre de 20 a las 08:12

Solo esta solución funciona para mí cuando el elemento se coloca en div cuyo centrado usando css top:50%, left:50%; transform:translate(-50%, -50%); ... excelente. De acuerdo con la pregunta de @ScottBiggs. Lógico es buscar la sencillez. - Nelek

tal vez no sea un ganador porque es lo mismo que la solución de Andy E, pero no funciona en navegadores antiguos <IE9 - niltoide

getBoundingClientRect provoca un pico de repintado masivo en mis gráficos de rendimiento - frumbert

Deberías definir rect usar var, leto const. De lo contrario, se define como window.rect. - iota

left: rect.left + window.scrollX + (rect.width / 2), top: rect.top + window.scrollY + (rect.height / 2) devolverá la posición media de un elemento - abhishake

Si quieres que se haga solo en javascript, aquí están algunas una línea usar getBoundingClientRect()

window.scrollY + document.querySelector('#elementId').getBoundingClientRect().top // Y

window.scrollX + document.querySelector('#elementId').getBoundingClientRect().left // X

La primera línea volverá offsetTop diga Y en relación con el documento. La segunda línea volverá offsetLeft diga X relativo al documento.

getBoundingClientRect() es una función de JavaScript que devuelve la posición del elemento en relación con la ventana gráfica de la ventana.

Respondido 29 Abr '20, 10:04

Esta debería ser la solución. No hay código bs largo aquí, ¡es comprensible y muy preciso! - E Alexis MT

¿Qué pasa si el elemento está dentro de un elemento desplazable? La única forma de hacerlo es sumar offsetTop de todos los elementos principales, como sugieren otras respuestas: Dmitri Pisarev

Como dice Dmitri, esto es incorrecto y muy defectuoso. No debería tener tantos votos a favor como lo hace. SIEMPRE también estará en un elemento desplazable porque el documento en sí se puede desplazar. En otras palabras, a menos que todo el documento quepa en la ventana gráfica, siempre será incorrecto si el usuario se ha desplazado por la ventana principal. - Lev

Esa también sería mi solución favorita, pero ten cuidado: provoca un repintado cada vez que lo haces. (daría como resultado una animación lenta si se hace con demasiada frecuencia) - Meo

Los elementos HTML en la mayoría de los navegadores tendrán: -

offsetLeft
offsetTop

Estos especifican la posición del elemento en relación con su padre más cercano que tiene diseño. A menudo se puede acceder a este padre mediante la propiedad offsetParent.

IE y FF3 tienen

clientLeft
clientTop

Estas propiedades son menos comunes, especifican la posición de un elemento con su área de cliente principal (el área acolchada es parte del área de cliente, pero el borde y el margen no lo son).

Respondido el 14 de enero de 09 a las 09:01

¿Cómo responde eso a la pregunta que es obtener la posición de un elemento en relación con la ventana del navegador y no solo el padre del elemento? - Prime

Si la página incluye, al menos, cualquier "DIV", la función proporcionada por meouw arroja el valor "Y" más allá de los límites de la página actual. Para encontrar la posición exacta, necesita manejar tanto offsetParent's como parentNode's.

Pruebe el código que se proporciona a continuación (está marcado para FF2):


var getAbsPosition = function(el){
    var el2 = el;
    var curtop = 0;
    var curleft = 0;
    if (document.getElementById || document.all) {
        do  {
            curleft += el.offsetLeft-el.scrollLeft;
            curtop += el.offsetTop-el.scrollTop;
            el = el.offsetParent;
            el2 = el2.parentNode;
            while (el2 != el) {
                curleft -= el2.scrollLeft;
                curtop -= el2.scrollTop;
                el2 = el2.parentNode;
            }
        } while (el.offsetParent);

    } else if (document.layers) {
        curtop += el.y;
        curleft += el.x;
    }
    return [curtop, curleft];
};

Respondido 07 ago 18, 22:08

al igual que con las otras soluciones, incluso con FF 24.4, el código anterior no funciona cuando existen anchos de borde como parte del diseño de posicionamiento. - robar

Eres un salvavidas. ¡Estoy trabajando en algunos errores de GWT bastante profundos en este momento y lanzar esto en un método JSNI resuelve todos mis problemas! - Will Byrne

Puede agregar dos propiedades a Element.prototype para obtener la parte superior / izquierda de cualquier elemento.

Object.defineProperty( Element.prototype, 'documentOffsetTop', {
    get: function () { 
        return this.offsetTop + ( this.offsetParent ? this.offsetParent.documentOffsetTop : 0 );
    }
} );

Object.defineProperty( Element.prototype, 'documentOffsetLeft', {
    get: function () { 
        return this.offsetLeft + ( this.offsetParent ? this.offsetParent.documentOffsetLeft : 0 );
    }
} );

Esto se llama así:

var x = document.getElementById( 'myDiv' ).documentOffsetLeft;

Aquí hay una demostración que compara los resultados con los de jQuery. offset().top y .left: http://jsfiddle.net/ThinkingStiff/3G7EZ/

Respondido 23 Feb 17, 23:02

modificador Element.prototype generalmente se considera una mala idea. Conduce a un código realmente difícil de mantener. Además, este código no tiene en cuenta el desplazamiento. - Jared Forsyth

Para recuperar la posición relativa a la página de manera eficiente y sin usar una función recursiva: (también incluye IE)

var element = document.getElementById('elementId'); //replace elementId with your element's Id.
var rect = element.getBoundingClientRect();
var elementLeft,elementTop; //x and y
var scrollTop = document.documentElement.scrollTop?
                document.documentElement.scrollTop:document.body.scrollTop;
var scrollLeft = document.documentElement.scrollLeft?                   
                 document.documentElement.scrollLeft:document.body.scrollLeft;
elementTop = rect.top+scrollTop;
elementLeft = rect.left+scrollLeft;

Respondido 10 ago 13, 17:08

Incluir todos los importantes scrollTop / scrollLeft hace que esta respuesta sea un poco más correcta. - scunliffe

¿Qué tal algo como esto, al pasar el ID del elemento y devolverá la izquierda o la parte superior, también podemos combinarlos:

1) encontrar a la izquierda

function findLeft(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return rec.left + window.scrollX;
} //call it like findLeft('#header');

2) encontrar la parte superior

function findTop(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return rec.top + window.scrollY;
} //call it like findTop('#header');

or 3) encontrar la izquierda y la parte superior juntas

function findTopLeft(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return {top: rec.top + window.scrollY, left: rec.left + window.scrollX};
} //call it like findTopLeft('#header');

Respondido el 29 de diciembre de 17 a las 10:12

Es posible que le sirva mejor si utiliza un marco de JavaScript, que tiene funciones para devolver dicha información (¡y mucho más!) De forma independiente del navegador. A continuación se muestran algunos:

Con estos marcos, podría hacer algo como: $('id-of-img').top para obtener la coordenada de píxel y de la imagen.

Respondido el 09 de diciembre de 10 a las 07:12

@Costa Todos usan ese tipo de funciones, aunque este es un campo en evolución, ya que los diferentes navegadores se ajustan de manera diferente a la especificación. Gran parte del código trata de "arreglar" las cosas que van mal. Realmente deberías mirar el código fuente. - Shalom Craiger

@scraimer: jQuery y YUI son NO marcos!!! Estos son bibliotecas! No es lo mismo. Citando jquery.com: "jQuery es un JavaScript rápido, pequeño y rico en funciones bibliotecas." Citando yuilibrary.com (también puede ver la palabra "mágica" en la URL ...): "YUI es un código JavaScript y CSS gratuito y de código abierto bibliotecas para crear aplicaciones web ricamente interactivas ". - Sk8erPeter

Entonces, ¿debería usar bibliotecas enormes solo para esta simple tarea? No es necesario. Odio que cada vez que quiero hacer algo con js, obtengo estas soluciones jQuery. ¡jQuery no es JS! - Intermediario de Opptatt

@OpptattJobber Estoy de acuerdo ... JQuery no es javascript. Se basa en Javascript, pero es un lenguaje de programación completamente diferente. - Nick Manning

@NickManning No es un lenguaje nuevo, es una capa de abstracción para el DOM que elimina tener que escribir soluciones alternativas de compatibilidad y rendimiento directamente en su código. Si no usa jQuery, debería usar algún tipo de capa de abstracción de todos modos. - ginebra

jQuery .compensar() obtendrá las coordenadas actuales del primer elemento, o establecerá las coordenadas de cada elemento, en el conjunto de elementos coincidentes, en relación con el documento.

Respondido 24 Feb 17, 00:02

Por alguna razón, no da los mismos resultados en IE en comparación con otros navegadores. Creo que en IE está dando una posición relativa a la ventana, por lo que si se desplaza, obtendrá resultados diferentes en IE en comparación con otros: Abdul Rahim Haddad

offset () se confunde con el zoom, al menos en Android Chrome, por lo que es inútil. stackoverflow.com/a/11396681/1691517 muestra una forma tolerante al zoom. - Timo Kähkönen

/**
 *
 * @param {HTMLElement} el
 * @return {{top: number, left: number}}
 */
function getDocumentOffsetPosition(el) {
    var position = {
        top: el.offsetTop,
        left: el.offsetLeft
    };
    if (el.offsetParent) {
        var parentPosition = getDocumentOffsetPosition(el.offsetParent);
        position.top += parentPosition.top;
        position.left += parentPosition.left;
    }
    return position;
}

Agradezcan Pensando rígido es la respuesta, esta es solo otra versión.

Respondido 12 Oct 20, 03:10

Tomé la respuesta de @ meouw, agregué en el clientLeft que permite el borde, y luego creé tres versiones:

getAbsoluteOffsetFromBody - similar a @ meouw's, esto obtiene la posición absoluta relativa al cuerpo o elemento html del documento (dependiendo del modo peculiar)

getAbsoluteOffsetFromGivenElement: devuelve la posición absoluta relativa al elemento dado (relativoEl). Tenga en cuenta que el elemento dado debe contener el elemento el, o este se comportará igual que getAbsoluteOffsetFromBody. Esto es útil si tiene dos elementos contenidos dentro de otro elemento (conocido) (opcionalmente varios nodos en el árbol de nodos) y desea que estén en la misma posición.

getAbsoluteOffsetFromRelative: devuelve la posición absoluta relativa al primer elemento principal con posición: relativa. Esto es similar a getAbsoluteOffsetFromGivenElement, por la misma razón, pero solo llegará hasta el primer elemento coincidente.

getAbsoluteOffsetFromBody = function( el )
{   // finds the offset of el from the body or html element
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
    {
        _x += el.offsetLeft - el.scrollLeft + el.clientLeft;
        _y += el.offsetTop - el.scrollTop + el.clientTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}

getAbsoluteOffsetFromGivenElement = function( el, relativeEl )
{   // finds the offset of el from relativeEl
    var _x = 0;
    var _y = 0;
    while( el && el != relativeEl && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
    {
        _x += el.offsetLeft - el.scrollLeft + el.clientLeft;
        _y += el.offsetTop - el.scrollTop + el.clientTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}

getAbsoluteOffsetFromRelative = function( el )
{   // finds the offset of el from the first parent with position: relative
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
    {
        _x += el.offsetLeft - el.scrollLeft + el.clientLeft;
        _y += el.offsetTop - el.scrollTop + el.clientTop;
        el = el.offsetParent;
        if (el != null)
        {
            if (getComputedStyle !== 'undefined')
                valString = getComputedStyle(el, null).getPropertyValue('position');
            else
                valString = el.currentStyle['position'];
            if (valString === "relative")
                el = null;
        }
    }
    return { top: _y, left: _x };
}

Si aún tiene problemas, especialmente relacionados con el desplazamiento, puede intentar mirar http://www.greywyvern.com/?post=331 - Noté al menos una pieza de código cuestionable en getStyle que debería estar bien asumiendo que los navegadores se comportan, pero no he probado el resto en absoluto.

Respondido el 01 de diciembre de 15 a las 11:12

Interesante ... pero en Edge getAbsoluteOffsetFromBody (element) .top devuelve un valor diferente a medida que me desplazo, en Chrome se mantiene constante a medida que me desplazo. Parece que Edge se está ajustando con la posición de desplazamiento. Cuando el elemento se desplaza fuera de la vista, obtengo un valor negativo. - Normando

getAbsoluteOffsetFromRelative me alegró el día, tuve que reproducir la información sobre herramientas de bootstrap sin Javascript de bootstrap, me ayudó mucho. - Nolyurn

En caso de que Meouw cambie su nombre de usuario, enlace para responder: stackoverflow.com/a/442474/3654837. (No quiero tropezar con este viejo hilo, así que sí, puse un comentario) - Mukyuu

si usa jQuery, el complemento de dimensiones es excelente y le permite especificar exactamente lo que desea.

p.ej

Posición relativa, posición absoluta, posición absoluta sin relleno, con relleno ...

Continúa, digamos que hay muchas cosas que puedes hacer con él.

Además, la ventaja de usar jQuery es su tamaño de archivo liviano y fácil de usar, no volverá a JavaScript sin él después.

Respondido 14 Jul 11, 22:07

Si está utilizando jQuery, esta podría ser una solución simple:

<script>
  var el = $("#element");
  var position = el.position();
  console.log( "left: " + position.left + ", top: " + position.top );
</script>

Respondido 16 Abr '13, 05:04

Diferencia entre pequeño y pequeño

function getPosition( el ) {
    var x = 0;
    var y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
    x += el.offsetLeft - el.scrollLeft;
    y += el.offsetTop - el.scrollTop;
    el = el.offsetParent;
    }
    return { top: y, left: x };
}

Mira un ejemplo de coordenadas: http://javascript.info/tutorial/coordinates

Respondido 25 ago 16, 16:08

Desafortunadamente, esto no funciona para todos los elementos que se pueden encontrar dentro de un documento HTML moderno. Incorporado <svg> elementos, por ejemplo, no tienen offsetLeft, offsetTop y offsetParent propiedades. - jonathan eunice

Es solo DIV or IMGno, SVG. ¿Ver "Mira un ejemplo de coordenadas"? puedes encontrar el objeto svg es una llamada de posición getOffsetRect, intente depender del trabajo del objeto. - reyjinete

El enfoque más limpio que he encontrado es una versión simplificada de la técnica utilizada por jQuery's offset. Similar a algunas de las otras respuestas, comienza con getBoundingClientRect; luego usa el window y el documentElement para ajustar la posición de desplazamiento, así como cosas como el margen en el body (a menudo el predeterminado).

var rect = el.getBoundingClientRect();
var docEl = document.documentElement;

var rectTop = rect.top + window.pageYOffset - docEl.clientTop;
var rectLeft = rect.left + window.pageXOffset - docEl.clientLeft;

var els = document.getElementsByTagName("div");
var docEl = document.documentElement;

for (var i = 0; i < els.length; i++) {

  var rect = els[i].getBoundingClientRect();

  var rectTop = rect.top + window.pageYOffset - docEl.clientTop;
  var rectLeft = rect.left + window.pageXOffset - docEl.clientLeft;

  els[i].innerHTML = "<b>" + rectLeft + ", " + rectTop + "</b>";
}
div {
  width: 100px;
  height: 100px;
  background-color: red;
  border: 1px solid black;
}
#rel {
  position: relative;
  left: 10px;
  top: 10px;
}
#abs {
  position: absolute;
  top: 250px;
  left: 250px;
}
<div id="rel"></div>
<div id="abs"></div>
<div></div>

respondido 04 nov., 14:14

Este es el mejor código que he logrado crear (también funciona en iframes, a diferencia del offset () de jQuery). Parece que webkit tiene un comportamiento un poco diferente.

Basado en el comentario de meouw:

function getOffset( el ) {
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
        _x += el.offsetLeft - el.scrollLeft;
        _y += el.offsetTop - el.scrollTop;
        // chrome/safari
        if ($.browser.webkit) {
            el = el.parentNode;
        } else {
            // firefox/IE
            el = el.offsetParent;
        }
    }
    return { top: _y, left: _x };
}

Respondido el 10 de Septiembre de 11 a las 18:09

Tenga en cuenta que necesitará jQuery que se utilizará $.browser.webkit; Necesitarás jugar con navigator.userAgent hacer lo mismo con puro JavaScript. - SP

$ .browser ya no está disponible en la última versión de jQuery - Gus

desafortunadamente, incluso con FF 24.4, el código anterior no funciona cuando existen anchos de borde como parte del diseño de posicionamiento. - robar

Si bien es muy probable que esto se pierda en la parte inferior de tantas respuestas, las principales soluciones aquí no funcionaron para mí.
Por lo que pude ver, ninguna de las otras respuestas habría ayudado.

Situación:
En una página HTML5 tenía un menú que era un elemento de navegación dentro de un encabezado (no EL encabezado sino un encabezado en otro elemento).
Quería que la navegación se mantuviera en la parte superior una vez que un usuario se desplazara hasta ella, pero antes de esto, el encabezado estaba en una posición absoluta (por lo que podría superponerlo ligeramente sobre algo más).
Las soluciones anteriores nunca provocaron un cambio porque .offsetTop no iba a cambiar ya que este era un elemento posicionado absoluto. Además, la propiedad .scrollTop era simplemente la parte superior del elemento más superior ... es decir, 0 y siempre sería 0.
Cualquier prueba que realicé utilizando estos dos (y lo mismo con los resultados de getBoundingClientRect) no me diría si la parte superior de la barra de navegación alguna vez se desplazó hasta la parte superior de la página visible (nuevamente, como se informó en la consola, simplemente se mantuvieron los mismos números mientras se desplazaba ocurrió).

Solución
La solución para mí fue utilizar

window.visualViewport.pageTop

El valor de la propiedad pageTop refleja la sección visible de la pantalla, lo que me permite rastrear dónde está un elemento en referencia a los límites del área visible.

Probablemente sea innecesario decirlo, cada vez que estoy lidiando con el desplazamiento, espero usar esta solución para responder programáticamente al movimiento de los elementos que se desplazan.
Espero que ayude a alguien más.
NOTA IMPORTANTE: Esto parece funcionar en Chrome y Opera actualmente y definitivamente no en Firefox (6-2018)... hasta que Firefox admita visualViewport, recomiendo NO usar este método (y espero que lo hagan pronto ... tiene mucho más sentido que el resto).


ACTUALIZACIÓN:
Solo una nota sobre esta solución.
Aunque todavía encuentro lo que descubrí que es muy valioso para situaciones en las que "... responden programáticamente al movimiento de los elementos que se desplazan". es aplicable. La mejor solución para el problema que tuve fue usar CSS para configurar posición: pegajosa en el elemento. Al usar sticky, puede hacer que un elemento permanezca en la parte superior sin usar javascript (NOTA: hay ocasiones en que esto no funcionará tan eficazmente como cambiar el elemento a fijo, pero para la mayoría de los usos, el enfoque sticky probablemente será superior)

UPDATE01:
Entonces me di cuenta de que para una página diferente tenía un requisito en el que necesitaba detectar la posición de un elemento en una configuración de desplazamiento ligeramente compleja (paralaje más elementos que se desplazan como parte de un mensaje). En ese escenario me di cuenta de que lo siguiente proporcionaba el valor que utilicé para determinar cuándo hacer algo:

  let bodyElement = document.getElementsByTagName('body')[0];
  let elementToTrack = bodyElement.querySelector('.trackme');
  trackedObjPos = elementToTrack.getBoundingClientRect().top;
  if(trackedObjPos > 264)
  {
    bodyElement.style.cssText = '';
  }

Espero que esta respuesta sea más útil ahora.

Respondido el 15 de junio de 18 a las 19:06

es muy probable que esté en la parte superior de tantas respuestas cuando hace clic en lector activo para ordenar las respuestas - Lucchi

@lucchi: D bueno, supongo que podría eliminar el texto @ en la parte superior ... aunque acabo de pasar en este caso de nuevo y me di cuenta de que había encontrado una mejor solución para mi propio problema ... aunque mi respuesta es más una nota al pie de las respuestas más completas. Sospecho que mis requisitos tal vez no eran tan comunes que las otras respuestas no funcionaron para mí. - MER

De todos modos, agradezco tu respuesta, fue solo para decirte que cualquiera que esté dispuesto sabrá que escribiste algo nuevo. Usted no está solo.... - Lucchi

Lo hice así para que fuera compatible con navegadores antiguos.

// For really old browser's or incompatible ones
    function getOffsetSum(elem) {
        var top = 0,
            left = 0,
            bottom = 0,
            right = 0

         var width = elem.offsetWidth;
         var height = elem.offsetHeight;

        while (elem) {
            top += elem.offsetTop;
            left += elem.offsetLeft;
            elem = elem.offsetParent;
        }

         right = left + width;
         bottom = top + height;

        return {
            top: top,
            left: left,
            bottom: bottom,
            right: right,
        }
    }

    function getOffsetRect(elem) {
        var box = elem.getBoundingClientRect();

        var body = document.body;
        var docElem = document.documentElement;

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

        var clientTop = docElem.clientTop;
        var clientLeft = docElem.clientLeft;


        var top = box.top + scrollTop - clientTop;
        var left = box.left + scrollLeft - clientLeft;
        var bottom = top + (box.bottom - box.top);
        var right = left + (box.right - box.left);

        return {
            top: Math.round(top),
            left: Math.round(left),
            bottom: Math.round(bottom),
            right: Math.round(right),
        }
    }

    function getOffset(elem) {
        if (elem) {
            if (elem.getBoundingClientRect) {
                return getOffsetRect(elem);
            } else { // old browser
                return getOffsetSum(elem);
            }
        } else
            return null;
    }

Más sobre coordenadas en JavaScript aquí: http://javascript.info/tutorial/coordinates

Respondido 06 Abr '15, 22:04

Para obtener el desplazamiento total de un elemento, puede sumar de forma recursiva todos los desplazamientos principales:

function getParentOffsets(el): number {
if (el.offsetParent) {
    return el.offsetParent.offsetTop + getParentOffset(el.offsetParent);
} else {
    return 0;
}
}

con esta función de utilidad, el desplazamiento superior total de un elemento dom es:

el.offsetTop + getParentOffsets(el);

respondido 01 mar '19, 13:03

Esta respuesta se parece a lo que me gustaría, excepto que aparece el error "Error de referencia no detectado: getParentOffset no está definido". Falta una 's', ¿verdad? Así que cambié la línea de retorno de la función para agregar una 's' a 'getParentOffset'. No hay error ahora, pero saber que hubo un error me preocupa ... - kenneth558

Utilicé con éxito la solución de Andy E para colocar un modal de bootstrap 2 dependiendo del enlace en una fila de la tabla en el que hace clic el usuario. La página es una página de Tapestry 5 y el javascript a continuación se importa en la clase de página de Java.

JavaScript:

function setLinkPosition(clientId){
var bodyRect = document.body.getBoundingClientRect(),
elemRect = clientId.getBoundingClientRect(),
offset   = elemRect.top - bodyRect.top;
offset   = offset + 20;
$('#serviceLineModal').css("top", offset);

}

Mi código modal:

<div id="serviceLineModal" class="modal hide fade add-absolute-position" data-backdrop="static" 
 tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="top:50%;">
<div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
    <h3 id="myModalLabel">Modal header</h3>
</div>

<div class="modal-body">
    <t:zone t:id="modalZone" id="modalZone">
        <p>You selected service line number: ${serviceLineNumberSelected}</p>
    </t:zone>
</div>

<div class="modal-footer">
    <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
    <!-- <button class="btn btn-primary">Save changes</button> -->
</div>

El enlace en el bucle:

<t:loop source="servicesToDisplay" value="service" encoder="encoder">
<tr style="border-right: 1px solid black;">       
    <td style="white-space:nowrap;" class="add-padding-left-and-right no-border"> 
        <a t:type="eventLink" t:event="serviceLineNumberSelected" t:context="service.serviceLineNumber" 
            t:zone="pageZone" t:clientId="modalLink${service.serviceLineNumber}"
            onmouseover="setLinkPosition(this);">
            <i class="icon-chevron-down"></i> <!-- ${service.serviceLineNumber} -->
        </a>
    </td>

Y el código java en la clase de página:

void onServiceLineNumberSelected(String number){
    checkForNullSession();
    serviceLineNumberSelected = number;
    addOpenServiceLineDialogCommand();
    ajaxResponseRenderer.addRender(modalZone);
}

protected void addOpenServiceLineDialogCommand() {
    ajaxResponseRenderer.addCallback(new JavaScriptCallback() {
        @Override
        public void run(JavaScriptSupport javascriptSupport) {
            javascriptSupport.addScript("$('#serviceLineModal').modal('show');");
        }
    });
}

Espero que esto ayude a alguien, esta publicación ayudó.

Respondido 23 Oct 14, 16:10

Este código js me ayudó, tengo una aplicación de formularios web antigua que usa múltiples marcadores de posición para inyectar páginas .aspx y no pude averiguar cómo agregarChild () de un cuadro emergente que estaba creando para colocarlo en la ventana gráfica porque todo el árbol DOM está bloqueado con los marcadores de posición múltiples y el marcado incorrecto. Usar body.getBoundingClientRect () y luego usar su parte superior en el posicionamiento era lo que necesitaba. Gracias. - Brad Martin

Después de mucha investigación y pruebas, esto parece funcionar.

function getPosition(e) {
    var isNotFirefox = (navigator.userAgent.toLowerCase().indexOf('firefox') == -1);
    var x = 0, y = 0;
    while (e) {
        x += e.offsetLeft - e.scrollLeft + (isNotFirefox ? e.clientLeft : 0);
        y += e.offsetTop - e.scrollTop + (isNotFirefox ? e.clientTop : 0);
        e = e.offsetParent;
    }
    return { x: x + window.scrollX, y: y + window.scrollY };
}

ver http://jsbin.com/xuvovalifo/edit?html,js,output

Respondido el 18 de junio de 15 a las 08:06

Solo pensé en tirar esto por ahí también.
No he podido probarlo en navegadores más antiguos, pero funciona en el último de los 3 principales :)

Element.prototype.getOffsetTop = function() {
    return ( this.parentElement )? this.offsetTop + this.parentElement.getOffsetTop(): this.offsetTop;
};
Element.prototype.getOffsetLeft = function() {
    return ( this.parentElement )? this.offsetLeft + this.parentElement.getOffsetLeft(): this.offsetLeft;
};
Element.prototype.getOffset = function() {
    return {'left':this.getOffsetLeft(),'top':this.getOffsetTop()};
};

Respondido el 02 de Septiembre de 15 a las 14:09

Dado que los diferentes navegadores están representando el borde, el relleno, el margen, etc. de manera diferente. Escribí una pequeña función para recuperar las posiciones superior e izquierda de un elemento específico en cada elemento raíz que desee en una dimensión precisa:

function getTop(root, offset) {
    var rootRect = root.getBoundingClientRect();
    var offsetRect = offset.getBoundingClientRect();
    return offsetRect.top - rootRect.top;
}

Para recuperar la posición izquierda debe regresar:

    return offsetRect.left - rootRect.left;

respondido 05 mar '15, 15:03

Esto es tan fácil como dos líneas en JS:

var elem = document.getElementById("id");    
alert(elem.getBoundingClientRect());

Respondido 12 ago 20, 13:08

Esta respuesta está incompleta y no agrega nada a las respuestas anteriores. - mfluehr

Obtener la posición de div con respecto a la izquierda y la parte superior

  var elm = $('#div_id');  //get the div
  var posY_top = elm.offset().top;  //get the position from top
  var posX_left = elm.offset().left; //get the position from left 

contestado el 27 de mayo de 18 a las 03:05

Voté en contra porque la parte inferior y la derecha no son propiedades de offset () - macrohombre

@MacroMan, respeto tu decisión pero ya he explicado en el texto que "abajo y derecha el código no está probado". Además, actualizaré mi código muy pronto. - vishal kumar

creo que es el.offsetTop y el.offsetLeft (el OP no dice nada sobre jQuery ... tampoco estoy seguro de por qué su respuesta usa jQuery ...) - mesqueeb

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.