Utilisation de jquery pour obtenir la position de l'élément par rapport à la fenêtre

117

Quelle est la bonne façon d'obtenir la position d'un élément sur la page par rapport à la fenêtre (plutôt qu'au document). jQuery.offsetla fonction semblait prometteuse:

Obtenez les coordonnées actuelles du premier élément, ou définissez les coordonnées de chaque élément, dans l'ensemble des éléments correspondants, par rapport au document.

Mais c'est relatif au document. Existe-t-il une méthode équivalente qui renvoie les décalages par rapport à la fenêtre?

DA.
la source
5
REMARQUE: Voir la réponse de @Igor G ...
Carl Smith
3
Pour DA, vous devriez vraiment définir la réponse d'Igor G comme acceptée, c'est une bouée de sauvetage!
Vincent Duprez

Réponses:

26

Regardez dans le plugin Dimensions, en particulier scrollTop()/ scrollLeft(). Des informations peuvent être trouvées sur http://api.jquery.com/scrollTop .

Agent_9191
la source
8
Je ne voulais pas utiliser un autre plugin, mais $ (window) .scrollTop () est exactement ce dont j'avais besoin! Merci!
DA.
16
Le plugin dimensions fait désormais partie du noyau jQuery. Le plugin ViewPort peut également être utile: appelsiini.net/projects/viewport
StriplingWarrior
288

Le moyen le plus simple de déterminer la taille et la position d'un élément est d'appeler sa méthode getBoundingClientRect () . Cette méthode renvoie les positions des éléments dans les coordonnées de la fenêtre. Il n'attend aucun argument et renvoie un objet avec les propriétés left, right, top et bottom . Les propriétés left et top donnent les coordonnées X et Y du coin supérieur gauche de l'élément et les propriétés right et bottom donnent les coordonnées du coin inférieur droit.

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

Pris en charge partout.

Igor G.
la source
15
C'est incroyable cette méthode a été ajoutée par IE5 ... quand quelque chose est bien, c'est bien!
roy riojas
Cela semblait génial au début, mais cela ne tient pas compte du fait qu'un utilisateur effectue un zoom sur Mobile Safari 7.
MyNameIsKo
2
Non pris en charge par le dernier FirefoxgetBoundingClientRect is not a function
user007
2
@ user007 Je confirme qu'il est pris en charge par le dernier Firefox.
adriendenat
27
Excellente réponse, et pour le faire jquery, faites-le simplement de cette façon: $('#myElement')[0].getBoundingClientRect().top(ou toute autre position)
Guillaume Arluison
40

Voici deux fonctions pour obtenir la hauteur de la page et les montants de défilement (x, y) sans utiliser le plugin de dimensions (gonflées):

// 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
la source
C'est génial. Très utile.
Jimmy
Par curiosité, pourquoi avez-vous utilisé la propriété «self» au lieu de window dans ce cas?
dkugappi
23

jQuery.offsetdoit être combiné avec scrollTopet scrollLeftcomme indiqué dans ce diagramme:

défilement de la fenêtre et décalage d'élément

Démo:

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
la source
2
cela a très bien fonctionné pour moi, mais je l'utilisais pour déterminer si une info-bulle sortait des limites, j'ai donc modifié pour inclure les valeurs en bas et à droite: jsfiddle.net/EY6Rk/21
Jordanie
C'est la réponse absolument, en tout cas, correcte. Tous les autres ont des problèmes en fonction de la configuration delta de la souris / du défilement, des navigateurs, de l'emplacement de l'objet, etc.
Pedro Ferreira
2

Voici une fonction qui calcule la position actuelle d'un élément dans la fenêtre:

/**
 * 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))
    ];
}

Les valeurs de retour sont calculées comme ceci:

Usage:

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

Démo:

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
la source
0

J'ai trouvé que la réponse de cballou ne fonctionnait plus dans Firefox à partir de janvier 2014. Plus précisément, if (self.pageYOffset)cela ne s'est pas déclenché si le client avait fait défiler vers la droite, mais pas vers le bas - parce que 0c'est un nombre faux. Cela n'a pas été détecté pendant un certain temps car Firefox supportait document.body.scrollLeft/ Top, mais cela ne fonctionne plus pour moi (sur Firefox 26.0).

Voici ma solution modifiée:

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

Testé et fonctionnant sous FF26, Chrome 31, IE11. Fonctionne presque certainement sur les anciennes versions de tous.

pglhall
la source