Quiero saber cómo obtener la posición X e Y de elementos HTML como imgy diven JavaScript.

respuesta

El enfoque correcto es usar element.getBoundingClientRect():

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

Internet Explorer ha soportado esto desde que es probable que le interese y finalmente se estandarizó en CSSOM Views . 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 con navegadores anteriores, consulte las revisiones de esta respuesta para obtener 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>');

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

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; 

Si desea que se haga solo en javascript , aquí hay algunos revestimientos 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á, por offsetLeftejemplo, 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.

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

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, debe manejar tanto offsetParent como parentNode.

Pruebe el código que se proporciona 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];
};

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/

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;

¿Qué tal algo como esto, al pasar 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 arriba

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

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.

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

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

/**
 *
 * @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 a ThinkingStiff por la respuesta , esta es solo otra versión.

Aquí hay un 1-liner moderno que usa Vanilla JS para iterar recursivamente sobre element.offsetTopy element.offsetParent:

Función:

getTop = el => el.offsetTop + (el.offsetParent && getTop(el.offsetParent))

Uso:

const el = document.querySelector('#div_id');
const elTop = getTop(el)

Ventaja:

Siempre devuelve el desplazamiento vertical absoluto, independientemente de la posición de desplazamiento actual.


Sintaxis tradicional:

function getTop(el) {
  return el.offsetTop + (el.offsetParent && getTop(el.offsetParent));
}

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

getAbsoluteOffsetFromBody: similar a @meouw, obtiene la posición absoluta relativa al cuerpo o elemento html del documento (según el modo peculiar)

getAbsoluteOffsetFromGivenElement: devuelve la posición absoluta relativa al elemento dado (relativeEl). 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 colocarlos 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 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 suponiendo que los navegadores se comporten , pero no he probado el resto en absoluto.

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

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>

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 liviano y fácil de usar, no volverás a JavaScript sin él después.

Para obtener el desplazamiento total de un elemento, puede resumir recursivamente todos los desplazamientos principales:

function getParentOffset(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 + getParentOffset(el);

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 windowy el documentElementpara ajustar la posición de desplazamiento, así como cosas como el margen en body(a menudo el valor 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>

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

Si bien es muy probable que esto se pierda en la parte inferior 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 el usuario se desplazaba hacia ella, pero antes de esto, el encabezado estaba en una posición absoluta (por lo que podría superponerse ligeramente a otra cosa).
Las soluciones anteriores nunca desencadenaron 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 alto... 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 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 se encuentra un elemento en referencia a los límites del área visible.

Probablemente no sea necesario decirlo, cada vez que trato 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 sobre esta solución.
Si bien todavía encuentro que lo que descubrí 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 establecer la posición: pegajosasobre el elemento. Al usar sticky, puede hacer que un elemento permanezca en la parte superior sin usar javascript (NOTA: hay veces que esto no funcionará tan efectivamente como cambiar el elemento a fijo, pero para la mayoría de los usos, el enfoque sticky probablemente será superior)

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

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

    
HTML program to show (x, y) of an
element by dragging mouse over it  you just copied it and use it on your own 
<!DOCTYPE html>
<html>
    <head>
        <title>
            position of an element
        </title>
        
        <!-- scropt to get position -->
        <script type = "text/javascript">
            function getPositionXY(element) {
                var rect = element.getBoundingClientRect();
                document.getElementById('text').innerHTML
                = 'X: ' + rect.x + '<br>' + 'Y: ' + rect.y;
            }
        </script>
    </head>
    
    <body>
        <p>Move the mouse over the text</p>
        
        <div onmouseover = "getPositionXY(this)">
            Position:
            <p id = 'text'></p>
        </div>
    
    </body>
</html>                 

Utilicé con éxito la solución de Andy E para colocar un modal de arranque 2 según el enlace en una fila de la tabla en el que hace clic un 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 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ó.

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,salida

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

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

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

Dado que los diferentes navegadores representan 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 devolver:

    return offsetRect.left - rootRect.left;

Get position of div in respect to left and Top

  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