ChatGPT解决这个技术问题 Extra ChatGPT

Scroll to bottom of div?

I am creating a chat using Ajax requests and I'm trying to get messages div to scroll to the bottom without much luck.

I am wrapping everything in this div:

#scroll {
    height:400px;
    overflow:scroll;
}

Is there a way to keep it scrolled to the bottom by default using JS?

Is there a way to keep it scrolled to the bottom after an ajax request?

In many cases this can be achieved with CSS-only. See this answer.

B
Black

Here's what I use on my site:

var objDiv = document.getElementById("your_div");
objDiv.scrollTop = objDiv.scrollHeight;

is this method ok with all browsers?
@PaulDinh: I just looked into this and there is an issue with IE7 and lower using scrollHeight. There does seem to be a work around for IE7 here.
why not scrollTopMax instead of scrollHeight?
This isn't working when I dynamically add images :(
The 'modern' way is to use Element.scrollIntoView() -- developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
d
dankilev

This is much easier if you're using jQuery scrollTop:

$("#mydiv").scrollTop($("#mydiv")[0].scrollHeight);

you need [0] to get dom element from jquery element to get scrollHeight
Without repeating yourself: $("#mydiv").scrollTop(function() { return this.scrollHeight; });
T
Tho

Try the code below:

const scrollToBottom = (id) => {
    const element = document.getElementById(id);
    element.scrollTop = element.scrollHeight;
}

You can also use Jquery to make the scroll smooth:

const scrollSmoothlyToBottom = (id) => {
    const element = $(`#${id}`);
    element.animate({
        scrollTop: element.prop("scrollHeight")
    }, 500);
}

Here is the demo

Here's how it works:

https://i.stack.imgur.com/IC85R.png

Ref: scrollTop, scrollHeight, clientHeight


this is really right answer, the pic is really useful
b
benomatis

using jQuery animate:

$('#DebugContainer').stop().animate({
  scrollTop: $('#DebugContainer')[0].scrollHeight
}, 800);

Notice how this answer uses .stop(), which prevents issues with multiple animations.
m
mikemaccana

Newer method that works on all current browsers:

this.scrollIntoView(false);

This should be the accepted answer as the older methods do not work anymore
That would be the case if "this" is something in the div that can be scrolled to
The method scrollIntoView is triggered on a child element inside a parent container. So how to use it to: scroll parent to bottom (as asked in the original question).
You can use scrollIntoView({ behavior: "smooth", block: "end" });
See which browsers are supported here caniuse.com/?search=scrollIntoView
A
Akira Yamamoto
var mydiv = $("#scroll");
mydiv.scrollTop(mydiv.prop("scrollHeight"));

Works from jQuery 1.6

https://api.jquery.com/scrollTop/

http://api.jquery.com/prop/


a
adl

smooth scroll with Javascript:

document.getElementById('messages').scrollIntoView({ behavior: 'smooth', block: 'end' });


A
Ahmet Şimşek

alternative solution

function scrollToBottom(element) {
  element.scroll({ top: element.scrollHeight, behavior: 'smooth' });
}

Great answer, tested and working well. Thank you.
B
Benny Neugebauer

If you don't want to rely on scrollHeight, the following code helps:

$('#scroll').scrollTop(1000000);

looks like a hack. what does the 1000000 number mean?
B
Barath Sankar

Java Script:

document.getElementById('messages').scrollIntoView(false);

Scrolls to the last line of the content present.


A
Anatol

You can use the HTML DOM scrollIntoView Method like this:

var element = document.getElementById("scroll");
element.scrollIntoView();

n
ngShravil.py

My Scenario: I had an list of string, in which I had to append a string given by a user and scroll to the end of the list automatically. I had fixed height of the display of the list, after which it should overflow.

I tried @Jeremy Ruten's answer, it worked, but it was scrolling to the (n-1)th element. If anybody is facing this type of issue, you can use setTimeOut() method workaround. You need to modify the code to below:

setTimeout(() => {
    var objDiv = document.getElementById('div_id');
    objDiv.scrollTop = objDiv.scrollHeight
}, 0)

Here is the StcakBlitz link I have created which shows the problem and its solution : https://stackblitz.com/edit/angular-ivy-x9esw8


with setTimeout(), its working fine. Worked with angular 9. Saved my day.
Happy to help :)
L
Lay Leangsros

Javascript or jquery:

var scroll = document.getElementById('messages');
   scroll.scrollTop = scroll.scrollHeight;
   scroll.animate({scrollTop: scroll.scrollHeight});

Css:

 .messages
 {
      height: 100%;
      overflow: auto;
  }

M
Muhammad Soliman

Using jQuery, scrollTop is used to set the vertical position of scollbar for any given element. there is also a nice jquery scrollTo plugin used to scroll with animation and different options (demos)

var myDiv = $("#div_id").get(0);
myDiv.scrollTop = myDiv.scrollHeight;

if you want to use jQuery's animate method to add animation while scrolling down, check the following snippet:

var myDiv = $("#div_id").get(0);
myDiv.animate({
    scrollTop: myDiv.scrollHeight
  }, 500);

B
Benkinass

I have encountered the same problem, but with an additional constraint: I had no control over the code that appended new elements to the scroll container. None of the examples I found here allowed me to do just that. Here is the solution I ended up with .

It uses Mutation Observers (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) which makes it usable only on modern browsers (though polyfills exist)

So basically the code does just that :

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});

I made a fiddle to demonstrate the concept : https://jsfiddle.net/j17r4bnk/


how to get dynamic id? like in <div class="abc"><div data-bind=attr : {'id': myId } ></div></div> In this code myId is a variable. How can I access this id in script.
I'm not quite sure I understand your question. In my example, "myId" is the id of the scroll container. Do you want to create more than one area where the user can scroll ?
d
devonj

Found this really helpful, thank you.

For the Angular 1.X folks out there:

angular.module('myApp').controller('myController', ['$scope', '$document',
  function($scope, $document) {

    var overflowScrollElement = $document[0].getElementById('your_overflow_scroll_div');
    overflowScrollElement[0].scrollTop = overflowScrollElement[0].scrollHeight;

  }
]);

Just because the wrapping in jQuery elements versus HTML DOM elements gets a little confusing with angular.

Also for a chat application, I found making this assignment after your chats were loaded to be useful, you also might need to slap on short timeout as well.


B
Bruno Jennrich

small addendum: scrolls only, if last line is already visible. if scrolled a tiny bit, leaves the content where it is (attention: not tested with different font sizes. this may need some adjustments inside ">= comparison"):

var objDiv = document.getElementById(id);
var doScroll=objDiv.scrollTop>=(objDiv.scrollHeight-objDiv.clientHeight);                   

// add new content to div
$('#' + id ).append("new line at end<br>"); // this is jquery!

// doScroll is true, if we the bottom line is already visible
if( doScroll) objDiv.scrollTop = objDiv.scrollHeight;

m
mylescc

Just as a bonus snippet. I'm using angular and was trying to scroll a message thread to the bottom when a user selected different conversations with users. In order to make sure that the scroll works after the new data had been loaded into the div with the ng-repeat for messages, just wrap the scroll snippet in a timeout.

$timeout(function(){
    var messageThread = document.getElementById('message-thread-div-id');
    messageThread.scrollTop = messageThread.scrollHeight;
},0)

That will make sure that the scroll event is fired after the data has been inserted into the DOM.


I suspect $scope.$apply(callback) would work as well as this forces a digest and re-evaluation of the view.
Thank you! I was really wondering why I couldn't get it to work and the $timeout was the issue.
@Wayferer same setTimeout(function() { ... }, n)
N
Navaneeth

This will let you scroll all the way down regards the document height

$('html, body').animate({scrollTop:$(document).height()}, 1000);

J
John Dunne

You can also, using jQuery, attach an animation to html,body of the document via:

$("html,body").animate({scrollTop:$("#div-id")[0].offsetTop}, 1000);

which will result in a smooth scroll to the top of the div with id "div-id".


M
Mike Taverne

Like you, I'm building a chat app and want the most recent message to scroll into view. This ultimately worked well for me:

//get the div that contains all the messages
let div = document.getElementById('message-container');

//make the last element (a message) to scroll into view, smoothly!
div.lastElementChild.scrollIntoView({ behavior: 'smooth' });

m
mjaque

Scroll to the last element inside the div:

myDiv.scrollTop = myDiv.lastChild.offsetTop

a
aravk33

A very simple method to this is to set the scroll to to the height of the div.

var myDiv = document.getElementById("myDiv");
window.scrollTo(0, myDiv.innerHeight);

m
moreirapontocom

On my Angular 6 application I just did this:

postMessage() {
  // post functions here
  let history = document.getElementById('history')
  let interval    
  interval = setInterval(function() {
    history.scrollTop = history.scrollHeight
    clearInterval(interval)
  }, 1)
}

The clearInterval(interval) function will stop the timer to allow manual scroll top / bottom.


A
Adonis Gaitatzis

You can use the Element.scrollTo() method.

It can be animated using the built-in browser/OS animation, so it's super smooth.

function scrollToBottom() { const scrollContainer = document.getElementById('container'); scrollContainer.scrollTo({ top: scrollContainer.scrollHeight, left: 0, behavior: 'smooth' }); } // initialize dummy content const scrollContainer = document.getElementById('container'); const numCards = 100; let contentInnerHtml = ''; for (let i=0; i

Card ${i + 1}
`; } scrollContainer.innerHTML = contentInnerHtml; .overflow-y-scroll { overflow-y: scroll; }


M
Marcio Duarte

If your project targets modern browsers, you can now use CSS Scroll Snap to control the scrolling behavior, such as keeping any dynamically generated element at the bottom.

.wrapper > div { background-color: white; border-radius: 5px; padding: 5px 10px; text-align: center; font-family: system-ui, sans-serif; } .wrapper { display: flex; padding: 5px; background-color: #ccc; border-radius: 5px; flex-direction: column; gap: 5px; margin: 10px; max-height: 150px; /* Control snap from here */ overflow-y: auto; overscroll-behavior-y: contain; scroll-snap-type: y mandatory; } .wrapper > div:last-child { scroll-snap-align: start; }

01
02
03
04
05
06
07
08
09
10


B
BrianLegg

I know this is an old question, but none of these solutions worked out for me. I ended up using offset().top to get the desired results. Here's what I used to gently scroll the screen down to the last message in my chat application:

$("#html, body").stop().animate({
     scrollTop: $("#last-message").offset().top
}, 2000);

I hope this helps someone else.


j
jocassid

I use the difference between the Y coordinate of the first item div and the Y coordinate of the selected item div. Here is the JavaScript/JQuery code and the html:

function scrollTo(event){ // In my proof of concept, I had a few

S
Spankied

Css only:

.scroll-container {
  overflow-anchor: none;
}

Makes it so the scroll bar doesn't stay anchored to the top when a child element is added. For example, when new message is added at the bottom of chat, scroll chat to new message.


P
PanDe

Why not use simple CSS to do this?

The trick is to use display: flex; and flex-direction: column-reverse;

Here is a working example. https://codepen.io/jimbol/pen/YVJzBg