除非用户向上滚动,否则保持溢出 div 滚动到底部

Posted

技术标签:

【中文标题】除非用户向上滚动,否则保持溢出 div 滚动到底部【英文标题】:Keep overflow div scrolled to bottom unless user scrolls up 【发布时间】:2013-09-07 23:42:23 【问题描述】:

我有一个只有 300 像素大的 div,我希望它在页面加载时滚动到内容的底部。这个 div 有动态添加的内容,需要一直向下滚动。现在,如果用户决定向上滚动,我不希望它跳回底部,直到用户再次向下滚动

是否有可能让一个 div 保持滚动到底部,除非用户向上滚动并且当用户滚动回到底部时,即使添加了新的动态内容,它也需要将自己保持在底部。我将如何创建这个。

【问题讨论】:

使用css位置顶部保持在底部position : relative; bottom:0;。用户滚动后删除 css 属性。 既然你没有接受答案,我想问一下:它对你有用吗? 听起来像是你想要完成的聊天框 对于这个问题的新手,应该在 2020 尝试css snap。 Here's css-only 方法适用于许多情况。 【参考方案1】:

我只能使用 CSS 来实现这一点。

诀窍是使用display: flex;flex-direction: column-reverse;

浏览器将底部视为顶部。假设您的目标浏览器支持flex-box,唯一需要注意的是标记必须以相反的顺序排列。

这是一个工作示例。 https://codepen.io/jimbol/pen/YVJzBg

【讨论】:

您可以通过添加一个额外的包装器并将overflow:auto; display:flex; flex-direction:column-reverse; 应用到外部包装器而不是内部包装器来避免需要反转内容。 可能是最好的解决方案,因为它不需要 javascript @NathanArthur 实际上,如果你只是在容器下添加一个 div 来取消所有内容:codepen.io/anon/pen/pdrLEZ 不幸的是,这个解决方案似乎不适用于 Firefox :( 现在是 2020 年 10 月。我已经检查过它也在 Firefox 上运行。感谢您的快速解决方案。【参考方案2】:

这可能会对您有所帮助:

var element = document.getElementById("yourDivID");
element.scrollTop = element.scrollHeight;

[编辑],以匹配评论...

function updateScroll()
    var element = document.getElementById("yourDivID");
    element.scrollTop = element.scrollHeight;

每当添加内容时,调用函数updateScroll(),或者设置一个定时器:

//once a second
setInterval(updateScroll,1000);

如果您只想在用户没有移动的情况下更新:

var scrolled = false;
function updateScroll()
    if(!scrolled)
        var element = document.getElementById("yourDivID");
        element.scrollTop = element.scrollHeight;
    


$("#yourDivID").on('scroll', function()
    scrolled=true;
);

【讨论】:

这很好地在页面加载时将其滚动到底部,但是当添加动态内容时我需要它保持在底部,除非用户向上滚动。 据我所知,当用户滚动回底部时,这不会重新启用动态滚动... @TvE 我们不能添加支持吗? 错误的解决方案。对于这个轻微的问题,没有理由添加setInterval @ethancrist 然而,你别无选择......耸耸肩。【参考方案3】:

我刚刚实现了这个,也许你可以使用我的方法。

假设我们有以下 html

<div id="out" style="overflow:auto"></div>

然后我们可以检查它是否滚动到底部:

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

scrollHeight 为您提供元素的高度,包括由于溢出而导致的任何不可见区域。 clientHeight 为您提供 CSS 高度,或者以另一种方式说,元素的实际高度。两种方法都返回没有margin 的高度,所以你不必担心。 scrollTop 为您提供垂直滚动的位置。 0 是顶部,最大值是元素的滚动高度减去元素本身的高度。使用滚动条时(对我来说它在 Chrome 中)可能很难将滚动条一直向下移动到底部。所以我投入了 1px 的误差。所以isScrolledToBottom 将是真的,即使滚动条距离底部 1px。您可以将其设置为适合您的任何内容。

那么只需将元素的scrollTop设置到底部即可。

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

我为你做了一个小提琴来展示这个概念:http://jsfiddle.net/dotnetCarpenter/KpM5j/

编辑: 添加了代码 sn-p 以阐明 isScrolledToBottom 何时为 true

将滚动条置于底部

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>

【讨论】:

这实际上是完成所述问题的唯一解决方案。并且应该被标记为正确答案。 @dotnetCarpenter:在我看来你需要if(!isScrolledToBottom):测试对我来说似乎是错误的(并且在我修复它之前无法在 my 代码中工作) . @luskwater 你能提供一个fsfiddle来解决你的问题吗?我不明白out.scrollHeight - out.clientHeight &lt;= out.scrollTop + 1 的问题。您是否在 CSS 中使用填充? 这就是我要找的。而且,这就是 OP 提出的问题的答案。谢谢 dotnetCarperter。 也许我很困惑,但它不应该是“if (!isScrolledToBottom)”吗?添加 not 似乎可以满足 OP 的要求。【参考方案4】:

在 2020 年,您可以使用 css snap,但在 Chrome 81 之前布局更改将 not trigger re-snap,pure css chat ui 适用于 Chrome 81,您也可以查看 Can I use CSS snap。

此演示将捕捉最后一个元素(如果可见),滚动到底部查看效果。

.container 
  overflow-y: scroll;
  overscroll-behavior-y: contain;
  scroll-snap-type: y proximity;


.container > div > div:last-child 
  scroll-snap-align: end;


.container > div > div 
  background: lightgray;
  height: 3rem;
  font-size: 1.5rem;

.container > div > div:nth-child(2n) 
  background: gray;
<div class="container" style="height:6rem">
<div>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</div>
</div>

编辑

使用scroll-snap-type: y proximity;,更容易向上滚动。

【讨论】:

这值得一枚奖牌。正是我想要的:) 它在 Firefox 79 中有效,但仅当您使用滚动条滚动时,如果您使用鼠标滚轮它不会触发回弹。 @aatifshaikh 我更新了答案,现在你可以更轻松地向上滚动了。 接近范围取决于可滚动高度。如果您的聊天视图高于 2 或 3 个聊天气泡,当您向上滚动多达 2 或 3 条消息时,它会再次快速回到末尾(除非您滚动数百像素),这使得该方法无法使用。共享sn-p之所以有效,是因为view的高度太小了。【参考方案5】:
$('#yourDiv').scrollTop($('#yourDiv')[0].scrollHeight);

现场演示:http://jsfiddle.net/KGfG2/

【讨论】:

这很好地在页面加载时将其滚动到底部,但是当添加动态内容时我需要它保持在底部,除非用户向上滚动。 这非常有效。我正在使用动态内容进行更新,并且滚动条始终位于底部。 这仅适用于具有固定高度的 div。不适用于可变 div 高度【参考方案6】:
$('#div1').scrollTop($('#div1')[0].scrollHeight);

Or animated:

$("#div1").animate( scrollTop: $('#div1')[0].scrollHeight, 1000);

【讨论】:

这很好地在页面加载时将其滚动到底部,但是当添加动态内容时我需要它保持在底部,除非用户向上滚动。 这在第一次拍摄时 div 增长很多时不起作用。例如在 Angular-js、react js、Meteor Blaze 模板加载中,这将不起作用。 这对我有用。我认为如果有问题的 div 将保持一致的高度,它会很好。尚未使用动态高度对其进行测试。【参考方案7】:

.cont
height: 100px;
overflow-x: hidden;
overflow-y: auto;
transform: rotate(180deg);
direction:rtl;
text-align:left;

ul
overflow: hidden;
transform: rotate(180deg);
<div class="cont"> 
 <ul>
   <li>0</li>
   <li>1</li>
   <li>2</li>
   <li>3</li>
   <li>4</li>
   <li>5</li>
   <li>6</li>
   <li>7</li>
   <li>8</li>
   <li>9</li>
   <li>10</li>  
 </ul>
</div>

    Run code snippet查看效果。 (PS:如果Run code snippet不起作用,试试这个:https://jsfiddle.net/Yeshen/xm2yLksu/3/)

    工作原理:

默认溢出是从上到下滚动。

transform: rotate(180deg) 可以让它从下到上滚动或加载动态块。

    最初的想法:

https://blog.csdn.net/yeshennet/article/details/88880252

【讨论】:

请添加更多关于您的代码如何解决 OP 问题的说明 1,增加了一个额外的介绍。 2、请Run code snippet,直接看效果。 我没有出现运行代码 sn-p 按钮。检查您的格式 太好了。请在您的答案中包含链接 非常有创意的解决方案。但是,它会反转鼠标滚轮的正常操作。要向上,我必须“向下”滚动,反之亦然。【参考方案8】:
$('#yourDivID').animate( scrollTop: $(document).height() , "slow");
return false;

这将使用$(document).height() 属性从#yourDivID 的高度计算ScrollTop Position,这样即使将动态内容添加到div,滚动条也将始终位于底部位置。希望这可以帮助。但是它也有一个小错误,即使我们向上滚动并将鼠标指针从滚动条上移开,它也会自动到达底部位置。如果有人能纠正那也很好。

【讨论】:

【参考方案9】:

这是基于a blog post by Ryan Hunt 的解决方案。这取决于overflow-anchor CSS 属性,它将滚动位置固定到滚动内容底部的元素。

function addMessage() 
  const $message = document.createElement('div');
  $message.className = 'message';
  $message.innerText = `Random number = $Math.ceil(Math.random() * 1000)`;
  $messages.insertBefore($message, $anchor);

  // Trigger the scroll pinning when the scroller overflows
  if (!overflowing) 
    overflowing = isOverflowing($scroller);
    $scroller.scrollTop = $scroller.scrollHeight;
  


function isOverflowing($el) 
  return $el.scrollHeight > $el.clientHeight;


const $scroller = document.querySelector('.scroller');
const $messages = document.querySelector('.messages');
const $anchor = document.querySelector('.anchor');
let overflowing = false;

setInterval(addMessage, 1000);
.scroller 
  overflow: auto;
  height: 90vh;
  max-height: 11em;
  background: #555;


.messages > * 
  overflow-anchor: none;


.anchor 
  overflow-anchor: auto;
  height: 1px;


.message 
  margin: .3em;
  padding: .5em;
  background: #eee;
<section class="scroller">
  <div class="messages">
    <div class="anchor"></div>
  </div>
</section>

请注意,overflow-anchor 目前在 Safari 中不起作用。

【讨论】:

【参考方案10】:
//Make sure message list is scrolled to the bottom
var container = $('#MessageWindowContent')[0];
var containerHeight = container.clientHeight;
var contentHeight = container.scrollHeight;

container.scrollTop = contentHeight - containerHeight;

这是我基于 dotnetCarpenter 的回答的版本。我的方法是纯 jQuery,我为变量命名以使事情更清晰。发生的情况是,如果内容高度大于容器,我们向下滚动额外的距离以达到所需的结果。

适用于 IE 和 chrome..

【讨论】:

【参考方案11】:

Jim Hall 的回答更可取,因为当你向上滚动时它确实不会滚动到底部,它也是纯 CSS。

非常不幸的是,这不是一个稳定的解决方案:在 chrome 中(可能是由于上面 dotnetCarpenter 描述的 1-px 问题),scrollTop 的行为不准确 1 像素,即使没有用户交互(在添加元素时)。您可以设置scrollTop = scrollHeight - clientHeight,但是当添加另一个元素时,这将使 div 保持在原位,即“将自身保持在底部”功能不再起作用。

因此,简而言之,添加少量 Javascript(叹气)将解决此问题并满足所有要求:

类似于https://codepen.io/anon/pen/pdrLEZ this(Coo 的示例),在将元素添加到列表后,还有以下内容:

container = ...
if(container.scrollHeight - container.clientHeight - container.scrollTop <= 29) 
    container.scrollTop = container.scrollHeight - container.clientHeight;

其中 29 是一行的高度。

所以,当用户向上滚动半行时(如果可能的话?),Javascript 将忽略它并滚动到底部。但我想这是可以忽略的。而且,它修复了 Chrome 1 px 的问题。

【讨论】:

【参考方案12】:

你可以使用这样的东西,

var element = document.getElementById("yourDivID");
window.scrollTo(0,element.offsetHeight);

【讨论】:

请解释一下! 1.scrollTo 是一种将整个窗口滚动到特定坐标的方法。2.offsetHeight 将给出元素的高度,因此上述代码的第二行在您分配时会继续向下滚动窗口东西。【参考方案13】:

我无法得到前两个答案,其他答案都对我没有帮助。所以我从 Reddit r/forhire 和 Upwork 向三个人支付了 30 美元,得到了一些非常好的答案。这个答案应该可以为您节省 90 美元。



Justin Hundley / The Site Bros 的解决方案

HTML

<div id="chatscreen">
  <div id="inner">
  
  </div>
</div>

CSS

#chatscreen 
  width: 300px;
  overflow-y: scroll;
  max-height:100px;

Javascript

$(function()
    var scrolled = false;
  var lastScroll = 0;
  var count = 0;
    $("#chatscreen").on("scroll", function() 
    var nextScroll = $(this).scrollTop();

    if (nextScroll <= lastScroll) 
        scrolled = true;
    
    lastScroll = nextScroll;
    
    console.log(nextScroll, $("#inner").height())
    if ((nextScroll + 100) == $("#inner").height()) 
        scrolled = false;
    
  );
 
  function updateScroll()
      if(!scrolled)
          var element = document.getElementById("chatscreen");
          var inner = document.getElementById("inner");
          element.scrollTop = inner.scrollHeight;
      
  

  // Now let's load our messages
  function load_messages()
      $( "#inner" ).append( "Test" + count + "<br/>" );
      count = count + 1;
      updateScroll();
  

    setInterval(load_messages,300); 
);

Preview the site bros' solution

portfolio



Lermex / Sviatoslav Chumakov 的解决方案

HTML

<div id="chatscreen">

</div>

CSS

#chatscreen 
  height: 300px;
  border: 1px solid purple;
  overflow: scroll;

Javascript

$(function()
var isScrolledToBottom = false;
// Now let's load our messages
function load_messages()
    $( "#chatscreen" ).append( "<br>Test" );
    updateScr();


var out = document.getElementById("chatscreen");
var c = 0;

$("#chatscreen").on('scroll', function()
        console.log(out.scrollHeight);
    isScrolledToBottom = out.scrollHeight - out.clientHeight <= out.scrollTop + 10;
);

function updateScr() 
        // allow 1px inaccuracy by adding 1
    //console.log(out.scrollHeight - out.clientHeight,  out.scrollTop + 1);
    var newElement = document.createElement("div");

    newElement.innerHTML = c++;
    out.appendChild(newElement);
    
    console.log(isScrolledToBottom);

    // scroll to bottom if isScrolledToBotto
    if(isScrolledToBottom) out.scrollTop = out.scrollHeight - out.clientHeight; 


var add = setInterval(updateScr, 1000);

setInterval(load_messages,300); // change to 300 to show the latest message you sent after pressing enter // comment this line and it works, uncomment and it fails
                                // leaving it on 1000 shows the second to last message
setInterval(updateScroll,30);
);

Preview Sviatoslav's solution

portfolio



Igor Rusinov 的解决方案

HTML

<div id="chatscreen"></div>

CSS

#chatscreen 
  height: 100px;
  overflow: scroll;
  border: 1px solid #000;

Javascript

$(function()

// Now let's load our messages
function load_messages()
    $( "#chatscreen" ).append( "<br>Test" );


var out = document.getElementById("chatscreen");
var c = 0;
var add = setInterval(function() 
    // allow 1px inaccuracy by adding 1
    var isScrolledToBottom = out.scrollHeight - out.clientHeight <= out.scrollTop + 1;
    load_messages();

    // scroll to bottom if isScrolledToBotto
    if(isScrolledToBottom) out.scrollTop = out.scrollHeight - out.clientHeight; 
, 1000);
setInterval(updateScroll,30);
);

Preview Igor's solution

portfolio

【讨论】:

【参考方案14】:

以下内容可以满足您的需求(我已尽了最大努力,一路上进行了大量的谷歌搜索):

<html>
<head>
  <script>
    // no jquery, or other craziness. just
    // straight up vanilla javascript functions
    // to scroll a div's content to the bottom
    // if the user has not scrolled up.  Includes
    // a clickable "alert" for when "content" is
    // changed.

    // this should work for any kind of content
    // be it images, or links, or plain text
    // simply "append" the new element to the
    // div, and this will handle the rest as
    // proscribed.

    let scrolled = false; // at bottom?
    let scrolling = false; // scrolling in next msg?
    let listener = false; // does element have content changed listener?
    let contentChanged = false; // kind of obvious
    let alerted = false; // less obvious

    function innerHTMLChanged() 
      // this is here in case we want to
      // customize what goes on in here.
      // for now, just:
      contentChanged = true;
    

    function scrollToBottom(id) 
      if (!id)  id = "scrollable_element"; 
      let DEBUG = 0; // change to 1 and open console
      let dstr = "";

      let e = document.getElementById(id);
      if (e) 
        if (!listener) 
          dstr += "content changed listener not active\n";
          e.addEventListener("DOMSubtreeModified", innerHTMLChanged);
          listener = true;
         else 
          dstr += "content changed listener active\n";
        
        let height = (e.scrollHeight - e.offsetHeight); // this isn't perfect
        let offset = (e.offsetHeight - e.clientHeight); // and does this fix it? seems to...
        let scrollMax = height + offset;

        dstr += "offsetHeight: " + e.offsetHeight + "\n";
        dstr += "clientHeight: " + e.clientHeight + "\n";
        dstr += "scrollHeight: " + e.scrollHeight + "\n";
        dstr += "scrollTop: " + e.scrollTop + "\n";
        dstr += "scrollMax: " + scrollMax + "\n";
        dstr += "offset: " + offset + "\n";
        dstr += "height: " + height + "\n";
        dstr += "contentChanged: " + contentChanged + "\n";

        if (!scrolled && !scrolling) 
          dstr += "user has not scrolled\n";
          if (e.scrollTop != scrollMax) 
            dstr += "scroll not at bottom\n";
            e.scroll(
              top: scrollMax,
              left: 0,
              behavior: "auto"
            )
            e.scrollTop = scrollMax;
            scrolling = true;
           else 
            if (alerted) 
              dstr += "alert exists\n";
             else 
              dstr += "alert does not exist\n";
            
            if (contentChanged)  contentChanged = false; 
          
         else 
          dstr += "user scrolled away from bottom\n";
          if (!scrolling) 
            dstr += "not auto-scrolling\n";

            if (e.scrollTop >= scrollMax) 
              dstr += "scroll at bottom\n";
              scrolled = false;

              if (alerted) 
                dstr += "alert exists\n";
                let n = document.getElementById("alert");
                n.remove();
                alerted = false;
                contentChanged = false;
                scrolled = false;
              
             else 
              dstr += "scroll not at bottom\n";
              if (contentChanged) 
                dstr += "content changed\n";
                if (!alerted) 
                  dstr += "alert not displaying\n";
                  let n = document.createElement("div");
                  e.append(n);
                  n.id = "alert";
                  n.style.position = "absolute";
                  n.classList.add("normal-panel");
                  n.classList.add("clickable");
                  n.classList.add("blink");
                  n.innerHTML = "new content!";

                  let nposy = parseFloat(getComputedStyle(e).height) + 18;
                  let nposx = 18 + (parseFloat(getComputedStyle(e).width) / 2) - (parseFloat(getComputedStyle(n).width) / 2);
                  dstr += "nposx: " + nposx + "\n";
                  dstr += "nposy: " + nposy + "\n";
                  n.style.left = nposx;
                  n.style.top = nposy;

                  n.addEventListener("click", () => 
                    dstr += "clearing alert\n";
                    scrolled = false;
                    alerted = false;
                    contentChanged = false;
                    n.remove();
                  );

                  alerted = true;
                 else 
                  dstr += "alert already displayed\n";
                
               else 
                alerted = false;
              
            
           else 
            dstr += "auto-scrolling\n";
            if (e.scrollTop >= scrollMax) 
              dstr += "done scrolling";
              scrolling = false;
              scrolled = false;
             else 
              dstr += "still scrolling...\n";
            
          
        
      

      if (DEBUG && dstr) console.log("stb:\n" + dstr);

      setTimeout(() =>  scrollToBottom(id); , 50);
    

    function scrollMessages(id) 
      if (!id)  id = "scrollable_element"; 
      let DEBUG = 1;
      let dstr = "";

      if (scrolled) 
        dstr += "already scrolled";
       else 
        dstr += "got scrolled";
        scrolled = true;
      
      dstr += "\n";

      if (contentChanged && alerted) 
        dstr += "content changed, and alerted\n";
        let n = document.getElementById("alert");
        if (n) 
          dstr += "alert div exists\n";
          let e = document.getElementById(id);
          let nposy = parseFloat(getComputedStyle(e).height) + 18;
          dstr += "nposy: " + nposy + "\n";
          n.style.top = nposy;
         else 
          dstr += "alert div does not exist!\n";
        
       else 
        dstr += "content NOT changed, and not alerted";
      

      if (DEBUG && dstr) console.log("sm: " + dstr);
    

    setTimeout(() =>  scrollToBottom("messages"); , 1000);

    /////////////////////
    // HELPER FUNCTION
    //   simulates adding dynamic content to "chat" div
    let count = 0;
    function addContent() 
      let e = document.getElementById("messages");
      if (e) 
        let br = document.createElement("br");
        e.append("test " + count);
        e.append(br);
        count++;
      
    
  </script>

  <style>
    button 
      border-radius: 5px;
    

    #container 
      padding: 5px;
    

    #messages 
      background-color: blue;
      border: 1px inset black;
      border-radius: 3px;
      color: white;
      padding: 5px;
      overflow-x: none;
      overflow-y: auto;
      max-height: 100px;
      width: 100px;
      margin-bottom: 5px;
      text-align: left;
    

    .bordered 
      border: 1px solid black;
      border-radius: 5px;
    

    .inline-block 
      display: inline-block;
    

    .centered 
      text-align: center;
    

    .normal-panel 
      background-color: #888888;
      border: 1px solid black;
      border-radius: 5px;
      padding: 2px;
    

    .clickable 
      cursor: pointer;
    
  </style>
</head>
<body>
<div id="container" class="bordered inline-block centered">
  <div class="inline-block">My Chat</div>

  <div id="messages" onscroll="scrollMessages('messages')">
    test<br>
    test<br>
    test<br>
    test<br>
    test<br>
    test<br>
    test<br>
    test<br>
    test<br>
    test<br>
  </div>

  <button onclick="addContent();">Add Content</button>
</div>
</body>
</html>

注意:您可能需要调整scrollToBottomscrollMessages 中的alert 位置(nposxnposy)以满足您的需求...

还有一个指向我自己的工作示例的链接,托管在我的服务器上:https://night-stand.ca/jaretts_tests/chat_scroll.html

【讨论】:

【参考方案15】:

这就是我的处理方式。我的 div 高度是 650 像素。我决定如果滚动高度在底部的 150px 范围内,则自动滚动它。否则,留给用户。

if (container_block.scrollHeight - container_block.scrollTop < 800) 
                    container_block.scrollTo(0, container_block.scrollHeight);

【讨论】:

【参考方案16】:

我设法让这个工作。诀窍是在添加新元素之前计算:(a) 当前 div 用户滚动位置和 (b) div 滚动高度。

如果 a === b,我们知道用户在添加新元素之前位于底部。

    let div = document.querySelector('div.scrollableBox');

    let span = document.createElement('span');
    span.textContent = 'Hello';

    let divCurrentUserScrollPosition = div.scrollTop + div.offsetHeight;
    let divScrollHeight = div.scrollHeight;

    // We have the current scroll positions saved in
    // variables, so now we can append the new element.
    div.append(span);

    
    if ((divScrollHeight === divCurrentUserScrollPosition)) 
        // Scroll to bottom of div
        div.scrollTo( left: 0, top: div.scrollHeight );
    

【讨论】:

【参考方案17】:

我试图用 Bootstrap 5 来做同样的事情。我正在编写的页面是一个单窗口 html 工具,我希望两列具有可滚动的内容,并且一个需要反转,因为它是一个日志( other 不太可能滚动,除非故意这样做)。列表和它们的标题也是底部锚定的,我很难让标题保持在弹性可滚动列表的顶部。

感谢上面的示例,我可以弄清楚我缺少什么并获得正确的类类型以使其正常工作。

这是我的full example。在我的实际应用程序中,另外两列左侧有第三列,类为mh-100 col overflow-auto,并且不需要内部行/列,因为没有标题可以粘贴在顶部(如果视口太小,它将正常滚动)。这些列表有一个 ID,用于选择和添加它们或删除顶部元素(即反向列表中底部的 &lt;li&gt; 项)。

这里提供了一个较小的版本:

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<div class="vh-100 w-75 container-fluid">
  <h1>2nd Level Scrolling Example</h1>
  <div class="h-75 row align-items-end">
    <div class="mh-100 col d-flex flex-column">
      <div class="row align-items-end">
        <div class="col"><h3>Normal scroll list, grow on top</h3></div>
      </div>
      <div class="row align-items-end overflow-auto">
        <div class="mh-100 col">
          <ul class="list-group">
            <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin ut</li>
            <li>tortor eu ex tincidunt pretium non eu nisl. Ut eu libero ac velit</li>
            <li>ultricies dapibus. Donec id augue scelerisque, gravida est ut,</li>
            <li>commodo sapien. Interdum et malesuada fames ac ante ipsum primis</li>
            <li>in faucibus. Suspendisse volutpat fermentum finibus. Cras egestas</li>
            <li>tempor tempor. Suspendisse potenti. Mauris ac tellus ultrices lectus</li>
            <li>accumsan pellentesque. Nullam semper, nisi nec euismod ultrices, leo</li>
            <li>sem bibendum sapien, in rutrum sapien massa id mi.</li>
          </ul>
        </div>
      </div>
    </div>
    <div class="mh-100 col d-flex flex-column">
      <div class="row align-items-end">
        <div class="col"><h3>Reverse scroll list, grow on bottom</h3></div>
      </div>
      <div class="row align-items-end d-flex flex-column-reverse overflow-auto">
        <div class="mh-100 col">
          <ul class="list-group">
            <li>sem bibendum sapien, in rutrum sapien massa id mi.</li>
            <li>accumsan pellentesque. Nullam semper, nisi nec euismod ultrices, leo</li>
            <li>tempor tempor. Suspendisse potenti. Mauris ac tellus ultrices lectus</li>
            <li>in faucibus. Suspendisse volutpat fermentum finibus. Cras egestas</li>
            <li>commodo sapien. Interdum et malesuada fames ac ante ipsum primis</li>
            <li>ultricies dapibus. Donec id augue scelerisque, gravida est ut,</li>
            <li>tortor eu ex tincidunt pretium non eu nisl. Ut eu libero ac velit</li>
            <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin ut</li>
          </ul>
        </div>
      </div>
    </div>
  </div>
</div>

如果您的视口高度小于整体内容,则标题应位于列表顶部,而所有内容均位于页面底部(实际上是视口高度的 75%,但在此示例中,标题不是占用它的设计空间)。

注意:我并不是真正的网络开发人员,只是为日常工作编写一些方便的基于 html 的工具,因此非常欢迎 cmets。

【讨论】:

【参考方案18】:

基于曼哈顿先生解决方案和 cmets。 https://***.com/a/18614545/9208887.

我还添加了一个带有flex 1 1 0% 的元素,以确保文本在容器未满时从顶部开始。

// just to add some numbers, so we can see the effect
// the actual solution requires no javascript
let num = 1001;
const container = document.getElementById("scroll-container");
document.getElementById("adder").onclick = () =>
  container.append(
    Object.assign(document.createElement("div"), 
      textContent: num++
    )
  );
.scroll-wrapper 
  height: 100px;
  overflow: auto;
  display: flex;
  flex-direction: column-reverse;
  border: 1px solid black;


.scroll-start-at-top 
  flex: 1 1 0%;
<div class="scroll-wrapper">
  <span class="scroll-start-at-top"></span>
  <div id="scroll-container">
    <div>1000</div>
  </div>
</div>

<button id="adder">Add Text</button>

【讨论】:

以上是关于除非用户向上滚动,否则保持溢出 div 滚动到底部的主要内容,如果未能解决你的问题,请参考以下文章

更新时如何让文本区域保持滚动到底部

怎么让overflow的滚动条不占据位置

如何用js控件div的滚动条,让它在内容更新时自动滚到底部?

如何通过JQuery将DIV的滚动条滚动到指定的位置

如何确定 div 是不是滚动到底部?

是否可以让 ScrollView 滚动到底部?