Quiero saber cómo obtener la posición X e Y de los elementos HTML, como img
y div
en JavaScript, en relación con la ventana del navegador.
Quiero saber cómo obtener la posición X e Y de los elementos HTML, como img
y div
en JavaScript, en relación con la ventana del navegador.
Respuestas:
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>');
<body>
embargo, vale la pena señalar que los reinicios de CSS eliminan el margen .
element.getBoundingClientRect().top
no devuelve el desplazamiento superior correcto en el 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 de 200 px, lo informaría como 420 px, donde 220 px es la altura del teclado virtual. Si configura los elementos position: absolute
y los coloca en la misma posición que si fueran fijos, obtendrá el 200px correcto. No sé una solución para esto.
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;
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
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 simplicidad.
rect
el uso de var
, let
o const
. De lo contrario, se define como window.rect
.
left: rect.left + window.scrollX + (rect.width / 2), top: rect.top + window.scrollY + (rect.height / 2)
devolverá la posición media de un elemento
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á offsetTop
decir Y en relación con el documento. La segunda línea devolverá offsetLeft
decir 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.
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).
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];
};
Puede agregar dos propiedades para Element.prototype
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/
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.
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 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');
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.
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.
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.
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.
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 };
}
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>
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
<svg>
elementos, por ejemplo, no tienen offsetLeft
, offsetTop
y offsetParent
propiedades.
DIV
o IMG
no 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.
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 window
y el documentElement
para 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;
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.
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
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);
/**
*
* @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.
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ó.
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 };
}
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()};
};
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;
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
el.offsetTop
y el.offsetLeft
(el PO no dice nada acerca de jQuery ... No estoy seguro de por qué su respuesta utiliza jQuery tampoco ...)