17Slow scrolling


Slow scrolling with a link

Slow scrolling is easy; we need four things, the first three of which are in the HTML:

  • An ID on the target element we want to scroll to

  • A link (anchor element)

  • A class in the link that references the ID

  • Some jQuery to join it all together

We’ve actually covered everything here in other sections, usually with the caveat that I’ll explain the slow scrolling later (well, here it is).

To explain this, I’m going to use a simple link to a point on the same page; I’ll use the exact example from the introduction, the link and soft scroll to figure 99.1 on the 99-00-typicals.html page of the website template.

This is the completion of what we started in § 13.4, in fact it is exactly the same link. Let’s look at what we have in the HTML:

<p class="hyp">Internal links to a point on the same page use the class <span class="code">xref</span>; this is less noticeable on the page: 
<a class="xref js--sc-f99-01" href="#">Figure 99.1</a>.</p> ... <figure class="fig-row">                    <!-- Start of figure -->     <div class="fig-col fig1-1" id="js--f99-01"> <img src="01-pages/99-00-typicals/02-images/fig-99-01.png" alt="Figure 99.1 - Full width image">         <figcaption>Figure 99.1 &emsp; Full width figure</figcaption> <!-- Caption -->     </div> </figure>
Code 17.1   Link to figure 99.1

Let’s look at figure 99.1 first, this is just a standard full width image, in fact it is exactly the same full width image we created in § 15.1.1, this is it:

Figure 17.2 - Figure 99.1 from the templates page
Figure 17.2   Figure 99.1 from the templates page

The figure has been given the unique ID (id="js--f99-01"), I’ve shown it underlined in dark blue and bold in the listing above (Code 17.1). This is the standard form for the ID of a figure; see Table 13.1.

All well and good, it is a unique ID for the figure in question.

Next let’s look at the link in the listing, I’ve shown it underlined in dark red and bold in Code 17.1:

<a class=" xref js--sc-f99-01" href="#">Figure 99.1</a>

The anchor for the link <a> has two classes, the first is the xref styling class that determines the appearance of the link (see § 13.4). The second is the peculiar class:


I first introduced this class in § 13.4; it is needed to make the soft scroll work; it matches the given ID of the object we want to soft scroll to.

This class has the same name as the target ID except that the js-- of the ID is replaced with js--sc-, i.e. there is an extra sc- after the --.

The names of these IDs and corresponding classes, the js-- and js--sc- look kind of official, as if they have a particular meaning to the JavaScript, but they don’t, they are a complete product of my imagination. You could use anything, hector and henry will work just as well.

In my mind, js was intended to indicate that it was applicable to the JavaScript, the double dashes -- allowed me to search for it easily and the sc is my abbreviation for scroll.

I’m sorry if you thought I was doing something clever — you should know by now that I hardly do anything clever and when I do it’s usually by accident.

To summarise:

  • The target (the thing we want to scroll to) has the ID:

  • The link (to the object) has the class js--sc-f99-01 i.e. exactly the same as the ID but with js--sc- instead of js--

Both the ID (js--f99-01) and the class (js--sc-f99-01) are missing from any CSS file (there isn’t actually a class js--sc-f99-01 in style.css), these are purely for use in a JavaScript file, specifically the scroll.js file for the web page.


The soft scroll jQuery

This is the clever stuff.

The soft scrolling is different for each web page, each web page has different sections, tables, figures &c. and no two are the same. Thus the soft scrolling goes in the .js file for the web page in particular; specifically it is the c-ss-scroll.js file. Even more specifically, in this case it is:


This is the scroll.js†1 file for the web page 99-00-typicals.html.

That is why it’s called scroll; it has all the slow scroll jQuery stuff in it.

†1 Generally, when I refer to the scroll.js file, I’m referring to the cc-ss-scroll.js file for the particular web page in question.

At the moment, this file just has the jQuery container for our code:

$(document).ready(function() {                  /* START OF PAGE READY FUNCTION */

/* ****************************************************************************
   **************************************************************************** */

});                                             /* END OF PAGE READY FUNCTION */
Code 17.2   99-00-scroll.js

Let’s add the slow scroll stuff we need for this particular link:

$(document).ready(function() {                  /* START OF PAGE READY FUNCTION */

    $('.js--sc-f99-01').click(function () {     /* START of scroll function */
       $('html, body').animate({scrollTop: $('#js--f99-01').offset().top -80}, 1000);

});                                             /* END OF PAGE READY FUNCTION */
Code 17.3   99-00-scroll.js with slow scroll code

I know what you’re thinking, you’re thinking “that’s a shitload of brackets” and you’re right, I count 14 brackets and four braces — for just three lines of code? I refer you to my earlier comment.

You’re probably also thinking “that doesn’t look like the stuff we did before, it looks complicated” — you’re less right this time, it does looks complicated (Linux people†2 . I blame you), but it sort of isn’t, you get used to it.

†2 Q. How do you tell an extroverted Linux person from an introverted one?
A. The extravert looks at your shoes when you talk to him.
And for C programmers:
99 definite bugs in the code
99 definite bugs
You fix one bug and you re-compile
100 definite bugs in the code.

Let’s look at this in terms of the jQuery syntax:


What we have here is just this, except that in the action, we create a function that has another jQuery in it.

Think of it like this (I’ve simplified the brackets):


If selctor1 is true, THEN we test another condition (selector2) and if that is true, carryout action2. If selector1 was false, we don’t do anything.

The only other thing we have to do concerns the second line; we need to put in another function (another anonymous function).

Let’s go through it. The first line:

    $('.js--sc-f99-01').click(function () {

The first bit (the selector) is looking for the class js--sc-f99-01 that we used in the link (<a class="xref js--sc-f99-01"...>).

In short, $('.js--sc-f99-01').click() is waiting for something with the class js--sc-f99-01 to be clicked. In our case, the link to figure 99.1 has that class because we gave it that class in the HTML:

<p class="hyp">Internal links to a point on the same page use the class <span class="code">xref</span>; this is less noticeable on the page: 
<a class="xref js--sc-f99-01" href="#">Figure 99.1</a>.</p>

It applies to everything inside the link (i.e. the Figure 99.1 that displays on the web page), if we click anywhere in the link, the jQuery $('.js--sc-f99-01').click() will be true and everything in the brackets of the .click action will execute.

What’s in those brackets is: function () {  so what does this mean?

It means that if the class has been clicked (i.e. the link has been clicked), I create another anonymous function that has no parameters (the empty brackets) and executes it.

When it is executed it runs all the code between the braces {}.

In this case, it executes the following:

$('html, body').animate({scrollTop: $('#js--f99-01').offset().top -80}, 1000);

This is another jQuery, $(selector) &c. This is also a standard bit of code for the scrollTop method, you see it everywhere.

This time the selector is $('html, body')†3 it is selecting anything that is within the html element or the body element, this essentially is everything on the web page, so this selector is always true. The .animate() performs some sort of animation, in this case it is the scrollTop animation.

†1 You may be wondering why I use both html and body in the selector, the body element is after all within the html element. The reason is for browser consistency (and this is a fairly standard method for overcoming it), some browsers (Firefox and Internet Explorer) need this to be html, some (Chrome, Safari and Edge) need it to be body. Using both satisfies everyone.

The syntax for the animate method is:

.animate({property}, duration)

The duration is in milliseconds

The property is scrollTop and its syntax is:

scrollTop: $(target).offset().top nn

Where nn is the number of pixels below the top of the screen where the scroll will position the target.

Nearly there.

The scrollTop property is the thing that actually does the scrolling, it will scroll to the target, in this case the target is the ID of the object: $('#js--f99-01'), it is the bit between the quotes and it is the CSS class or ID, if it were a class, the # would be replace with a ., just like it is in CSS.

  • I tend to use single quotes in jQuery, but double quotes work in just the same way; i.e. $("#js--f99-01"). JavaScript and jQuery don’t care which you use, just be consistent, it doesn’t like it if you start with one and finish with the other, for example $("#js--f99-01') won’t work (double quote at the start, single quote at the end).

The offset().top is entirely optional, if you miss it out or set the offset to zero, the top of the target will be positioned exactly at the top of the browser window:

Figure 17.3 - ScrollTop with zero offset
Figure 17.3   ScrollTop with zero offset

The offset moves the stop point, if the number is positive it is further down the page, the following is an example with an offset of 100 (pixels, offset is always in pixels) offset().top +100.

  • For positive offsets, you have to use the plus sign (+), it doesn’t work if you just give it a number.
Figure 17.4 - ScrollTop with positive offset
Figure 17.4   ScrollTop with positive offset

It chops the top off the image.

Generally, we want negative offsets to leave a bit of a gap between the target and the top of the browser. This is an offset of -20: offset().top -20:

Figure 17.5 - ScrollTop with negative offset
Figure 17.5   ScrollTop with negative offset

Now in practice, there will be the sticky navigation bar (next chapter) at the top of the browser, and that has maximum height of 60 px; to make the slow scroll stop before the sticky navigation bar, we need to increase the gap by 60 pixels.

I tend to use an offset of -80 pixels for figures: offset().top -80.

With the sticky nav it looks like this:

Figure 17.6 - ScrollTop with negative offset and sticky navigation bar
Figure 17.6   ScrollTop with negative offset and sticky navigation bar

Tables and code fragments have different offsets (-60 for tables and -120 for code fragments), this is because these objects have different top margins. Sections, subsections and inline sections also have different offsets; the summary at the end gives examples of each (Table 17.1).

The final thing is the duration; this is the 1000 in the second line:

       $('html, body').animate({scrollTop: $('#js--f99-01').offset().top -80}, 1000);

This is the duration of the animation, i.e. how long it takes the browser to scroll for where it is to the target. This value is in milliseconds (one thousandth of a second) so a value of 1000 is equivalent to a duration of one second.

It is actually part of the animate method, not the scrollTop.

End flourish image