web-dev-qa-db-fra.com

Récupérer la position (X, Y) d'un élément HTML

Je souhaite savoir comment obtenir la position X et Y d'éléments HTML tels que img et div en JavaScript.

1342
monaung

La bonne approche consiste à utiliser element.getBoundingClientRect() :

var rect = element.getBoundingClientRect();
console.log(rect.top, rect.right, rect.bottom, rect.left);

Internet Explorer supporte cela depuis aussi longtemps que vous vous en souciez et il a finalement été normalisé en 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 cela ne soit pas standard. Si vous êtes inquiet à propos de la compatibilité d'ancien navigateur, vérifiez les révisions de cette réponse pour une mise en œuvre optimisée et dégradante.

Les valeurs renvoyées par element.getBoundingClientRect() sont relatives à la fenêtre d'affichage. 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>');
1615
Andy E

Les bibliothèques s’efforcent d’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; 
300
meouw

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
203
Adam Grant

Les éléments HTML sur la plupart des navigateurs auront: -

offsetLeft
offsetTop

Celles-ci spécifient la position de l'élément par rapport à son parent le plus proche qui possède une disposition. Ce parent est souvent accessible via la propriété offsetParent.

IE et FF3 ont

clientLeft
clientTop

Ces propriétés sont moins communes, elles spécifient une position d'éléments avec la zone cliente de son parent (la zone matelassée fait partie de la zone client mais la bordure et la marge ne le sont pas).

39
AnthonyWJones

Si la page inclut - au moins - un "DIV", la fonction donnée par meouw jette la valeur "Y" au-delà des limites de la page en cours. Afin de trouver la position exacte, vous devez gérer à la fois les propriétés 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];
};

35
Refik Ayata

Vous pouvez ajouter deux propriétés à Element.prototype pour obtenir le haut/gauche de tout é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 );
    }
} );

Ceci s'appelle comme ceci:

var x = document.getElementById( 'myDiv' ).documentOffsetLeft;

Voici une démo comparant les résultats à offset().top et .left de jQuery: http://jsfiddle.net/ThinkingStiff/3G7EZ/

34
ThinkingStiff

Si vous voulez le faire uniquement en javascript , voici quelques one liners en utilisant getBoundingClientRect()

window.scrollX + document.querySelector('#elementId').getBoundingClientRect().left // X

window.scrollY + document.querySelector('#elementId').getBoundingClientRect().top // Y

La première ligne retournera offsetLeft dire X par rapport au document.

La deuxième ligne retournera offsetTop dire Y 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.

34
Asif J

Pour récupérer efficacement la position par rapport à la page, sans utiliser de fonction récursive: (inclut IE également)

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;
21
Abdul Rahim Haddad

Que diriez-vous de quelque chose comme ceci, en passant l'ID de l'élément qui retournera à gauche ou en haut, nous pouvons aussi 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 en haut

function findTop(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return rec.top + window.scrollY;
} //call it like findTop('#header');

ou ) trouve la gauche et le 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');
19
Alireza

Vous pourriez être mieux servi en utilisant un framework JavaScript, qui dispose de fonctions pour renvoyer de telles informations (et bien plus encore!) De manière indépendante du navigateur. Voici quelques-uns:

Avec ces frameworks, vous pouvez faire quelque chose comme: $('id-of-img').top pour obtenir la coordonnée y-pixel de l'image.

16
Shalom Craimer

jQuery . offset () va obtenir les coordonnées actuelles du premier élément, ou définir les coordonnées de chaque élément, dans l'ensemble des éléments correspondants, par rapport au document.

14
akauppi

J'ai pris la réponse de @ meouw, ajoutée dans le clientLeft qui permet la bordure, 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 quirks)

getAbsoluteOffsetFromGivenElement - renvoie 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 façon 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) et que vous souhaitez les placer à la même position.

getAbsoluteOffsetFromRelative - retourne 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 regarder http://www.greywyvern.com/?post=331 - J'ai remarqué au moins un morceau de code douteux dans getStyle. ce qui devrait bien se passer si les navigateurs se comportent, mais n'ont pas testé le reste du tout.

10

si vous utilisez jQuery, le dimensions plugin 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 que vous pouvez faire beaucoup avec cela.

De plus, jQuery a l'avantage d'être léger et facile à utiliser. Vous ne pourrez pas revenir à JavaScript sans cela par la suite.

8
John_

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>
7
Adam Boostani

C'est le meilleur code que j'ai réussi à créer (fonctionne également dans les iframes, contrairement à offset () de jQuery). Semble webkit a un comportement légèrement différent.

Basé sur 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 };
}
7
Ron Reiter

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

7
KingRider

L'approche la plus propre que j'ai trouvée est une version simplifiée de la technique utilisée par offset de jQuery. Semblable à certaines des autres réponses, il commence par getBoundingClientRect; il utilise ensuite la window et la documentElement pour ajuster la position de défilement, ainsi que des éléments tels que la marge sur la 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;
var els = document.getElementsByTagName("div");
var docEl = document.documentElement;

for (var i = 0; i < els.length; i++) {

  var rect = els[i].getBoundingClientRect();

  var rectTop = rect.top + window.pageYOffset - docEl.clientTop;
  var rectLeft = rect.left + window.pageXOffset - docEl.clientLeft;

  els[i].innerHTML = "<b>" + rectLeft + ", " + rectTop + "</b>";
}
div {
  width: 100px;
  height: 100px;
  background-color: red;
  border: 1px solid black;
}
#rel {
  position: relative;
  left: 10px;
  top: 10px;
}
#abs {
  position: absolute;
  top: 250px;
  left: 250px;
}
<div id="rel"></div>
<div id="abs"></div>
<div></div>
6
James Montagne

Je l'ai fait comme ça, il était donc 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

5
Bojan Kseneman

Bien que cela risque fort d'être perdu au bas de tant de réponses, les meilleures solutions ici ne fonctionnaient pas pour moi.
Autant que je sache, aucune des autres réponses n’aurait été utile.

Situation:
Dans une page HTML5, j'avais un menu qui était un élément de navigation dans un en-tête (pas THE en-tête mais un en-tête dans un autre élément).
Je voulais que la navigation reste en haut une fois que l'utilisateur y a fait défiler, mais auparavant, l'en-tête était positionné de manière absolue (afin que je puisse le superposer légèrement à autre chose).
Les solutions ci-dessus n'ont jamais provoqué de changement, car .offsetTop n'allait pas changer car il s'agissait d'un élément de positionnement absolu. De plus, la propriété .scrollTop était tout simplement le haut de l'élément le plus haut ... c'est-à-dire 0 et serait toujours 0.
Les tests que j'ai effectués en utilisant ces deux résultats (et les mêmes avec les résultats de getBoundingClientRect) ne me disaient pas si le haut de la barre de navigation était jamais passé en haut de la page visible (encore une fois, comme indiqué dans la console, ils restaient tout simplement les mêmes numéros lors du défilement se sont produits).

Solution
La solution pour moi consistait à 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 savoir où se trouve un élément par rapport aux limites de la zone visible.

Probablement inutile de dire, chaque fois que je traite du défilement, je compte utiliser cette solution pour répondre par programme au déplacement d'éléments défilant.
J'espère que ça aidera quelqu'un d'autre.
NOTE 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 ... c'est beaucoup plus logique que les autres).


UPDATE:
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épond par programme au mouvement des éléments défilant". est applicable. La meilleure solution au problème que j’avais était d’utiliser CSS pour définir position: sticky sur l’élément. En utilisant sticky, vous pouvez laisser un élément rester au sommet sans utiliser javascript (REMARQUE: il se peut que cela ne fonctionne pas aussi efficacement que de changer l'élément en élément fixe, mais que, dans la plupart des cas, l'approche sticky sera probablement supérieure).

UPDATE01:
Je me suis donc rendu compte que pour une page différente, j'avais une exigence selon laquelle je devais détecter la position d'un élément dans une configuration de défilement peu complexe (parallaxe plus éléments qui défilaient dans le cadre d'un message). J'ai réalisé dans ce scénario que ce qui suit fournissait la valeur que j'ai utilisée 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.

4
MER

J'ai utilisé avec succès la solution d'Andy E pour positionner un modal bootstrap 2 en fonction du lien dans lequel l'utilisateur clique dans une ligne du tableau. La page est une page Tapestry 5 et le javascript ci-dessous est importé dans la classe de pages 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é.

2
Mark Espinoza

Pour obtenir le décalage total d'un élément, vous pouvez récapituler de manière récursive tous les décalages parent:

function getParentOffsets(el): number {
if (el.offsetParent) {
    return el.offsetParent.offsetTop + getParentOffset(el.offsetParent);
} else {
    return 0;
}
}

avec cette fonction d’utilité, l’offset total d’un élément dom est égal à:

el.offsetTop + getParentOffsets(el);
2
Kevin K.

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

voir http://jsbin.com/xuvovalifo/edit?html,js,output

1
kernowcode

Je pensais juste que je lancerais ça aussi.
Je n'ai pas été en mesure de le tester dans les anciens navigateurs, mais cela fonctionne dans le dernier des 3 premiers. :)

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()};
};
1
Duncan

Obtenir 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 
0
Vishal

Étant donné que différents navigateurs rendent 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 d'un élément spécifique dans chaque élément racine souhaité 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;
0
samadadi
/**
 *
 * @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 , ceci n'est qu'une autre version de celui-ci.

0
Văn Quyết