Comment obtenir la première position d'un élément par rapport à la fenêtre d'affichage du navigateur?


173

Je souhaite obtenir la position d'un élément par rapport à la fenêtre d'affichage du navigateur (la fenêtre d'affichage dans laquelle la page est affichée, pas la page entière). Comment cela peut-il être fait en JavaScript?

Merci beaucoup


2
Je pense que cette question est similaire à stackoverflow.com/questions/211703/ ... qui a une solution vraiment sympa.
Jakob Runge

1
@JakobRunge, c'était "sympa" en 2013?
Iulian Onofrei

1
Pensez à accepter une solution.
Iulian Onofrei

Réponses:


306

Les réponses existantes sont désormais dépassées. La getBoundingClientRect()méthode native existe depuis un certain temps maintenant et fait exactement ce que la question demande. De plus, il est pris en charge sur tous les navigateurs (y compris IE 5, semble-t-il!)

Depuis la page MDN :

La valeur renvoyée est un objet TextRectangle, qui contient des propriétés en lecture seule à gauche, en haut, à droite et en bas décrivant la zone de bordure, en pixels, avec le haut à gauche par rapport au haut à gauche de la fenêtre .

Vous l'utilisez comme ceci:

var viewportOffset = el.getBoundingClientRect();
// these are relative to the viewport, i.e. the window
var top = viewportOffset.top;
var left = viewportOffset.left;

3
Cela peut ne pas fonctionner correctement lorsque vous utilisez le zoom du navigateur (Android Chrome). La solution de @rism ( voir ci-dessous ) fonctionne dans ce cas
Dmitry

4
Bon pour la plupart des cas, mais cela suppose que l'élément ne se trouve pas dans une iframe intégrée, non? La question se pose sur la fenêtre relative du navigateur. El.getBoundingClientRect () retournera la fenêtre relative de l'iframe, pas la fenêtre du navigateur.
cakidnyc

6
La question se pose sur la fenêtre relative du navigateur.
Dmitry Dvornikov

2
@Denilson getBoundingClientRect().topn'est pas dans mon IE11, il renvoie 0. Avez-vous une solution.
Arif

@Arif: Désolé, mais je ne peux pas reproduire votre problème. J'ai testé cela sur IE11 et j'ai toujours obtenu des résultats: codepen.io/denilsonsa/pen/ypqyXj
Denilson Sá Maia

57

Dans mon cas, juste pour être sûr du défilement, j'ai ajouté le window.scroll à l'équation:

var element = document.getElementById('myElement');
var topPos = element.getBoundingClientRect().top + window.scrollY;
var leftPos = element.getBoundingClientRect().left + window.scrollX;

Cela me permet d'obtenir la position relative réelle de l'élément sur le document, même s'il a été défilé.


2
N'êtes-vous pas censé ajouter la position de défilement au lieu de la soustraire?
Iulian Onofrei

J'ai voté pour la réponse mais quand même, @lulian Onofrei a raison. Veuillez modifier.
pmrotule

@Fabio getBoundingClientRect().topn'est pas dans mon IE11, il renvoie 0. Avez-vous une solution.
Arif

1
@Arif window.scrollY || window.pageYOffsetpeut améliorer le support
Fabian von Ellerts

@FabianvonEllerts :)
Arif

15

Modifier: ajoutez un code pour tenir compte du défilement de la page.

function findPos(id) {
    var node = document.getElementById(id);     
    var curtop = 0;
    var curtopscroll = 0;
    if (node.offsetParent) {
        do {
            curtop += node.offsetTop;
            curtopscroll += node.offsetParent ? node.offsetParent.scrollTop : 0;
        } while (node = node.offsetParent);

        alert(curtop - curtopscroll);
    }
}

L'argument id est l'id de l'élément dont vous voulez le décalage. Adapté d'un article de quirksmode .


1
Merci pour votre réponse mais je pense que vous avez mal compris ma question, je sais comment obtenir le haut d'un élément par rapport à la page, ce que j'essaie de faire est d'obtenir la position par rapport à la 'fenêtre' (c'est-à-dire la fenêtre du navigateur , pas le document)
Waleed Eissa

Désolé, votre utilisation de «viewport» m'a jeté. Donc, vous dites que vous voulez prendre en compte le chrome du navigateur, c'est-à-dire la barre d'outils des signets, la barre d'emplacement, etc.?
Derek Swingley

Non, juste la fenêtre à travers laquelle vous voyez la page. Si la page est défilée, ce sera différent du haut du document, sinon ils sont identiques.
Waleed Eissa

Oh, OK, je comprends. Je ne sais pas comment faire cela ... modifiera ma réponse si je trouve quelque chose.
Derek Swingley

J'ai rendu le code ci-dessus un peu plus laid mais ça marche ... utilisez offsetParent.scrollTop
Derek Swingley

10
var element =  document.querySelector('selector');
var bodyRect = document.body.getBoundingClientRect(),
    elemRect = element.getBoundingClientRect(),
    offset   = elemRect.top - bodyRect.top;

Cela semble calculer à partir du haut du document, pas de la fenêtre d'affichage
Scott Leonard

6

Tu peux essayer:

node.offsetTop - window.scrollY

Il fonctionne sur Opera avec la balise meta viewport définie.


7
Si je comprends bien la documentation , offsetTopest relative à l'élément positionné le plus proche. Qui, selon la structure de la page, peut ou non être l'élément racine.
Denilson Sá Maia

5

jQuery l'implémente assez élégamment. Si vous regardez la source de jQuery offset, vous constaterez que c'est fondamentalement comment il est implémenté:

var rect = elem.getBoundingClientRect();
var win = elem.ownerDocument.defaultView;

return {
    top: rect.top + win.pageYOffset,
    left: rect.left + win.pageXOffset
};

2

La fonction de cette page renverra un rectangle avec les coordonnées en haut, à gauche, en hauteur et en largeur d'un élément passé par rapport au port d'affichage du navigateur.

    localToGlobal: function( _el ) {
       var target = _el,
       target_width = target.offsetWidth,
       target_height = target.offsetHeight,
       target_left = target.offsetLeft,
       target_top = target.offsetTop,
       gleft = 0,
       gtop = 0,
       rect = {};

       var moonwalk = function( _parent ) {
        if (!!_parent) {
            gleft += _parent.offsetLeft;
            gtop += _parent.offsetTop;
            moonwalk( _parent.offsetParent );
        } else {
            return rect = {
            top: target.offsetTop + gtop,
            left: target.offsetLeft + gleft,
            bottom: (target.offsetTop + gtop) + target_height,
            right: (target.offsetLeft + gleft) + target_width
            };
        }
    };
        moonwalk( target.offsetParent );
        return rect;
}

2
function inViewport(element) {
    let bounds = element.getBoundingClientRect();
    let viewWidth = document.documentElement.clientWidth;
    let viewHeight = document.documentElement.clientHeight;

    if (bounds['left'] < 0) return false;
    if (bounds['top'] < 0) return false;
    if (bounds['right'] > viewWidth) return false;
    if (bounds['bottom'] > viewHeight) return false;

    return true;
}

la source


1

Merci pour toutes les réponses. Il semble que Prototype a déjà une fonction qui fait cela (la fonction page ()). En visualisant le code source de la fonction, j'ai constaté qu'elle calcule d'abord la position de décalage de l'élément par rapport à la page (c'est-à-dire le haut du document), puis soustrait le scrollTop de cela. Voir le code source du prototype pour plus de détails.


Bonne décision. Il est probablement préférable d'utiliser l'une des principales bibliothèques, car elles sont plus susceptibles de donner le même résultat sur tous les navigateurs. Si vous êtes curieux, vérifiez ma réponse. Le code y fera cela mais je n'ai aucune idée de comment il tiendra dans les navigateurs.
Derek Swingley

1

Je suppose qu'un élément ayant un identifiant btn1existe dans la page Web, et aussi que jQuery est inclus. Cela a fonctionné sur tous les navigateurs modernes de Chrome, FireFox, IE> = 9 et Edge. jQuery n'est utilisé que pour déterminer la position par rapport au document.

var screenRelativeTop =  $("#btn1").offset().top - (window.scrollY || 
                                            window.pageYOffset || document.body.scrollTop);

var screenRelativeLeft =  $("#btn1").offset().left - (window.scrollX ||
                                           window.pageXOffset || document.body.scrollLeft);

1
jQuery est JavaScript. Je crois que vous vouliez dire "ce n'est pas 100% vanille / pur JS."
hungerstar

Oui, c'est ce que je voulais dire.
Sunil

1

Parfois getBoundingClientRect(), la valeur de la propriété de l'objet affiche 0 pour IE. Dans ce cas, vous devez définir display = 'block'l'élément. Vous pouvez utiliser le code ci-dessous pour tous les navigateurs pour obtenir un décalage.

Étendez la fonctionnalité jQuery:

(function($) {
    jQuery.fn.weOffset = function () {
        var de = document.documentElement;
        $(this).css("display", "block");
        var box = $(this).get(0).getBoundingClientRect();
        var top = box.top + window.pageYOffset - de.clientTop;
        var left = box.left + window.pageXOffset - de.clientLeft;
        return { top: top, left: left };
    };
}(jQuery));

Utilisation :

var elementOffset = $("#" + elementId).weOffset();
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.