簡體   English   中英

除非用戶向上滾動,否則保持溢出 div 滾動到底部

[英]Keep overflow div scrolled to bottom unless user scrolls up

我有一個只有 300 像素大的 div,我希望它在頁面加載時滾動到內容的底部。 這個 div 有動態添加的內容,需要一直向下滾動。 現在,如果用戶決定向上滾動,我不希望它跳回到底部,直到用戶再次向下滾動

是否有可能讓一個 div 保持滾動到底部,除非用戶向上滾動,並且當用戶滾動回到底部時,即使添加了新的動態內容,它也需要將自己保持在底部。 我 go 如何創建它。

我只能使用 CSS 來實現它。

訣竅是使用display: flex; flex-direction: column-reverse;

瀏覽器將底部視為頂部。 假設您的目標瀏覽器支持flex-box ,唯一需要注意的是標記必須以相反的順序排列。

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

這可能會幫助您:

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

我剛剛實現了這個,也許你可以使用我的方法。

假設我們有以下 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 的誤差。 因此即使滾動條距離底部 1px, isScrolledToBottom也會為真。 您可以將其設置為適合您的任何內容。

然后只需將元素的 scrollTop 設置到底部即可。

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

我為你做了一個小提琴來展示這個概念:http: //jsfiddle.net/dotnetCarpenter/KpM5j/

編輯:添加代碼片段以闡明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>

2020 年可以使用css snap ,但在 Chrome 81 之前布局更改不會觸發 re-snap純 css 聊天 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; , 向上滾動更容易。

$('#yourDiv').scrollTop($('#yourDiv')[0].scrollHeight);

現場演示:http: //jsfiddle.net/KGfG2/

$('#div1').scrollTop($('#div1')[0].scrollHeight);

Or animated:

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

 .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>

  1. Run code snippet查看效果。 (PS:如果Run code snippet不起作用,試試這個: https ://jsfiddle.net/Yeshen/xm2yLksu/3/)

  2. 它是如何工作的:

默認溢出是從上到下滾動。

transform: rotate(180deg)可以使其從下到上滾動或加載動態塊。

  1. 創見:

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

基於 Jim Halls 的解決方案和評論。 https://stackoverflow.com/a/44051405/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>

這是基於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 中不起作用。

我無法得到前兩個答案,其他答案都對我沒有幫助。 所以我從 Reddit r/forhireUpwork向三個人支付了 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); 
});

預覽網站兄弟的解決方案

文件夾



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

預覽 Sviatoslav 的解決方案

文件夾



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

預覽 Igor 的解決方案

文件夾

$('#yourDivID').animate({ scrollTop: $(document).height() }, "slow");
return false;

這將使用$(document).height()屬性從#yourDivID的高度計算 ScrollTop Position,這樣即使將動態內容添加到 div,滾動條也將始終位於底部位置。 希望這可以幫助。 但是它也有一個小錯誤,即使我們向上滾動並將鼠標指針從滾動條上移開,它也會自動到達底部位置。 如果有人可以糾正這一點,那就太好了。

//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..

吉姆霍爾的答案是可取的,因為當你向上滾動時它確實不會滾動到底部,它也是純 CSS。

然而,非常不幸的是,這不是一個穩定的解決方案:在 chrome 中(可能是由於上面 dotnetCarpenter 描述的 1-px 問題),即使沒有用戶交互(在添加元素時), scrollTop的行為也會不准確 1 個像素。 您可以設置scrollTop = scrollHeight - clientHeight ,但是當添加另一個元素時,這將使 div 保持在適當的位置,即“將自身保持在底部”功能不再起作用。

因此,簡而言之,添加少量 Javascript(嘆氣)將解決此問題並滿足所有要求:

https://codepen.io/anon/pen/pdrLEZ這樣的東西(Coo 的例子),在向列表中添加一個元素之后,還有以下內容:

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

其中 29 是一條線的高度。

因此,當用戶向上滾動半行時(如果可能的話?),Javascript 將忽略它並滾動到底部。 但我想這是可以忽略的。 而且,它修復了 Chrome 1 px 的東西。

你可以使用這樣的東西,

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

以下是您需要的(我盡了最大努力,一路上進行了大量的谷歌搜索):

<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中的警報位置( nposxnposy )以滿足您的需要......

還有一個鏈接到我自己的工作示例,托管在我的服務器上: https ://night-stand.ca/jaretts_tests/chat_scroll.html

這是我的處理方式。 我的 div 高度是 650 像素。 我決定如果滾動高度在底部的 150px 范圍內,則自動滾動它。 否則,留給用戶。

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

我設法讓這個工作。 訣竅是計算:(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 });
    }

我試圖對 Bootstrap 5 做同樣的事情。我正在編寫的頁面是一個單窗口 html 工具,我希望兩列具有可滾動的內容,並且一個需要反轉,因為它是一個日志(另一個不太可能滾動,除非故意這樣做)。 列表和它們的標題也是底部錨定的,我很難讓標題保持在彈性可滾動列表的頂部。

多虧了上面的例子,我可以弄清楚我缺少什么並獲得正確的類類型來使其工作。

這是我的完整示例 在我的實際應用程序中,另外兩列左側的第三列具有mh-100 col overflow-auto類,並且不需要內部行/列,因為沒有標題可以粘貼在頂部(如果視口是,它只會正常滾動太小)。 列表有一個 ID,我用來選擇和添加它們或刪除頂部元素(這是反向列表中底部的<li>項)。

這里提供了一個較小的版本:

 <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 的工具,因此非常歡迎發表評論。

我發現最用戶友好的解決方案是將scroll-snap-align方法與一點點 Javascript 結合起來。 前一種解決方案本身的問題是快照太強,您必須滾動很遠才能擺脫它。

取而代之的是,我們可以在容器滾動到底部時使用捕捉動態,然后在用戶向上滾動超過某個閾值時禁用它。

該解決方案還有一個額外的好處,即它是一種漸進式增強:如果用戶禁用了 Javascript,它將回退到僅使用 CSS 的方法。

 const container = document.getElementById("container"); const snap = document.getElementById("snap"); // Scroll the view to the bottom once initially container.scrollTop = container.scrollHeight; container.addEventListener("scroll", (event) => { const target = event.currentTarget; const scroll = target.scrollTop; const maxScroll = target.scrollHeight - target.clientHeight; const threshold = 50; // px isScrollBottomedOut = maxScroll - scroll < threshold; // If the user scrolls up more than the threshold, disable snapping // If the user scrolls down again, reenable snapping snap.style.display = isScrollBottomedOut ? "block" : "none"; });
 #container { width: 200px; height: 500px; overflow-y: auto; overflow-x: hidden; -webkit-overflow-scrolling: touch; -ms-scroll-chaining: none; overscroll-behavior: contain; -ms-scroll-snap-type: y proximity; scroll-snap-type: y proximity; border: 2px solid black; } #snap { scroll-snap-align: end; }
 <div id="container"> <ol> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> </ol> <!-- This is the snapping target, if visible --> <div id="snap"></div> </div>

這個問題有原生支持。

有一個名為*.scrollIntoView的方法。 運行此方法一次后,它使容器在底部滾動。 即使在向容器中添加新內容后,它也會滾動到底部。

import {
  AfterViewInit,
  Directive,
  ElementRef,
} from '@angular/core';

@Directive({
  selector: '[aeScrollIntoView]',
})
export class ScrollIntoViewDirective implements AfterViewInit {
  constructor(private readonly el: ElementRef<HTMLDivElement>) {}
  ngAfterViewInit(): void {
    this.el.nativeElement.scrollIntoView({ behavior: 'smooth' });
  }
}

<div aeScrollIntoView>
 Your long and dynamic content. 
 Whenever new content is added to this container, it scrolls to the bottom.
<div>

使用 Bootstrap 5:

 <div class="overflow-auto d-flex flex-column-reverse" style="max-width: 300px; max-height: 300px;"> <div> <!-- Your content here --> </div> </div>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM