FF2+ IE8+ Opr8+

DD ScrollSpy Menu v1.2

Author: Dynamic Drive

July 30th, 14: Updated to v1.2, which supports  showing a progress bar inside each menu item (except in iOS devices). Other minor improvements.

Description: For long pages with lots of content, keeping the user oriented and knowing where within the page he/she is at all times can be challenging. DD ScrollSpy Menu solves this problem, by letting you create a menu whose menu items are automatically highlighted based on the portion of the page the user is currently viewing. As the user scrolls the page, the menu item that points to that section is highlighted (via the injection of a desired CSS class to style it). The script also works on scrollable DIVs within the page to spy on their scroll positions instead. Starting in v1.2, you can now also enable a progress bar to be shown inside each spymenu's menu item to show a progress of how much the user has scrolled within the currently viewed section.

DD ScrollSpy "spies" on the visitor's position on the page, but for their benefit (and in turn yours)!

Demos: (Look at the top fixed menu above, plus the side menu below)

Click to dynamically add another menu item

Paragraph 1

Paragraph 2

Paragraph 3

Paragraph 4

Paragraph 5

Directions Developer's View

Step 1: This script uses the following external files. Download them below (right click, and select "Save As"):

Step 2: Add the below code to the HEAD section of your page:

Select All

Step 2: Then, add the below sample markup to your page:

Select All

DD ScrollSpy Menu set up

To set up a DD ScrollSpy Menu, call the jQuery function ddscrollSpy() on the menu that will act as the spy menu:

jQuery(function($){ // on document load

Where "menuselector" is a valid jQuery selector referencing the desired menu on the page (ie: $("#horizontalmenu").ddscrollspy()), and options is a list of options for this DD ScrollSpy Menu instance. The menu typically would be a fixed menu, with menu items pointing to various sections within the page:

<ul id="horizontalmenu" class="underlinemenu">
<li><a href="#description">Description</a></li>
<li><a href="#demos">Demos</a></li>
<li><a href="#directions">Directions</a></li>
<li><a href="#setup">Set Up</a></li>
<li><a href="#section5">Section 5</a></li>

As you can see, it's just a regular menu with its menu items pointing to the IDs of the sections of the page they corresponds to (prefixed by "#").

To segment each portion of the page to correspond with the menu items above, just wrap each content in a DIV tag with a matching ID attribute, such as:

Recommended way to segment your content <div id="description">
This is some content...

<div id="demos">
This is some content...

<div id="directions">
This is some content...

<div id="setup">
This is some content...

It's important to wrap each content entirely using such a DIV tag if you want the calculations to be accurate as far as which content the script considers to be currently visible on the screen. The less desirable alternative is to just define HTML anchors on the page to indicate the start of each content, though the calculations will be imprecise with such a set up:

Less than ideal way to segment your content <a id="description"></a> This is some content...

<a id="demos" data-range="400"></a> This is some content...

<a id="directions"></a> This is some content...

<a id="setup"></a> This is some content...

In the less desirable set up above, notice the custom attribute "data-range". You can make use of this attribute to manually tell the script how tall the content in question is when segmenting your content using HTML anchors that do NOT wrap around the entire content in question. It's still not ideal, as apart from the extra work needed to estimate how tall the content is manually, depending on whether your page is fluid, resizing the page may alter the content's height.

$(menuselector).ddscrollspy() options

As mentioned in the first step to setting up a DD ScrollSpy Menu, you should call ddscrollSpy() in the HEAD section of your page to initialize the menu. The following lists the options you can pass into this function, all of which are optional:

option Description

defaults to window

The DOM object DD Scrollspy should monitor for scroll behaviour. Defaults to the window object, which is the desired setting in most cases when you're updating a menu based on the scroll position of the document itself.

If you wish to monitor the scroll position of a scrollable DIV (and the contents within it)  instead of the page itself, set spytarget to reference this DIV instead, such as:

 spytarget: document.getElementById('scrolldiv')

scrolltopoffset: integer

defaults to 0

Sets an offset from the top of each content within spytarget the script should include when calculating whether that content is currently visible on the screen. By default, a piece of content is considered visible when its top corner or below is showing inside the viewable area of the browser. You can decrease or increase that threshold by defining a negative/ positive integer (pixel unit assumed) to scrolltopoffset.

The value of this option will also be included when scrolling to each piece of content via clicking on the corresponding menu. If your spy menu is a fixed menu located at the very top of the page that never scrolls, setting scrolltopoffset to - (negative) height of the menu so the top portion of each content does not get obscured when the script scrolls to it:

 spytarget: document.getElementById('test'),
 scrolltopoffset: -50 // if spy menu is a fixed top menu, set this to -height of menu so it doesn't obscure content

enableprogress: "string"

defaults to ""

v1.2 option. Not supported in iOS devices.

Enables a progress bar that's shown inside the target spy menu's <A> elements to display a live status of how much of the corresponding content has been scrolled. Set "enableprogress" to an arbitrary CSS class to enable the feature, such as to "progress", whereas an empty string ("") disables it.

When "enableprogress" is set to a CSS class string, the script will dynamically insert a DIV with that class inside the spy menu's A elements to act as the progress bar. You can style the progress bar inside your CSS by referencing said CSS class name. By default inside ddscrollspydemo.css, it comes with the following style for the progress bar with name "progress":

a div.progress{ /* style for progress element that gets added to each A element of a spy menu when the "enableprogress" option is enabled and set to "progress" */
background: #E5E5E5;
position: absolute;
height: 100%;
width: 100%;
top: 0;
left: 0;
z-index: -1;

The script dynamically modifies the progress bar's left property to show a percentage of it inside each spy menu link.

When you turn on "enableprogress", you should make sure your spy menu links carry either a CSS style of "display: block" or "display:inline-block" so that they can properly house the progress bar element inside of them. See "Creating a sticky vertical scrollspy menu with progress bar" for more info on using this option.

scrollbehavior: "jump | smooth"

defaults to "smooth"

Sets the scroll behaviour when navigating to each piece of monitored content via clicking on the menu. Set to jump to hop straight to the associated content without any scroll animation.

Important: In IE9 and below, the scrollbehavior will always be set to "jump" if the spytarget option is set to window even when you've set to "smooth". This is due to the scrolling animation conflicting with the preservation of the browser's location hash in said browsers (specifically, ones that don't support HTMl5's pushstate function).

scrollduration: integer

defaults to 500

If scrollbehavior above is set to "smooth" (default setting), this option sets the duration of the scroll animation (in milliseconds).
highlightclass: "string"

defaults to "selected"

Sets the CSS class that gets added to the menu item corresponding to the content currently visible on the page. Defaults to "selected", which you should style in your CSS.
trigger('updatespy') Performs a re-initialization of the target menu for any content referenced by the menu to spy on. Useful if you've dynamically added menu items to the target menu pointing to new content, or have made changes to the page in general that affect the dimensions or scroll positions of the existing spied on contents. More info below.

That's it- the "JavaScript" item will be selected automatically when the menu is initialized.

Dynamically adding a menu item to a ScrollSpy Menu

You can dynamically add menu items to your Spy Menu to spy on additional content on the page even after the page has loaded. Adding a menu item itself just involves using standard DOM or jQuery methods to augment the menu's markup, such as:

$('#verticalspymenu').append('<li><a href="#para5">Paragraph 5</a></li>')

The above jQuery code when run adds a new LI element to the menu with ID="verticalspymenu". That's all good and dandy, but after that you also need to reinitialize the spy menu so it knows of the presence of this newly added menu item and the content it points to (in this case, the DIV with ID="para5"). To do this, just call trigger("updatespy") on the spy menu:


Call this method on a spy menu whenever you've added new menu items to it, or if the contents the menu is spying on may have shifted position on the page (such as after the injection of other content onto the page, pushing everything else up or down). This method basically causes a re-scan and re-calculation of everything related to that spy menu.

Table Of Contents

Wordpress Users: Step by Step instructions to add ANY Dynamic Drive script to an entire Wordpress theme or individual Post