Introduction
This article is a summary of the approach using JavaScript, after reading Implementing a pin-to-bottom scrolling element with only CSS.
Nowadays, it is common to see web pages automatically scrolling to the bottom whenever new content is added. For example, the comment sections on platforms like Twitch and YouTube.
In Chinese, there doesn't seem to be a specific term for this behavior, so let's call it "pin to bottom" for now.
[JavaScript] How to implement?
function append(comment) {
const comments = document.querySelector(".comments")
comments.appendChild(comment)
comments.scrollTop = comments.scrollHeight
}
First, set the container to a fixed height and add overflow-y: auto
. This allows the content to scroll when it exceeds the container's height.
Whenever a new element is added, simply call comments.scrollTop = comments.scrollHeight
to ensure that the scrollTop
always equals the height of scrollHeight
.
Considerations
Although this implementation is straightforward, there is one issue to address. When users want to scroll back to view other content, if new comments appear, the page will still force scroll to the bottom.
To solve this, we can check the current scrollTop
of the container. If there is a significant difference compared to scrollHeight
, we won't automatically scroll for the user.
if (
comments.offsetHeight < comments.scrollHeight &&
comments.scrollTop + comments.offsetHeight + 150 > comments.scrollHeight
) {
comments.scrollTop = comments.scrollHeight - comments.offsetHeight
}
Here, offsetHeight
represents the container's height (CSS height), scrollHeight
represents the total scrolled height of the container, and scrollTop
represents the current scroll position.
- If it has not exceeded
offsetHeight
, there's no need to define the scrolling behavior. - If the user has scrolled more than
150px
, we won't automatically scroll for them.
Additionally, if we don't automatically scroll, it is common to add a button or indicator for the user to jump to the latest comment.
Another potential performance issue can arise if the comment list is very long. There are a few ways to handle this:
- Keep only the latest 500 comments (the specific number depends on the actual requirement).
- Optimize using techniques like windowing (though it may not be suitable for variable heights).
overflow-anchor
Today, I want to introduce a method to achieve a similar effect using overflow-anchor. I came across this property in the article Implementing a pin-to-bottom scrolling element with only CSS. The article explains how to achieve the desired effect using overflow-anchor
.
This property is defined in the CSS Scroll Anchoring Module. To efficiently allow users to consume content, this draft defines the behavior of overflow-anchor
. It automatically detects the content that needs to be anchored when resizing or scrolling occurs.
The detailed algorithm definition can be found here.
- When scrolling content S, select an anchor node from the child elements whose
overflow-anchor
property is notnone
. - If N is inside scrolling content S and cannot be seen (excluded subtree or fully clipped, meaning it is not visible within the scrolling frame), do nothing.
- If N is visible inside scrolling content S, select N as the anchor node.
- If N is partially visible inside scrolling content S, continue the algorithm on the child elements to find the anchor node.
The draft defines many other behaviors, so feel free to explore if interested. However, understanding what it can do is sufficient.
First, we add an anchor within the container:
<ul class="comments">
<li class="anchor"></li>
</ul>
The anchor
should have the CSS property overflow-anchor: auto
to make the browser recognize it as an anchor.
.comments {
& > .comment {
overflow-anchor: none; // Not an anchor
}
.anchor {
overflow-anchor: auto; // Anchor
}
}
Then, change the way comments are added using insertBefore
to ensure they are inserted before the anchor.
Test Results
On the left is the regular approach, while on the right is the implementation using overflow-anchor
. However, I noticed that scrolling the anchor is required for it to work correctly.
As an additional note, the text content used is from an article I wrote after reading "Gasoline Life" by Kotaro Isaka. I copied a few paragraphs for convenience.
Currently, browser support is limited to Firefox 66 and Chrome 56, so it is not widely adopted. However, there may be new approaches in the future for similar functionality. Although the drawback is the need to add an additional anchor, it is an interesting method achieved purely with CSS.