Keep overflow div scrolled to bottom unless user scrolls up
I was able to get this working with CSS only.
The trick is to use display: flex;
and flex-direction: column-reverse;
The browser treats the bottom like its the top. Assuming the browsers you're targeting support flex-box
, the only caveat is that the markup has to be in reverse order.
Here is a working example. https://codepen.io/jimbol/pen/YVJzBg
I just implemented this and perhaps you can use my approach.
Say we have the following HTML:
<div id="out" style="overflow:auto"></div>
Then we can check if it scrolled to the bottom with:
var out = document.getElementById("out");
// allow 1px inaccuracy by adding 1
var isScrolledToBottom = out.scrollHeight - out.clientHeight <= out.scrollTop + 1;
scrollHeight gives you the height of the element, including any non visible area due to overflow. clientHeight gives you the CSS height or said in another way, the actual height of the element. Both methods returns the height without margin
, so you needn't worry about that. scrollTop gives you the position of the vertical scroll. 0 is top and max is the scrollHeight of the element minus the element height itself. When using the scrollbar it can be difficult (it was in Chrome for me) to get the scrollbar all the way down to the bottom. so I threw in a 1px inaccuracy. So isScrolledToBottom
will be true even if the scrollbar is 1px from the bottom. You can set this to whatever feels right to you.
Then it's simply a matter of setting the scrollTop of the element to the bottom.
if(isScrolledToBottom)
out.scrollTop = out.scrollHeight - out.clientHeight;
I have made a fiddle for you to show the concept: http://jsfiddle.net/dotnetCarpenter/KpM5j/
EDIT:
Added code snippet to clarify when isScrolledToBottom
is true
.
Stick scrollbar to bottom
const out = document.getElementById("out")
let c = 0
setInterval(function() {
// allow 1px inaccuracy by adding 1
const isScrolledToBottom = out.scrollHeight - out.clientHeight <= out.scrollTop + 1
const newElement = document.createElement("div")
newElement.textContent = format(c++, 'Bottom position:', out.scrollHeight - out.clientHeight, 'Scroll position:', out.scrollTop)
out.appendChild(newElement)
// scroll to bottom if isScrolledToBottom is true
if (isScrolledToBottom) {
out.scrollTop = out.scrollHeight - out.clientHeight
}
}, 500)
function format () {
return Array.prototype.slice.call(arguments).join(' ')
}
#out {
height: 100px;
}
<div id="out" style="overflow:auto"></div>
<p>To be clear: We want the scrollbar to stick to the bottom if we have scrolled all the way down. If we scroll up, then we don't want the content to move.
</p>
This might help you:
var element = document.getElementById("yourDivID");
element.scrollTop = element.scrollHeight;
[EDIT], to match the comment...
function updateScroll(){
var element = document.getElementById("yourDivID");
element.scrollTop = element.scrollHeight;
}
whenever content is added, call the function updateScroll(), or set a timer:
//once a second
setInterval(updateScroll,1000);
if you want to update ONLY if the user didn't move:
var scrolled = false;
function updateScroll(){
if(!scrolled){
var element = document.getElementById("yourDivID");
element.scrollTop = element.scrollHeight;
}
}
$("#yourDivID").on('scroll', function(){
scrolled=true;
});