web-dev-qa-db-fra.com

jQuery offset (). top renvoie une valeur incorrecte - erreur avec marge

si vous essayez d'obtenir un décalage supérieur à partir d'un élément de la liste dans un parent et que ce parent n'est pas placé en haut, vous obtiendrez une valeur erronée.

http://jsbin.com/yuxacuduna/1/edit?html,css,js,console,output

Essayez de supprimer le margin-top sur l'élément .container et vous verrez qu'il fonctionnera. 

Quelle est la solution à ce problème? 

11
user3631654

Ta question:

Quelle est la solution à ce problème?

Je vous suggère de positionner le .container à relative:

.container{
  margin-top:100px;
  background:yellow;
  height:600px;
  width:300px;
  overflow-y:auto;
  overflow-x:hidden;
  position:relative; /*<---add this*/
}

et dans votre script, utilisez .position().top, cela vous facilitera la vie:

$('.container li:nth-child(7)').css("background", "red");
$('.container').animate({
    scrollTop: $('.container li:nth-child(7)').position().top
});

.offset().top:
Description: Obtenir les coordonnées actuelles du premier élément de l'ensemble des éléments correspondants, relatives au document. 

.position().top:
À partir de la documentation: 

Description:Obtenir les coordonnées actuelles du premier élément de l'ensemble des éléments correspondants, par rapport au parent décalé. 

.position().top est calculé du haut vers le parent si parent est relativement positionné. 

$(function() {
  $('.container li:nth-child(7)').css("background", "red");
  $('.container').animate({
    scrollTop: $('.container li:nth-child(7)').position().top
  });
});
html,
body {
  margin: 0;
  padding: 0;
}
.container {
  margin-top: 100px;
  background: yellow;
  height: 600px;
  width: 300px;
  overflow-y: auto;
  overflow-x: hidden;
  position: relative;
}
.container ul {
  margin: 0;
  padding: 0;
  list-style: none outside none;
}
.container li {
  background: blue;
  display: block;
  height: 150px;
  width: 100%;
  padding: 10px;
  margin-bottom: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
  <ul>
    <li>asdasd</li>
    <li>asdasd</li>
    <li>asdasd</li>
    <li>asdasd</li>
    <li>asdasd</li>
    <li>asdasd</li>
    <li>asdasd77</li>
    <li>asdasd</li>
    <li>asdasd</li>
    <li>asdasd</li>
    <li>asdasd</li>
  </ul>
</div>

23
Jai

Vous pouvez également rencontrer ce problème si une partie de votre contenu est constituée d'images. Si vous appelez .offset () dans document.ready (), les images ne sont peut-être pas encore chargées. Essayez de déplacer votre appel .offset () vers window.load ().

3
Nate

Je pense que ça fonctionne correctement. Selon offset()documentation jQuery :

La méthode .offset () nous permet de récupérer la position actuelle d'un élément relatif au document

Donc, le problème que vous avez est que vous essayez de faire défiler la ul mais avec la valeur du scrollTop de l'élément dans le document, et non dans la liste. Pour résoudre ce problème, corrigez simplement la valeur en prenant en compte le scrollTop du parent (le ul):

$(function(){
    $('.container li:nth-child(7)').css("background", "red");
    $('.container').animate({
        scrollTop: $('.container li:nth-child(7)').offset().top - $(".container").offset().top
    });
});

Vous pouvez le voir travailler sur cette modification de votre JSBin: http://jsbin.com/fanixodiwi/1/edit?html,css,js,console,output }

0
Alvaro Montoro

J'ai eu le même problème. Toutes les solutions sur le Web ne fonctionnent pas pour moi.

Si vous utilisez margin pour séparer certains éléments sans bordure, utilisez plutôt un remplissage. La fonction offset () de jQuery comptera pour les rembourrages mais exclura les marges. Les numéros de position en offset () redeviendront corrects.

0
Eric Luo