Auto-Scroll in Javascript

CG_Musta
The Startup
Published in
5 min readSep 26, 2020

Recently I was working on a project, a Chat-app, and I had to solve a problem with the messages displayed to the user. While testing the app, I’ve noticed that when user’s messages reach the bottom of the visible part on the screen I had to scroll manually to keep viewing the new message, and it wasn’t Ideal for user experience. My question was, how I can I make this scroll automatically while the user is sending messages? the answer was easier than I thought, I had just to google it:

I’ve found many useful methods that could help me to get the job done with one line of code:

($messages) is the div I am using to insert the messages in:

const $messages = document.querySelector('#messages')

“the element’s scrollTop value is a measurement of the distance from the element's top to its topmost visible content. When an element's content does not generate a vertical scrollbar, then its scrollTop value is 0".sources

“The Element.scrollHeight read-only property is a measurement of the height of an element's content, including content not visible on the screen due to overflow". Sources

Now, this function works perfectly fine if you call it at the end of the method that adds the new messages. So what the big issue here??. I’ve found out that when a new user joins the chat and try to read the previous messages was automatically scrolled to the bottom of the chat when a new message is sent. This made it impossible for a user to read the old messages or review the chat without getting interrupted and scrolled down every time a new message comes in.

As you can imagine this can get really frustrated and not delivering the best user experience. The solution in my head was, I need to make sure that the auto-scroll function runs just if the user is already at the bottom of the page, means that the user is actually reading the last messages, but if the user is on the top reading the old message I should not run this method in a way to don’t bring it down automatically.

So let’s go step by step in building this new method. First, we need to create a variable that grabs the last message element:

const newMessage = $messages.lastElementChild

Second, we need to get the height of the new message and take in consideration its margin as well, and we have a few steps here to follow:

const newMessageStyles = getComputedStyle(newMessage)

This will give us all the styles of the new messages, so we can figure out what that margin-bottom spacing value is. We need to extract the marginBottom styles and convert them in numerical value from a string:

const newMessageMargin = parseInt(newMessageStyles.marginBottom)

We can now create a variable and store the height of the new message plus its margin value that we figure out from the above methods:

const newMessageHeight = newMessage.offsetHeight + newMessageMargin

Now we have the total height of the new message, including its margin.

The third step is to get the visible height which is the amount of space I can view on the screen, and this value does not often change as you can imagine.

const visibleHight = $messages.offsetHeight

The next step is to get the total height of the container, which is much larger than the visible hight as there are things I cannot see at some point, and it gets larger every time a new message is sent, and we need to scroll.

const containerHeight = $messages.scrollHeight

This will give us the total height we can scroll through. Now is one of the most important point, we need to figure out how much we have scrolled, for example, we are at the top of the mage in the middle or at the bottom.

const scrollOffset = $messages.scrollTop + visibleHeight

($messages.scrollTop), give is the amount of distance I have scrolled from the top. If you are at the top of the page with the scroll bar, this value will be zero, and more you go down more this value will increase. We then add the visibleHeight we calculate previously, and this will give us how close to the bottom we are.

It’s time to add some conditional logic to our code to make sure we are at the bottom of the page when a new message gets added:

if (containerHeight - newMessageHeight <= scrollOffset)

The condition we are checking is the following:

We take out from the total of the container height the height of the new message because we want to make sure that the user was at the bottom of the page before the new message comes in. We then check if this height is less or equal to the “scrolloffset”, which measure the total of the scroll from the bottom pulse the visible part.

if (containerHeight - newMessageHeight <= scrollOffset) {$messages.scrollTop = $messages.scrollHeight}

It may sound complicated, this is why I prepared a small visual content that could help you to better visualize the above logic.

If the total container height minus the new message is less or equal to the distance scrolled from the bottom plus the visible part, set the scroll height equal to the total available content we can scroll.

And this is how the function should look like in the end:

--

--