Je veux savoir comment obtenir la position X et Y des éléments HTML tels que img
et div
en JavaScript par rapport à la fenêtre du navigateur.
Je veux savoir comment obtenir la position X et Y des éléments HTML tels que img
et div
en JavaScript par rapport à la fenêtre du navigateur.
Réponses:
La bonne approche consiste à utiliser element.getBoundingClientRect()
:
var rect = element.getBoundingClientRect();
console.log(rect.top, rect.right, rect.bottom, rect.left);
Internet Explorer prend en charge cela depuis aussi longtemps que vous vous en souciez et il a finalement été normalisé dans les vues CSSOM . Tous les autres navigateurs l'ont adopté il y a longtemps .
Certains navigateurs renvoient également des propriétés de hauteur et de largeur, bien que ce ne soit pas standard. Si vous êtes préoccupé par la compatibilité des anciens navigateurs, consultez les révisions de cette réponse pour une implémentation dégradée optimisée.
Les valeurs renvoyées par element.getBoundingClientRect()
sont relatives à la fenêtre. Si vous en avez besoin par rapport à un autre élément, soustrayez simplement un rectangle de l'autre:
var bodyRect = document.body.getBoundingClientRect(),
elemRect = element.getBoundingClientRect(),
offset = elemRect.top - bodyRect.top;
alert('Element is ' + offset + ' vertical pixels from <body>');
<body>
, cependant.
element.getBoundingClientRect().top
ne renvoie pas le décalage supérieur correct dans le cas d'un position: fixed
élément dans iOS (iPhone 8) s'il contient un élément d'entrée focalisé et que le clavier virtuel a glissé vers le haut. Par exemple, si le décalage réel par rapport au haut de la fenêtre est de 200 pixels, il le signalera comme 420 pixels, où 220 pixels est la hauteur du clavier virtuel. Si vous définissez l'élément position: absolute
et le positionnez à la même position que s'il était fixe, vous obtiendrez les 200 pixels corrects. Je ne connais pas de solution à cela.
Les bibliothèques vont jusqu'à certaines longueurs pour obtenir des décalages précis pour un élément.
voici une fonction simple qui fait le travail dans toutes les circonstances que j'ai essayées.
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;
Cela a fonctionné pour moi (modifié à partir de la réponse la plus votée):
function getOffset(el) {
const rect = el.getBoundingClientRect();
return {
left: rect.left + window.scrollX,
top: rect.top + window.scrollY
};
}
En utilisant cela, nous pouvons appeler
getOffset(element).left
ou
getOffset(element).top
div
le centre à l'aide de CSS top:50%, left:50%; transform:translate(-50%, -50%);
... excellent. D'accord avec la question @ScottBiggs. La logique est de rechercher la simplicité.
rect
aide var
, let
ou const
. Sinon, il est défini comme window.rect
.
left: rect.left + window.scrollX + (rect.width / 2), top: rect.top + window.scrollY + (rect.height / 2)
renverra la position médiane d'un élément
Si vous voulez que cela se fasse uniquement en javascript , voici quelques doublons utilisantgetBoundingClientRect()
window.scrollY + document.querySelector('#elementId').getBoundingClientRect().top // Y
window.scrollX + document.querySelector('#elementId').getBoundingClientRect().left // X
La première ligne renverra offsetTop
dire Y par rapport au document. La deuxième ligne renverra offsetLeft
disons X par rapport au document.
getBoundingClientRect()
est une fonction javascript qui renvoie la position de l'élément par rapport à la fenêtre d'affichage de la fenêtre.
Les éléments HTML de la plupart des navigateurs auront: -
offsetLeft
offsetTop
Ceux-ci spécifient la position de l'élément par rapport à son parent le plus proche qui a une disposition. Ce parent est souvent accessible via la propriété offsetParent.
IE et FF3 ont
clientLeft
clientTop
Ces propriétés sont moins courantes, elles spécifient une position des éléments avec sa zone cliente parents (la zone rembourrée fait partie de la zone cliente mais pas la bordure et la marge).
Si la page inclut - au moins - tout "DIV", la fonction donnée par meouw jette la valeur "Y" au-delà des limites de page actuelles. Afin de trouver la position exacte, vous devez gérer à la fois offsetParent et parentNode.
Essayez le code donné ci-dessous (il est vérifié pour 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];
};
Vous pouvez ajouter deux propriétés pour Element.prototype
obtenir le haut / gauche de n'importe quel élément.
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 );
}
} );
Cela s'appelle comme ceci:
var x = document.getElementById( 'myDiv' ).documentOffsetLeft;
Voici une démo comparant les résultats à ceux de jQuery offset().top
et .left
: http://jsfiddle.net/ThinkingStiff/3G7EZ/
Element.prototype
est généralement considérée comme une mauvaise idée . Cela rend le code très difficile à maintenir. De plus, ce code ne tient pas compte du défilement.
Pour récupérer efficacement la position par rapport à la page, et sans utiliser de fonction récursive: (inclut également 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;
Que diriez-vous de quelque chose comme ça, en passant l'ID de l'élément et il retournera la gauche ou le haut, nous pouvons également les combiner:
1) trouver à gauche
function findLeft(element) {
var rec = document.getElementById(element).getBoundingClientRect();
return rec.left + window.scrollX;
} //call it like findLeft('#header');
2) trouver le top
function findTop(element) {
var rec = document.getElementById(element).getBoundingClientRect();
return rec.top + window.scrollY;
} //call it like findTop('#header');
ou 3) trouver gauche et haut ensemble
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');
Vous pourriez être mieux servi en utilisant un framework JavaScript, qui a des fonctions pour renvoyer ces informations (et bien plus encore!) De manière indépendante du navigateur. Voici quelques-uns:
Avec ces cadres, vous pourriez faire quelque chose comme:
$('id-of-img').top
pour obtenir la coordonnée y-pixel de l'image.
jQuery .offset () obtiendra les coordonnées actuelles du premier élément, ou définira les coordonnées de chaque élément, dans l'ensemble des éléments correspondants, par rapport au document.
J'ai pris la réponse de @ meouw, ajouté dans le clientLeft qui permet la frontière, puis créé trois versions:
getAbsoluteOffsetFromBody - similaire à @ meouw, cela obtient la position absolue par rapport au corps ou à l'élément html du document (selon le mode excentrique)
getAbsoluteOffsetFromGivenElement - retourne la position absolue par rapport à l'élément donné (relativeEl). Notez que l'élément donné doit contenir l'élément el, sinon cela se comportera de la même manière que getAbsoluteOffsetFromBody. Cela est utile si vous avez deux éléments contenus dans un autre élément (connu) (éventuellement plusieurs nœuds dans l'arborescence des nœuds) et que vous souhaitez leur donner la même position.
getAbsoluteOffsetFromRelative - renvoie la position absolue par rapport au premier élément parent avec position: relative. Ceci est similaire à getAbsoluteOffsetFromGivenElement, pour la même raison, mais n'ira que jusqu'au premier élément correspondant.
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 vous rencontrez toujours des problèmes, en particulier en ce qui concerne le défilement, vous pouvez essayer de consulter http://www.greywyvern.com/?post=331 - J'ai remarqué au moins un morceau de code discutable dans getStyle qui devrait être correct en supposant que les navigateurs se comportent , mais je n'ai pas testé le reste du tout.
si vous utilisez jQuery, le plugin dimensions est excellent et vous permet de spécifier exactement ce que vous voulez.
par exemple
Position relative, position absolue, position absolue sans rembourrage, avec rembourrage ...
Cela continue, disons simplement qu'il y a beaucoup à faire.
De plus, l'avantage de jQuery est sa taille de fichier légère et son utilisation facile, vous ne reviendrez pas à JavaScript sans cela par la suite.
C'est le meilleur code que j'ai réussi à créer (fonctionne également dans les iframes, contrairement à l'offset () de jQuery). Il semble que le webkit ait un comportement légèrement différent.
D'après le commentaire 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 vous utilisez jQuery, cela pourrait être une solution simple:
<script>
var el = $("#element");
var position = el.position();
console.log( "left: " + position.left + ", top: " + position.top );
</script>
Différence entre petit et petit
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 };
}
Regardez un exemple de coordonnées: http://javascript.info/tutorial/coordinates
<svg>
éléments, par exemple, ne sont pas offsetLeft
, offsetTop
et les offsetParent
propriétés.
DIV
ou IMG
pas SVG
. Voir "Regardez un exemple de coordonnées"? vous pouvez trouver l'objet svg est l'appel de position getOffsetRect , essayez de dépendre du travail de l'objet.
L'approche la plus propre que j'ai trouvée est une version simplifiée de la technique utilisée par jQuery offset
. Semblable à certaines des autres réponses, il commence par getBoundingClientRect
; il utilise ensuite le window
et le documentElement
pour ajuster la position du défilement ainsi que des éléments comme la marge sur le body
(souvent la valeur par défaut).
var rect = el.getBoundingClientRect();
var docEl = document.documentElement;
var rectTop = rect.top + window.pageYOffset - docEl.clientTop;
var rectLeft = rect.left + window.pageXOffset - docEl.clientLeft;
Bien que cela soit très probablement perdu au bas de tant de réponses, les meilleures solutions ici ne fonctionnaient pas pour moi.
Pour autant que je sache, aucune des autres réponses n'aurait aidé.
Situation :
dans une page HTML5, j'avais un menu qui était un élément nav à l'intérieur d'un en-tête (pas l'en-tête mais un en-tête dans un autre élément).
Je voulais que la navigation reste en haut une fois qu'un utilisateur y avait fait défiler, mais avant cela, l'en-tête était positionné de manière absolue (donc je pouvais le superposer quelque chose d'autre).
Les solutions ci-dessus n'ont jamais déclenché de changement car .offsetTop n'allait pas changer car il s'agissait d'un élément positionné en absolu. De plus, la propriété .scrollTop était simplement le haut de l'élément le plus haut ... c'est-à-dire 0 et serait toujours 0.
Tous les tests que j'ai effectués en utilisant ces deux (et la même chose avec les résultats de getBoundingClientRect) ne me diraient pas si le haut de la barre de navigation a jamais défilé vers le haut de la page visible (encore une fois, comme indiqué dans la console, ils sont simplement restés les mêmes chiffres pendant le défilement eu lieu).
Solution
La solution pour moi était d'utiliser
window.visualViewport.pageTop
La valeur de la propriété pageTop reflète la section visible de l'écran, ce qui me permet donc de suivre où un élément se réfère aux limites de la zone visible.
Il est probablement inutile de le dire, chaque fois que je traite du défilement, je m'attends à utiliser cette solution pour répondre par programmation au mouvement des éléments défilés.
J'espère que cela aide quelqu'un d'autre.
REMARQUE IMPORTANTE: cela semble fonctionner dans Chrome et Opera actuellement et certainement pas dans Firefox (6-2018) ... jusqu'à ce que Firefox prenne en charge visualViewport, je recommande de NE PAS utiliser cette méthode, (et j'espère qu'ils le feront bientôt ... cela fait beaucoup plus de sens que les autres).
MISE À JOUR:
Juste une note concernant cette solution.
Bien que je trouve toujours ce que j'ai découvert très utile pour les situations dans lesquelles "... répondre par programmation au mouvement des éléments en cours de défilement". est applicable. La meilleure solution au problème que j'avais était d'utiliser CSS pour définir position: collantsur l'élément. En utilisant sticky, vous pouvez laisser un élément en haut sans utiliser javascript (REMARQUE: il y a des moments où cela ne fonctionnera pas aussi efficacement que de changer l'élément en fixe, mais pour la plupart des utilisations, l'approche collante sera probablement supérieure)
UPDATE01:
J'ai donc réalisé que pour une page différente, j'avais une exigence où je devais détecter la position d'un élément dans une configuration de défilement légèrement complexe (parallaxe plus éléments qui défilent dans le cadre d'un message). J'ai réalisé dans ce scénario que les éléments suivants fournissaient la valeur que j'utilisais pour déterminer quand faire quelque chose:
let bodyElement = document.getElementsByTagName('body')[0];
let elementToTrack = bodyElement.querySelector('.trackme');
trackedObjPos = elementToTrack.getBoundingClientRect().top;
if(trackedObjPos > 264)
{
bodyElement.style.cssText = '';
}
J'espère que cette réponse est plus largement utile maintenant.
Je l'ai fait comme ça, donc c'était compatible avec les anciens navigateurs.
// 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;
}
Plus d'informations sur les coordonnées en JavaScript ici: http://javascript.info/tutorial/coordinates
Pour obtenir le décalage total d'un élément, vous pouvez résumer récursivement tous les décalages parents:
function getParentOffsets(el): number {
if (el.offsetParent) {
return el.offsetParent.offsetTop + getParentOffset(el.offsetParent);
} else {
return 0;
}
}
avec cette fonction d'utilité, le décalage supérieur total d'un élément dom est:
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;
}
Merci ThinkingStiff pour la réponse , ce n'est qu'une autre version de celui-ci.
J'ai utilisé avec succès la solution d'Andy E pour positionner un modal bootstrap 2 en fonction du lien dans une ligne de tableau sur lequel un utilisateur clique. La page est une page Tapestry 5 et le javascript ci-dessous est importé dans la classe de page 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);
}
Mon code 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>
Le lien dans la boucle:
<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>
Et le code java dans la classe de page:
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');");
}
});
}
J'espère que cela aide quelqu'un, ce message a aidé.
Après de nombreuses recherches et tests, cela semble fonctionner
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 };
}
Je pensais juste que je jetterais ça aussi.
Je n'ai pas pu le tester dans les anciens navigateurs, mais cela fonctionne dans le dernier du top 3. :)
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()};
};
Étant donné que différents navigateurs affichent la bordure, le remplissage, la marge, etc. de manière différente. J'ai écrit une petite fonction pour récupérer les positions supérieure et gauche de l'élément spécifique dans chaque élément racine que vous souhaitez dans une dimension précise:
function getTop(root, offset) {
var rootRect = root.getBoundingClientRect();
var offsetRect = offset.getBoundingClientRect();
return offsetRect.top - rootRect.top;
}
Pour récupérer la position gauche, vous devez retourner:
return offsetRect.left - rootRect.left;
Obtenez la position de div par rapport à gauche et en haut
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
et el.offsetLeft
(l'OP ne dit rien sur jQuery ... Je ne sais pas pourquoi votre réponse utilise jQuery non plus ...)