How do I use this Javascript to keep scrollable div focused on its bottom (Javascript newbie)

I want to keep the screen focused on the bottom of a scrollable div whenever it gets loaded. What I have in my game is something like this:

<div id="storywindow" style="position:absolute;bottom:0;overflow:auto">\
\
<<display "PreDisplay">>\
\
<<display "Reactions">>\
<div id="location"><<print $location[$char[0].loc].desc>></div>\
\
<<display $story>>\
\
<div id="reports"><<display "Reports">></div>\
\
</div>\

So, in certain conditions the “reports” div gets filled with sencences, and pushes everything upwards, but when the screen gets filled to the brim, further content sinks downwards to be scrolled, as you may expect. Googling I found this javascript code:

var out = document.getElementById("out");
// allow 1px inaccuracy by adding 1
var isScrolledToBottom = out.scrollHeight - out.clientHeight <= out.scrollTop + 1;

if(isScrolledToBottom)
    out.scrollTop = out.scrollHeight - out.clientHeight;

The source is this (3rd answer):
https://stackoverflow.com/questions/18614301/keep-overflow-div-scrolled-to-bottom-unless-user-scrolls-up

It comes with a lot of other instructions and I get completely lost. I manage well with HTML and CSS, but I barely know anything about Javascript, let alone make it work in a Twine passage. Could somebody tell me what can I do with this?
Thanks a lot in advance.

1 Like

I’m sorry that your question was not answered. I was also wondering how to scroll a dialog to bottom.

EDIT: I was able to do it with this code. Maybe this can help someone else:

<<run Dialog.body().scrollTop = Dialog.body().scrollHeight;>>\

There are several ways to do it: for instance this function should scroll to the bottom of a scrollable element, using the scrollTo method:

function scrollToBottom(elementWithScrollbar) {
	elementWithScrollbar.scrollTo({
      top: elementWithScrollbar.scrollHeight,
      // behavior: 'smooth'
    })
}

Note that you can uncomment the behavior: 'smooth' line by removing the two backslashes in order to animate the scrolling instead of jumping there instantly

If you want to scroll to a particular element inside a scrolling container, the scrollIntoView method is probably handier.


But usually the tricky bit is deciding when to run the code, and finding the element that has the scrollbar, or that you want to scroll to. You want the code to run after the content is loaded (so it knows how tall it is: it does no good to scroll to the bottom of an empty page and then add a bunch of content), but you don’t want to run it over and over again so it prevents the user from scrolling away, etc.

SugarCube’s rendering has two phases: the :passagerender event “renders” the passage off-screen, then it adds the passage to the document all at once and triggers the :passagedisplay event.

So if you want to scroll the whole window to the bottom each time you go to a new passage, you could do this:

$(document).on(':passagedisplay', function(eventData) {
  if(tags().includes('scrollDown')) {
  	scrollToBottom(document.documentElement)
  }
})

Note that I’ve made this conditional: you probably don’t want all your passages to scroll down. So this only scrolls if the passage has a scrollDown tag.

(and actually deciding when to run can be trickier than that, especially if you’re trying to scroll down on the very first page when someone opens your game, or if they close the window and come back in the middle of your game. It might render briefly with the default styling and then change length once your fonts and styles load… but usually this will be good enough)

What else? This is JavaScript code, so it goes in the Story JavaScript section.

So that might get you started… or you might have a more complicated use-case.

This article explains a css only option: Pin Scrolling to Bottom - CSS-Tricks - CSS-Tricks