Challenges are becoming crazier, day by day for me. Today, I had to implement something like the below, but only thing is that, both the chevrons need to be hovered over and the content should scroll:

I thought this was a task simple enough to add just an animate() function in jQuery and start changing the scrollTop of the scrollable element. I did write my first code this way:

$(".prev").mouseover(function () {
  $(".scroll").animate({
    "scrollTop": 0
  }, 1000);
});

Well, I thought, Wow, that was easy. Problem solved. But little did I know that the problem came when you try to scroll both of them. You will see the difference in the speeds, at a given point of time and at a given point of scroll. The below is my first prototype, which obviously is screwed up:

See the Pen BasicScrollableDiv by Praveen Kumar (@praveenscience) on CodePen.

After feeling a sigh of relief, in the QA testing, there was a problem. When you try to scroll down for the first time, it works okayish. Stop at the middle or slight scroll, then try to hover on the top? It goes at light speed. After a long thought I found out the reason.

The parameters we give for the animation's timing function is just the total time of the animation and not the scroll speed. So, when the content has scrolled only to an extent, the animation needs to complete within the same one second duration, which makes the speed go nuts, when it has large content. The same thing takes a longer time if the content is very less.

To combat this issue, we should take the length of the whole scrollable content, and the challenge is to predict where the user might stop the scrolling. It will be like this for each case:

Considering the above way, it changes for each direction and also based on the scrollTop value of the scrollable element. So we need to calculate the animation's timing function as the difference between the height of the total scrollable body and the current scrolling position for the movement to go to top, while difference between double the height of the scrollable area and the current scroll position for the movement to go to bottom.

The above algorithm can be done using:

// To top
$("#scrollPane .wrap").outerHeight() - $("#scrollPane .wrap").scrollTop()
// To bottom
$("#scrollPane .wrap").height() * 2 - $(this).scrollTop()

The above values should be going into the animate's timing function and finally we get this:

See the Pen FinalScrollableDiv by Praveen Kumar (@praveenscience) on CodePen.

This way, both the movement to top and bottom has the same scrolling speed. I also hope you have learnt something from this. Wait! I might be wrong. Please advice me in the comments, if I had done it the wrong way or may be, provide a better solution too. I'll be happy to update the blog post and also give due credits, wherever required.