91 votes

offsetTop vs. jQuery.offset().top

J'ai lu que offsetLeft y offsetTop ne fonctionnent pas correctement dans tous les navigateurs. jQuery.offset() est censé fournir une abstraction pour cela afin de fournir la valeur correcte xbrowser.

Ce que j'essaie de faire, c'est d'obtenir les coordonnées de l'endroit où un élément a été cliqué par rapport à la partie supérieure gauche de l'élément.

Le problème est que jQuery.offset().top me donne en fait une valeur décimale dans FFX 3.6 (dans IE et Chrome, les deux valeurs correspondent).

Ce violon expose le problème. Si vous cliquez sur l'image du bas, jQuery.offset().top renvoie 327,5, mais offsetTop retourne 328.

J'aimerais penser que offset() renvoie la valeur correcte et je devrais l'utiliser car il fonctionnera sur tous les navigateurs. Cependant, il est évident que les gens ne peuvent pas cliquer sur des décimales de pixels. Quelle est la bonne façon de déterminer le véritable décalage de l'image ? Math.round() le décalage que jQuery renvoie ? Dois-je utiliser offsetTop à la place, ou une autre méthode entièrement différente ?

85voto

Jan Turoň Points 6598

C'est ce que Doc. API jQuery dit à propos de .offset() :

Obtenez les coordonnées actuelles du premier élément, ou définissez le paramètre coordonnées de chaque élément, dans l'ensemble des éléments appariés, par rapport aux coordonnées du premier élément. par rapport à l'élément document .

C'est ce que API Web MDN dit à propos de .offsetTop :

offsetTop renvoie la distance de l'élément courant par rapport à l'élément haut de l'élément nœud offsetParent

C'est ce que fait jQuery v.1.11 .offset() pour obtenir les coordonnées :

var box = { top: 0, left: 0 };

// BlackBerry 5, iOS 3 (original iPhone)
if ( typeof elem.getBoundingClientRect !== strundefined ) {
  box = elem.getBoundingClientRect();
}
win = getWindow( doc );
return {
  top: box.top  + ( win.pageYOffset || docElem.scrollTop )  - ( docElem.clientTop  || 0 ),
  left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
};
  • pageYOffset indique intuitivement combien de fois la page a défilé.
  • docElem.scrollTop est la solution de repli pour IE<9 (qui ne sont pas supportés dans jQuery 2).
  • docElem.clientTop est la largeur de la bordure supérieure d'un élément (le document dans ce cas)
  • elem.getBoundingClientRect() obtient les coordonnées relatives à la document fenêtre d'observation (voir les commentaires). Il peut renvoyer des valeurs fractionnées, c'est donc la source de votre bogue. Il peut également peut causer un bug dans IE<8 lorsque la page est zoomée. Pour éviter les valeurs fractionnées, essayez de calculer la position itérativement

Conclusion

  • Si vous voulez des coordonnées relatives à la nœud parent utiliser element.offsetTop . Ajouter element.scrollTop si vous voulez prendre en compte le défilement du parent. (ou utilisez jQuery .position() si vous êtes fan de cette bibliothèque)
  • Si vous voulez des coordonnées relatives à la fenêtre d'observation utiliser element.getBoundingClientRect().top . Ajouter window.pageYOffset si vous voulez prendre en compte le défilement du document. Il n'est pas nécessaire de soustraire la valeur de l'indicateur clientTop si le document n'a pas de bordure (ce qui n'est généralement pas le cas), vous avez donc une position relative à l'élément document
  • Soustraire element.clientTop si vous ne considérez pas la bordure de l'élément comme une partie de l'élément

0 votes

Element.getBoundingClientRect() donne les positions par rapport à la fenêtre d'observation et non le document

0 votes

@Klaus : pouvez-vous expliquer quelle est la différence exacte ?

2 votes

@JanTuron : La différence est qu'elle est relative au haut de la fenêtre du navigateur et non au "vrai haut" du document. Cela signifie qu'il retournera des valeurs négatives si vous faites défiler le haut du document au-delà du haut de la fenêtre, par exemple.

15voto

ChristopheCVB Points 4355

Je pense que vous avez raison de dire que les gens ne peuvent pas cliquer sur des demi-pixels, donc personnellement, j'utiliserais un décalage jQuery arrondi...

4 votes

Le décalage de jQuery est bogué lorsque le zoom CSS est utilisé

5voto

steve Points 407

Essayez ça : parseInt(jQuery.offset().top, 10)

1 votes

J'aimerais qu'il y ait une raison derrière tout ça, pour que je puisse voter pour toi.

2voto

Emyr Points 1460

Il est possible que le offset peut être un nombre non entier, en utilisant em comme unité de mesure, relative font-sizes sur % .

Je pense également que le offset peut ne pas être un nombre entier lorsque le zoom n'est pas 100% mais cela dépend de la façon dont le navigateur gère la mise à l'échelle.

2 votes

Si le zoom n'est pas de 100%, offset().top vous donnera une pléthore d'autres problèmes ... bugs.jquery.com/ticket/8362

-1voto

ShankarSangoli Points 45345

Vous pouvez utiliser parseInt(jQuery.offset().top) pour toujours utiliser l'Integer (primitif) int ) dans tous les navigateurs.

1 votes

Est-ce que parseInt() arrondit les doubles ou les tronque ?

0 votes

Il prendra simplement la partie entière du nombre et il sera le même dans tous les navigateurs.

0 votes

Le PO indique que dans un navigateur il donne 327.5 alors que dans un autre il donne 328. Donc, si vous prenez juste la partie entière (tronquée), le PO lui-même en est un exemple. pas étant la même sur tous les navigateurs. Dans cet exemple au moins, il faudrait arrondir les deux pour obtenir le même chiffre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X