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


1570

Quiero saber cómo obtener la posición X e Y de los elementos HTML, como imgy diven JavaScript, en relación con la ventana del navegador.


134
¿Relativo a qué?
AnthonyWJones

44
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 tener 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 sombody puede señalar las fallas si las hay.
Jayapal Chandran

99
@AnthonyWJones, supongo que necesitabas el placer pedante, pero es obvio, como siempre 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.
Motes

77
@Mote, no, no es tan obvio. Deje de lado la inferencia, la subjetividad y los axiomas falsos. Puede ser relativo a la vista o al inicio de la página (también conocido como document.documentElement).
Andre Figueiredo

16
Por defecto, el más general no es 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 tal como lo pones. En Game Theory, se codifica como un concepto llamado punto de Schelling. Asegúrese de especificar cuándo no se refiere al caso más general.
Motes

Respuestas:


1796

El enfoque correcto es usar element.getBoundingClientRect():

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

Internet Explorer lo ha respaldado desde que es probable que le importe y finalmente se estandarizó en las 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 del navegador anterior, consulte las revisiones de esta respuesta para una implementación degradante optimizada.

Los valores devueltos por element.getBoundingClientRect()son relativos 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>');

143
Un artículo muy interesante sobre las coordenadas JS . En este artículo se menciona en ninguna parte en lo tanto, debe ..
e2-e4

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

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

44
@CpnCrunch: veo a qué te refieres ahora; No me di cuenta de que te referías 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. Sin <body>embargo, vale la pena señalar que los reinicios de CSS eliminan el margen .
Andy E

3
element.getBoundingClientRect().topno devuelve el desplazamiento superior correcto en el caso de un position: fixedelemento 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 de 200 px, lo informaría como 420 px, donde 220 px es la altura del teclado virtual. Si configura los elementos position: absolutey los coloca en la misma posición que si fueran fijos, obtendrá el 200px correcto. No sé una solución para esto.
Jānis Elmeris

327

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; 

14
cambiar: el = el.parentNode a: el = el.offsetParent; y parece funcionar para iframes anidados ahora ... ¿Creo que eso es lo que pretendías?
Adam el

44
Esta solución está incompleta. Intenta poner un borde grueso en un div y anidéalo varias veces. En cualquier versión de Firefox (2-5) estará desactivado por el ancho de los bordes (incluso en modo de cumplimiento de estándares).
ck_

3
¿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, ¿debemos esperar DOM4? Estoy creando una aplicación de lienzo HTML5, por lo 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 hacemos clic en el elemento.
baptx

1
Entonces, @Adam y meouw, ¿estás 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; ¿podría ser bueno eliminar las cosas si están equivocadas?)
Arjan

2
@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: realmente ni siquiera necesita el código de respaldo, ya que los navegadores lo han soportado durante mucho tiempo.
Andy E

242

Esto funcionó para mí (modificado de la respuesta más votada):

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

Usando esto podemos llamar

getOffset(element).left

o

getOffset(element).top

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

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

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

1
Debe definir rectel uso de var, leto const. De lo contrario, se define como window.rect.
hev1

2
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

97

Si desea que se haga solo en javascript , aquí hay algunos liners que usangetBoundingClientRect()

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

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

La primera línea devolverá offsetTopdecir Y en relación con el documento. La segunda línea devolverá offsetLeftdecir X en relación con el 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.


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

2
¿Qué pasa si el elemento está dentro de un elemento desplazable? La única forma de hacerlo es sumar la compensación de la parte superior 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 como lo hace. SIEMPRE también estará en un elemento desplazable porque el documento en sí puede desplazarse. En otras palabras, a menos que todo el documento se ajuste a la ventana gráfica, siempre será incorrecto si el usuario ha desplazado la ventana principal.
Lev

46

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 una posición de los elementos con el área del cliente principal (el área acolchada es parte del área del cliente pero el borde y el margen no lo son).


36

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

Pruebe el código que figura a continuación (se verifica 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];
};

1
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 a través de algunos errores de GWT bastante profundos en este momento y lanzar esto en un método JSNI resuelve todos mis problemas.
Will Byrne

35

Puede agregar dos propiedades para Element.prototypeobtener 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().topy .left: http://jsfiddle.net/ThinkingStiff/3G7EZ/


14
la modificación Element.prototypegeneralmente 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

23

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;

Incluyendo el importante scrollTop / scrollLeft hace que esta respuesta sea un poco más correcta.
scunliffe

19

¿Qué tal algo como esto? Al pasar la 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');

o 3) encontrar izquierda y arriba juntos

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

16

Es posible que le sirva mejor utilizando un marco de JavaScript, que tiene funciones para devolver dicha información (¡y mucho más!) De forma independiente del navegador. Aquí hay algunos:

Con estos marcos, puede hacer algo como: $('id-of-img').top obtener la coordenada y-pixel de la imagen.


2
@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 salen mal. Realmente deberías mirar el código fuente.
Shalom Craimer

18
@scraimer: ¡jQuery y YUI NO son marcos ! Estas son bibliotecas ! No es lo mismo. Citando jquery.com : "jQuery es una biblioteca de JavaScript rápida, pequeña y rica en funciones ". Citando yuilibrary.com (también se puede ver la palabra "mágica" en la URL ...): "YUI es una biblioteca gratuita de código abierto de JavaScript y CSS para crear aplicaciones web ricamente interactivas".
Sk8erPeter

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

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

55
@NickManning No es un lenguaje nuevo, es una capa de abstracción para el DOM que elimina la necesidad de escribir soluciones de compatibilidad y rendimiento directamente en su código. Si no usa jQuery, debería estar usando algún tipo de capa de abstracción de todos modos.
ginman

15

jQuery .offset () 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.


Por alguna razón, no está dando 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á diferentes resultados en IE en comparación con otros
Abdul Rahim Haddad

1
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

10

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

getAbsoluteOffsetFromBody - similar a @ meouw's, esto obtiene la posición absoluta en relación con el cuerpo o el elemento html del documento (dependiendo del modo peculiaridades)

getAbsoluteOffsetFromGivenElement: devuelve la posición absoluta en relación con el elemento dado (relativeEl). Tenga en cuenta que el elemento dado debe contener el elemento el, o esto 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 colocarlos en la misma posición.

getAbsoluteOffsetFromRelative: devuelve la posición absoluta relativa al primer elemento padre con position: relative. Esto es similar a getAbsoluteOffsetFromGivenElement, por la misma razón, pero solo irá 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 todavía tiene problemas, particularmente en relación 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 comporten bien , pero no he probado el resto en absoluto.


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.
Norman

getAbsoluteOffsetFromRelative hizo mi 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 subir esto hilo de edad así que sí, puesto en comentario)
Mukyuu

8

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 mucho que puedes hacer con él.

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


8

Este es el mejor código que he logrado crear (también funciona en iframes, a diferencia del desplazamiento 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 };
}

Tenga en cuenta que jQuerydeberá usar $.browser.webkit; Tendrás que jugar navigator.userAgentpara hacer lo mismo con pure JavaScript.
SP

2
$ .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

8

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>

8

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


Desafortunadamente, esto no funciona para todos los elementos que uno puede encontrar dentro de un documento HTML moderno. Embedded <svg>elementos, por ejemplo, no tienen offsetLeft, offsetTopy offsetParentpropiedades.
Jonathan Eunice

Es justo DIVo IMGno SVG. Ver "Buscar un ejemplo de coordenadas"? puede encontrar el objeto svg es llamar a la posición getOffsetRect , intente y dependa del trabajo del objeto.
KingRider

7

El enfoque más limpio que he encontrado es una versión simplificada de la técnica utilizada por jQuery offset. Similar a algunas de las otras respuestas con las que comienza getBoundingClientRect; luego usa el windowy el documentElementpara ajustar la posición de desplazamiento, así como elementos como el margen en 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;


6

Si bien es muy probable que esto se pierda al final de tantas respuestas, las mejores soluciones aquí no me funcionaron.
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 hacia ella, pero antes de esto, el encabezado estaba en una posición absoluta (para que pudiera superponer algo más).
Las soluciones anteriores nunca activaron un cambio porque .offsetTop no iba a cambiar ya que este era un elemento de posición absoluta. 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ó a la parte superior de la página visible (nuevamente, como se informó en la consola, simplemente permanecieron 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 decir que cada vez que estoy tratando 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 ... hace mucho) más sentido que el resto).


ACTUALIZACIÓN:
solo una nota con respecto a esta solución.
Si bien todavía encuentro que lo que descubrí es muy valioso para situaciones en las que "... responde 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 establecer la posición: pegajosoen el elemento Usando sticky puede hacer que un elemento permanezca en la parte superior sin usar javascript (NOTA: hay veces que esto no funcionará de manera tan efectiva como cambiar el elemento a fijo pero para la mayoría de los usos el enfoque adhesivo probablemente sea superior)

ACTUALIZACIÓN01:
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 levemente compleja (paralaje más elementos que se desplazan como parte de un mensaje). Me di cuenta en ese escenario que lo siguiente proporcionó 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.


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

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

1
Aprecio tu respuesta de todos modos, fue solo para decirte que cualquiera que esté dispuesto sabrá que escribiste algo nuevo. No estás solo ...
lucchi 01 de

5

Lo hice así, por lo que era compatible con los 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 información sobre las coordenadas en JavaScript aquí: http://javascript.info/tutorial/coordinates


4

Para obtener el desplazamiento total de un elemento, puede resumir recursivamente 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);

3
/**
 *
 * @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;
}

Gracias ThinkingStiff por la respuesta , esta es solo otra versión de la misma.


2

Utilicé con éxito la solución de Andy E para posicionar un modo de arranque 2 dependiendo de en qué enlace de una fila de la tabla haga clic el usuario. La página es una página de Tapestry 5 y javascript se importa a continuación en la clase de página 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 de 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ó.


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 encontrar la manera de agregar Child () de un cuadro emergente que estaba creando para ingresarlo a la ventana gráfica porque todo el árbol DOM está loco con los múltiples marcadores de posición y marcado incorrecto. Usar el body.getBoundingClientRect () y luego usar su parte superior en posicionamiento era lo que necesitaba. Gracias.
Brad Martin

1

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


1

Solo pensé en tirar esto por ahí también.
No he podido probarlo en navegadores 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()};
};

0

Dado que diferentes navegadores representan bordes, relleno, 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;

-1

Obtener posición de div con respecto a izquierda y arriba

  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 

Voté a la baja porque la parte inferior y la derecha no son propiedades de offset ()
MacroMan

@MacroMan, respeto su decisión, pero ya he explicado en el texto que "el código inferior y derecho no se ha probado". Además, actualizaré mi código muy pronto.
Vishal

Creo que es el.offsetTopy el.offsetLeft(el PO no dice nada acerca de jQuery ... No estoy seguro de por qué su respuesta utiliza jQuery tampoco ...)
mesqueeb
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.