Last Updated:

Smooth page scrolling in JavaScript

Intro.

Many selling landing pages use smooth page scrolling to a certain thematic block, so the topic of smooth scrolling has been repeatedly considered in many articles posted on sites or blogs devoted to Programming in JavaScript. Various solutions were offered, both in pure JavaScript and using jQuery. Most of them use (anchors) and links pointing to them, which causes a lot of controversy in the comments about the feasibility of such a method from the point of view of THE CEO. There are options in which the connection between the navigation element and the block to which you want to screw the page is carried out through . This method is more interesting, but it is not without drawbacks.anchorID

In my article, I suggest considering a variant of a JS script that will not use either an anchor or an ID. The identification of the containers that you want to scroll to the top of the screen will be based on the index of the item in the collection. This will greatly simplify both HTML layout and JS code, but at the same time, their flexibility will be preserved and it will be easier to add new containers.

HTML markup for smooth page scrolling.

The header of the page in which the menu with scroll control elements will be placed will have the property . This positioning will allow the header to be constantly at the top of the screen, which will provide access to navigation elements.display: fixed

The menu is based on an unlabeled list , and the controls will be . Using as an interactive element eliminates another fairly common mistake - the use of a tag (link) for these purposes.<ul><span><span><a>

Remember, this is very important.
Both from the point of view of semantics and from the point of view of SEO – the tag should be used only to form links leading to other pages of the site or other Internet resource. To control the elements of the current page (show/hide, change style, move, load, etc.), the elements of , , , . It is on them that the event handlers are hung. <a><span><button><div><li>

HTML markup source code:

As you can see from the HTML layout, I didn't use anchors, links to them, or identifiers.

A style sheet for smoothly scrolling through the page.

A small style sheet that defines the appearance of the header, menu, and content containers themselves:

JavaScript to control the smooth scrolling of the page.

To limit the scope, let's place the script in an anonymous self-starting function.

Remember, this is very important.
When creating an animation in JavaScript, use the . This feature allows you to synchronize animations with the browser's built-in page refresh mechanisms. The result will be a more efficient use of the graphics accelerator, re-processing of the same sections of the page will be excluded, there will be less CPU usage and, most importantly, the animation will be smoother, without jerks and twitches. setIntervalrequestAnimationFrame

Based on the above, the first thing we need to do is to create the possibility of cross-browser use of the function . Let's add the following code inside the generated anonymous function:requestAnimationFrame

Now we need to get a number of objects and collections of elements on the basis of which our JavaScrit will work:

  1. Object — for delegation based on the pop-up of events;menu
  2. Object collection — interactive elements that trigger page scrolling;SPAN
  3. Object collection - Containers to which the page scrolls.DIV

Now we need to hang the event handler on the . When the event is triggered (a click was made on the menu) and using delegation based on the pop-up of events, we determine that the click occurred on the element, and not on the empty menu area. After that, run two functions in turn: and .clickmenuspanswitchLinksselectContainer

Consider the function responsible for highlighting the menu item on which the click is made. It also returns the index() of the item in the . You will need this index to identify the container to which the page will scroll.
The argument to the function is the object of the element on which the click was made. In addition to the resulting argument, the function uses the object collection . This collection is not explicitly passed to the function as an argument because it is global within the scope of the self-starting anonymous function.switchLinkscurrentitemsspanswitchLinksitems

Now let's look at the JS code of the . This function finds a container from the collection using the index argument of the active menu item and starts an animated scrolling of the page by calling the .selectContainercontainerscurrentscroll

It remains to consider the work of the main function of our script - , which provides a smooth scrolling of the page to the selected container, taking into account the direction of scrolling.scroll

The function takes two arguments:
1. is the object of the element to which the page will scroll;
2. - the coefficient that determines the up or down you need to scroll the page.containerDIVdirection

Now in detail, step by step, we will understand how the animation of scrolling the page will work.

  • 1

    Before you start an animation, you must assign several variables and assign them values:
    — , duration of the animation;
    - , the start time of the animation;durationstart

  • 2

    Inside the function, let's create a named function that will call itself recursively until the animation runs out. Inside this function, let's declare and assign values to three more variables:
    — , the current position of the upper border of the container, taking into account the height of the header from the menu;
    — , the elapsed time since the beginning of the page scroll animation;
    — , the amount of page scrolling in one cycle of the function .scrollfntopnowresultfn

    where, is the height of the cap.96

  • 3

    In order for the container not to slip through the lower border of the header when scrolling the page, it is necessary to adjust the value depending on the current position of the upper border of the container. To do this, let's add a few conditions:result

  • 4

    Compare the product c . If the product is greater than zero, then scroll through the page by a size and recursively run the function for the next cycle.direction * top0resultfn

    When scrolling down the page, the values are positive, when scrolling up, the values are negative, so the result of multiplication is always positive.directiontop

    The method scrolls the page relative to the current coordinates, respectively, scrolls the page at the 'Y' coordinate by the result value.scrollBy(x,y)window.scrollBy(0,result)

  • 5

    To start the animation, you need to place the code at the end of the function that originally calls the function.scrollfn

Now let's put it all together and see what the function looks like in its entirety:scroll

It seems that the problem is solved, but... If the last block has a height less than the height of the screen, as in our example, then its upper boundary will not physically be able to reach the header, in other words, the condition

will always be true and our script will loop.

Let's take a closer look at the figure:

 

As you can see from the figure, when the page is scrolled completely, the difference between the height of the page and the height of the scroll is equal to the visible part of the browser window, otherwise this difference is greater. This is the dependence that we will use to get out of the cycle of smooth scrolling of the page.

To implement this dependency as a condition for terminating the script, you must obtain the following values:

  1. The height of the document (page).
    You can determine the size of the page taking into account scrolling by taking the maximum of several properties:

    Let's add this code at the beginning of our anonymous function, after the line:

  2. current page scroll
    you can get the current scroll by using a special property window.pageYOffset

  3. The height of the visible part of the window
    The height of the visible part of the window is contained in the property document.documentElement.clientHeigh

Let's update the function taking into account the above:scroll

So, the smooth scrolling script of the page works, it seems that all the nuances are taken into account and you can stop there.