Usando jquery para obtener la posición del elemento relativa a la ventana gráfica

117

¿Cuál es la forma correcta de obtener la posición de un elemento en la página en relación con la ventana gráfica (en lugar del documento)? jQuery.offsetla función parecía prometedora:

Obtenga las coordenadas actuales del primer elemento, o establezca las coordenadas de cada elemento, en el conjunto de elementos coincidentes, en relación con el documento.

Pero eso es relativo al documento. ¿Existe un método equivalente que devuelva compensaciones en relación con la ventana gráfica?

DA.
fuente
5
NOTA: Vea la respuesta de @Igor G ...
Carl Smith
3
Para DA, realmente debería establecer la respuesta de Igor G como aceptada, ¡es un salvavidas!
Vincent Duprez

Respuestas:

26

Busque en el complemento Dimensiones, específicamente scrollTop()/ scrollLeft(). Puede encontrar información en http://api.jquery.com/scrollTop .

Agent_9191
fuente
8
No quería usar otro complemento, ¡pero $ (window) .scrollTop () es exactamente lo que necesitaba! ¡Gracias!
DA.
16
El complemento de dimensiones ahora es parte del núcleo de jQuery. El complemento ViewPort también puede ser útil: appelsiini.net/projects/viewport
StriplingWarrior
287

La forma más sencilla de determinar el tamaño y la posición de un elemento es llamar a su método getBoundingClientRect () . Este método devuelve las posiciones de los elementos en las coordenadas de la ventana gráfica. No espera argumentos y devuelve un objeto con propiedades left, right, top e bottom . Las propiedades izquierda y superior dan las coordenadas X e Y de la esquina superior izquierda del elemento y las propiedades derecha e inferior dan las coordenadas de la esquina inferior derecha.

element.getBoundingClientRect(); // Get position in viewport coordinates

Soportado en todas partes.

Igor G.
fuente
15
Es increíble que IE5 haya agregado este método ... cuando algo es bueno, ¡es bueno!
roy riojas
Esto parecía genial al principio, pero no tiene en cuenta un usuario que hace zoom en Mobile Safari 7.
MyNameIsKo
2
No es compatible con la última getBoundingClientRect is not a function
versión de Firefox
2
@ user007 Confirmo que ES compatible con el último firefox.
adriendenat
26
Gran respuesta, y para que sea jquery, simplemente hágalo de esta manera: $('#myElement')[0].getBoundingClientRect().top(o cualquier otra posición)
Guillaume Arluison
40

Aquí hay dos funciones para obtener la altura de la página y las cantidades de desplazamiento (x, y) sin el uso del complemento de dimensiones (hinchado):

// getPageScroll() by quirksmode.com
function getPageScroll() {
    var xScroll, yScroll;
    if (self.pageYOffset) {
      yScroll = self.pageYOffset;
      xScroll = self.pageXOffset;
    } else if (document.documentElement && document.documentElement.scrollTop) {
      yScroll = document.documentElement.scrollTop;
      xScroll = document.documentElement.scrollLeft;
    } else if (document.body) {// all other Explorers
      yScroll = document.body.scrollTop;
      xScroll = document.body.scrollLeft;
    }
    return new Array(xScroll,yScroll)
}

// Adapted from getPageSize() by quirksmode.com
function getPageHeight() {
    var windowHeight
    if (self.innerHeight) { // all except Explorer
      windowHeight = self.innerHeight;
    } else if (document.documentElement && document.documentElement.clientHeight) {
      windowHeight = document.documentElement.clientHeight;
    } else if (document.body) { // other Explorers
      windowHeight = document.body.clientHeight;
    }
    return windowHeight
}
Corey Ballou
fuente
Esto es brillante. Muy útil.
Jimmy
Por curiosidad, ¿por qué usó la propiedad "self" en lugar de la ventana en este caso?
dkugappi
23

jQuery.offsetdebe combinarse con scrollTopy scrollLeftcomo se muestra en este diagrama:

desplazamiento de la ventana gráfica y desplazamiento del elemento

Manifestación:

function getViewportOffset($e) {
  var $window = $(window),
    scrollLeft = $window.scrollLeft(),
    scrollTop = $window.scrollTop(),
    offset = $e.offset(),
    rect1 = { x1: scrollLeft, y1: scrollTop, x2: scrollLeft + $window.width(), y2: scrollTop + $window.height() },
    rect2 = { x1: offset.left, y1: offset.top, x2: offset.left + $e.width(), y2: offset.top + $e.height() };
  return {
    left: offset.left - scrollLeft,
    top: offset.top - scrollTop,
    insideViewport: rect1.x1 < rect2.x2 && rect1.x2 > rect2.x1 && rect1.y1 < rect2.y2 && rect1.y2 > rect2.y1
  };
}
$(window).on("load scroll resize", function() {
  var viewportOffset = getViewportOffset($("#element"));
  $("#log").text("left: " + viewportOffset.left + ", top: " + viewportOffset.top + ", insideViewport: " + viewportOffset.insideViewport);
});
body { margin: 0; padding: 0; width: 1600px; height: 2048px; background-color: #CCCCCC; }
#element { width: 384px; height: 384px; margin-top: 1088px; margin-left: 768px; background-color: #99CCFF; }
#log { position: fixed; left: 0; top: 0; font: medium monospace; background-color: #EEE8AA; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<!-- scroll right and bottom to locate the blue square -->
<div id="element"></div>
<div id="log"></div>

Salman A
fuente
2
esto funcionó muy bien para mí, pero estaba usando esto para determinar si una información sobre herramientas se salía de los límites, por lo que lo modifiqué para incluir los valores inferiores y derechos: jsfiddle.net/EY6Rk/21
Jordan
Esta es la respuesta absolutamente, en cualquier caso, correcta. Todos los demás tienen problemas según la configuración del delta del mouse / scroll, los navegadores, la ubicación del objeto, etc.
Pedro Ferreira
2

Aquí hay una función que calcula la posición actual de un elemento dentro de la ventana gráfica:

/**
 * Calculates the position of a given element within the viewport
 *
 * @param {string} obj jQuery object of the dom element to be monitored
 * @return {array} An array containing both X and Y positions as a number
 * ranging from 0 (under/right of viewport) to 1 (above/left of viewport)
 */
function visibility(obj) {
    var winw = jQuery(window).width(), winh = jQuery(window).height(),
        elw = obj.width(), elh = obj.height(),
        o = obj[0].getBoundingClientRect(),
        x1 = o.left - winw, x2 = o.left + elw,
        y1 = o.top - winh, y2 = o.top + elh;

    return [
        Math.max(0, Math.min((0 - x1) / (x2 - x1), 1)),
        Math.max(0, Math.min((0 - y1) / (y2 - y1), 1))
    ];
}

Los valores devueltos se calculan así:

Uso:

visibility($('#example'));  // returns [0.3742887830933581, 0.6103752759381899]

Manifestación:

function visibility(obj) {var winw = jQuery(window).width(),winh = jQuery(window).height(),elw = obj.width(),
    elh = obj.height(), o = obj[0].getBoundingClientRect(),x1 = o.left - winw, x2 = o.left + elw, y1 = o.top - winh, y2 = o.top + elh; return [Math.max(0, Math.min((0 - x1) / (x2 - x1), 1)),Math.max(0, Math.min((0 - y1) / (y2 - y1), 1))];
}
setInterval(function() {
  res = visibility($('#block'));
  $('#x').text(Math.round(res[0] * 100) + '%');
  $('#y').text(Math.round(res[1] * 100) + '%');
}, 100);
#block { width: 100px; height: 100px; border: 1px solid red; background: yellow; top: 50%; left: 50%; position: relative;
} #container { background: #EFF0F1; height: 950px; width: 1800px; margin-top: -40%; margin-left: -40%; overflow: scroll; position: relative;
} #res { position: fixed; top: 0; z-index: 2; font-family: Verdana; background: #c0c0c0; line-height: .1em; padding: 0 .5em; font-size: 12px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="res">
  <p>X: <span id="x"></span></p>
  <p>Y: <span id="y"></span></p>
</div>
<div id="container"><div id="block"></div></div>

Arne
fuente
0

Descubrí que la respuesta de cballou ya no funcionaba en Firefox a partir de enero de 2014. Específicamente, if (self.pageYOffset)no se activó si el cliente se había desplazado hacia la derecha, pero no hacia abajo, porque 0es un número falso. Esto pasó desapercibido durante un tiempo porque Firefox admitía document.body.scrollLeft/ Top, pero ya no me funciona (en Firefox 26.0).

Aquí está mi solución modificada:

var getPageScroll = function(document_el, window_el) {
  var xScroll = 0, yScroll = 0;
  if (window_el.pageYOffset !== undefined) {
    yScroll = window_el.pageYOffset;
    xScroll = window_el.pageXOffset;
  } else if (document_el.documentElement !== undefined && document_el.documentElement.scrollTop) {
    yScroll = document_el.documentElement.scrollTop;
    xScroll = document_el.documentElement.scrollLeft;
  } else if (document_el.body !== undefined) {// all other Explorers
    yScroll = document_el.body.scrollTop;
    xScroll = document_el.body.scrollLeft;
  }
  return [xScroll,yScroll];
};

Probado y funcionando en FF26, Chrome 31, IE11. Es casi seguro que funcione en versiones anteriores de todos ellos.

pglhall
fuente