jQuery offset().top returns wrong value - error with margin

55,573

Solution 1

Your question:

What is the solution for this problem?

I suggest you to position the .container to relative:

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

and within your script use .position().top, it will make your life easier:

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

.offset().top:
Description: Get the current coordinates of the first element in the set of matched elements, relative to the document..

.position().top:
From the docs:

Description: Get the current coordinates of the first element in the set of matched elements, relative to the offset parent.

.position().top is calculated from the top to the parent if parent is relatively positioned.

$(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>

Solution 2

You can also encounter this problem if some of your content is images. If you're calling .offset() inside document.ready(), the images may not have loaded yet. Try moving your .offset() call to window.load().

Share:
55,573
user3631654
Author by

user3631654

Updated on January 30, 2020

Comments

  • user3631654
    user3631654 over 4 years

    if you try to get a top offset from a list element within a parent, and that parent is not positioned at the top, you will get a wrong value.

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

    Try removing the margin-top on the .container element and you will see it will work.

    What is the solution for this problem?

  • user3631654
    user3631654 about 9 years
    best solution since this will not require to know where the animation element is nested in. In the other posted answers it is necessary to know if parent elements have margin or not.
  • evolutionxbox
    evolutionxbox about 9 years
    Relative positioning ftw!
  • NoBugs
    NoBugs over 8 years
    But won't generically subtracting the problematic element's position().top from your element's offset.top() also solve it?
  • r3wt
    r3wt about 8 years
    this answer will actually work without the parent having relative positioning.
  • Jake Wilson
    Jake Wilson over 4 years
    $element.offset().top is supposed to return the distance from the top of the document. How come in the original example here it's returning the distance from the top of the viewport??
  • Viet Nguyen
    Viet Nguyen about 4 years
    4 years answer still working today, you're saving my life
  • Chad Reitsma
    Chad Reitsma about 4 years
    This should be the correct answer. Using offset.top in document.ready() returns wacky results. I was getting numbers greater than my viewport, but using window.load() works!