I have a terminal-like contentEditable div. I'd like new output to cause it to scroll the window so it is in view, unless the user has manually moved the scroll bar to be viewing another position. In that case, I wish to leave it viewing the position they were at.
I'd prefer to avoid doing this with JavaScript hooks or timer callbacks if at all possible. So I was interested in a promising CSS-only solution of using display: flex with flex-direction: column-reverse;. (A comment on that solution explains that you can avoid the hassle of the reversal of elements by using an outer container with the attribute.)
Borrowing a snippet from another one of those answers, here is a demonstration that this technique works--in my browser--but only for a fixed-size div.
const inner = document.getElementById("inner")
let c = 0
setInterval(function() {
const newElement = document.createElement("div")
newElement.textContent = "Line #" + (++c)
inner.appendChild(newElement)
}, 500)
#outer { /* contents of this div are reversed */
height: 100px;
display: flex;
flex-direction: column-reverse;
overflow: auto;
}
#inner { /* this div has content in normal order */
}
<div id="outer"><div id="inner"></div></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>
But changing that to 100% instead breaks it. Same for height: auto. Is there any magic I can apply to keep the behavior and use 100% height?
const inner = document.getElementById("inner")
let c = 0
setInterval(function() {
const newElement = document.createElement("div")
newElement.textContent = "Line #" + (++c)
inner.appendChild(newElement)
}, 500)
#outer { /* contents of this div are reversed */
height: auto;
display: flex;
flex-direction: column-reverse;
overflow: auto;
}
#inner { /* this div has content in normal order */
}
<div id="outer"><div id="inner"></div></div>
<p>Having changed it to 100%, new content never gets scrolled into view, even if the scroll bar was "stuck" to the bottom</p>
For a flexbox you must specify its dimension along the flex-axis (height in this case as it is a column flexbox) - at least it must inherit an intrinsic width - see demo below where it works when a parent element #wrap has a specified height:
const inner = document.getElementById("inner")
let c = 0
setInterval(function() {
const newElement = document.createElement("div")
newElement.textContent = "Line #" + (++c)
inner.appendChild(newElement)
}, 500)
function format() {
return Array.prototype.slice.call(arguments).join(' ')
}
#wrap {
height: 100px;
}
#outer {
/* contents of this div are reversed */
height: 100%;
display: flex;
flex-direction: column-reverse;
overflow: auto;
}
#inner {
/* this div has content in normal order */
}
<div id="wrap">
<div id="outer">
<div id="inner"></div>
</div>
<p>Having changed it to 100%, new content never gets scrolled into view, even if the scroll bar was "stuck" to the bottom</p>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With