Me he encontrado con el mismo problema, pero con una restricción adicional: no tenía control sobre el código que agregaba nuevos elementos al contenedor de desplazamiento. Ninguno de los ejemplos que encontré aquí me permitió hacer eso. Aquí está la solución con la que terminé.
Utiliza Mutation Observers
( https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver ) lo que lo hace utilizable solo en navegadores modernos (aunque existen polyfills)
Entonces, básicamente, el código hace exactamente eso:
var scrollContainer = document.getElementById("myId");
// Define the Mutation Observer
var observer = new MutationObserver(function(mutations) {
// Compute sum of the heights of added Nodes
var newNodesHeight = mutations.reduce(function(sum, mutation) {
return sum + [].slice.call(mutation.addedNodes)
.map(function (node) { return node.scrollHeight || 0; })
.reduce(function(sum, height) {return sum + height});
}, 0);
// Scroll to bottom if it was already scrolled to bottom
if (scrollContainer.clientHeight + scrollContainer.scrollTop + newNodesHeight + 10 >= scrollContainer.scrollHeight) {
scrollContainer.scrollTop = scrollContainer.scrollHeight;
}
});
// Observe the DOM Element
observer.observe(scrollContainer, {childList: true});
Hice un violín para demostrar el concepto:
https://jsfiddle.net/j17r4bnk/