33

I have an issue with scrollspy, recreated in this fiddle: http://jsfiddle.net/jNXvG/3/

As seen in the demo, the ScrollSpy plugin always keeps the last menu item selected no matter the scrolling position. I've read other questions and answers and tried different combinations of offset, etc., but none of them have helped. I can't figure out what's wrong.

I don't want to edit my template to include ugly html 'data' tags, so I am calling scrollspy() via JavaScript to activate the plugin.

The next step would be to remove the fixed content height and use 'affix' on the sidebar.

merv
  • 67,214
  • 13
  • 180
  • 245
koichirose
  • 1,815
  • 4
  • 22
  • 30

16 Answers16

36

I had the exact same problem and for me, adding height: 100% to the body element was the fix.

(stricly nothing else seemed to make it work)

Mehdi Benadda
  • 361
  • 3
  • 3
  • 1
    I suggest you post this *as a comment* – Barranka Apr 09 '13 at 00:02
  • 1
    Wow, this answer is exactly the opposite of Baris' answer. – markus Nov 05 '13 at 00:59
  • 1
    This worked for me as well. After hours of searching. – Mark Hustad Jun 22 '17 at 12:24
  • What worked for me is adding `min-height: 100vh` to the element containing the tags. I think it is because my content is dynamic and on page load there is not enough content for a scrollbar so it automatically chooses the last nav link as active. – EJC Jan 16 '20 at 22:41
35

You need to attach the ScrollSpy to the element that is going to trigger scroll events, rather than the menu that is going to reflect the scroll position:

$('#content').scrollspy();​

JSFiddle

merv
  • 67,214
  • 13
  • 180
  • 245
  • 1
    Seems like the documentation is misleading! This fixed my issue – Arch Jun 16 '13 at 01:13
  • @ShaunRowan yeah, the Fiddle only demonstrates the minimal change to the OP's Fiddle required to activate the ScrollSpy properly. However, I've at least updated the Fiddle link to go to the fullscreen Result view, rather than the Edit view, since I suspect much of your impression of "flaky"-ness has more to do with the narrow dimensions of the result frame in the Edit view. – merv Oct 18 '13 at 20:52
15

FYI: To get my desired effect (same one as on the Twitter Bootstrap docs page) I needed to set 'body' as my target element...I could not get scrollspy'ing to work by using the immediate parent of the elements I wanted to spy as the target.

(It just auto-selected the my last element always)

Andrew
  • 3,650
  • 9
  • 31
  • 32
  • I wonder why that is. The bootstrap example at http://twitter.github.com/bootstrap/javascript.html#scrollspy doesn't do that. – Joe Van Dyk Nov 29 '12 at 18:12
  • I've spent hours (at least 2) on searching a solution to this now. Finally a solution that worked for me. body height 100% or not, like other suggests, does not seem to make a difference to me. – Mattias Nordqvist Apr 21 '13 at 16:08
7

In my case, Firefox was always selecting the last element and it was NOT the

height:100%;

on the body that was causing the problem (as I didn't have anything like that).

It was a

position:absolute; 

on a container div.

Hope it helps someone out there...

gsaslis
  • 3,066
  • 2
  • 26
  • 32
7

I fixed it using body height 100% but it didnt work on Firefox. After wasting so much time found the answer on github page. Applying height 100% to HTML tag fixes the issue both for Chrome and Firefox.

https://github.com/twbs/bootstrap/issues/5007

Atif
  • 821
  • 2
  • 10
  • 15
6

When calling the scrollspy method you typically specify the body tag and the nav element.

<script>
        $(function() {
            $('body').scrollspy({ target: '#faq_sidebar' });
        });
</script>

The JavaScript above is equivalent to:

<body data-spy="scroll" data-target="#faq_sidebar">

The only situation where you do not specify the body tag is if you want to track an element with a nested scrollbar like in the JSFiddle above.

James Lawruk
  • 30,112
  • 19
  • 130
  • 137
  • Making sure the `data-spy` was in the `body` tag and not one of the `div`'s is what did it for me. – darda May 11 '14 at 23:52
5

If anyone else's issue wasn't solved by the suggestions above try adding <!DOCTYPE html> to the first line of your page. This was a simple step which solved the problem for me.

4

I had this same problem; removing the height: 100% from the <body> element fixed this for me.

Baris Wanschers
  • 160
  • 1
  • 8
2

I had a similar issue where scroll spy would not work on anything but a body tag so I actually went into the bootstrap js found the Scroll spy (SCROLLSPY CLASS DEFINITION) section and changed this line:

, $element = $(element).is('body') ? $(window) : $(element)

to this:

, $element = $(element).is('body') ? $(window) : $(window) //$(element)

(note that the element after the // is a comment so I don't forget I changed it)

And that fixed it for me.

1

ScrollSpy is pretty unforgiving and the documentation is sparse to say the least...there are different and conflicting fixes for this based on your implementation...

Nested content was my problem. This fixed it for me:

(1) make sure all hrefs in your nav match a corresponding ID in your spied upon target container.

(2) If the items in your spied upon content container are nested then it won't work...

This:

<ul class="nav" id="sidebar">
  <li>
     <a href="#navItem1" />
  </li>
  <li>
     <a href="#navItem2" />
  </li>
</ul>
<div id="spiedContent"> <!-- nested content -->
   <div id="navItem1">
      <div id="navItem2"></div>
   </div>    

</div>

To This:

<ul class="nav" id="sidebar">
  <li>
     <a href="#navItem1" />
  </li>
  <li>
     <a href="#navItem2" />
  </li>
</ul>
<div id="spiedContent"> <!-- flat content -->
   <div id="navItem1"></div>    
   <div id="navItem2"></div>
</div>

All good!

My guess if you looked at the scrollspy code its not looking past the first child of the spied container for the ids.

AgonyOfVictory
  • 164
  • 1
  • 4
0

Make sure you're not mixing implementations. You don't need $('#content).scrollspy() if you have data-spy="scroll" data-target=".bs-docs-sidebar" on your body tag.

Archonic
  • 5,207
  • 5
  • 39
  • 55
0

I think that this might be a bug in ScrollSpy.

I also had the same problem and when I stepped through the code I could see that the offset for all the targets were the same (-95px). I checked where these were being set and it was using the position() function. This returns the position of the element relative to the offset of the parent.

I changed this to use the offset() function instead. This function returns the position of the element relative to the offset of the page. Once I did this then it worked perfectly. Not sure why this isn't the default behaviour.

The reason that the position() function wasn't working in my case was because I had to have an empty div which was actually absolutely positioned 95px above the top of its container. I needed this as my target so that the headings weren't hidden behind my header that was fixed to the top of the page.

steinybot
  • 5,491
  • 6
  • 37
  • 55
0

When I was trying to figure out this issue, I used some of what Mehdi Benadda said and added position: relative; to the body. I added this to the stylesheet:

body {
  position: relative;
  height: 100%;
}

Hopefully this helps someone in the future.

Trevor Nestman
  • 2,456
  • 19
  • 26
0

You don't have to call method scrollspy(). Also you don't need set height: 100% anywhere.

All you need is:

  1. position: relative; for body
  2. add data-bs-spy="scroll" to your content or body
  3. add data-bs-target with navbar id

https://i.stack.imgur.com/U1xCl.png

It helps me.

Alemyk
  • 1
  • 1
0

It seems that scroll spy work only when used container has a scrollbar (Tested with bootstrap 5). You can put data-bs-spy="scroll" and data-bs-target="#target-nav" attributes in the nearest parent having a scrollbar.

Polla Toube
  • 178
  • 3
  • 10
0

In my case, i had added the scrollspy component of bootstrap version 5.2.3 but my bootstrap js cdn was 5.0. After i added the 5.2.3 js cdn, it worked!

You may also add the downladed bootstrap js files as well.

And make sure to add the bootstrap css cdn too!

Abhishek
  • 546
  • 5
  • 13