Lassen Sie den Überlauf div nach unten scrollen, es sei denn, der Benutzer scrollt nach oben

222

Ich habe ein Div, das nur 300 Pixel groß ist, und ich möchte, dass beim Laden der Seite zum Ende des Inhalts gescrollt wird. Diesem Div werden Inhalte dynamisch hinzugefügt und müssen bis zum Anschlag gescrollt werden. Wenn der Benutzer sich entscheidet, nach oben zu scrollen, möchte ich nicht, dass er nach unten zurückspringt, bis der Benutzer wieder ganz nach unten scrollt

Ist es möglich, ein Div zu haben, das nach unten gescrollt bleibt, es sei denn, der Benutzer scrollt nach oben und wenn der Benutzer nach unten zurückblättert, muss er sich selbst dann unten halten, wenn neuer dynamischer Inhalt hinzugefügt wird. Wie würde ich das schaffen?

Robert E. McIntosh
quelle
1
Verwenden Sie die CSS-Position oben und halten Sie sie unten {position : relative; bottom:0;}. Entfernen Sie die CSS-Eigenschaft, sobald der Benutzer einen Bildlauf durchgeführt hat.
TCHdvlp
Da Sie keine Antwort akzeptiert haben, möchte ich fragen: Hat es bei Ihnen funktioniert?
Mr.Manhattan
4
Klingt wie eine Chatbox, die Sie erreichen möchten
Thielicious
1
Für Neu in dieser Frage sollte versuchen, CSS Snap im Jahr 2020 .
Wener

Antworten:

136

Dies könnte Ihnen helfen:

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

[BEARBEITEN], passend zum Kommentar ...

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

Rufen Sie beim Hinzufügen von Inhalten die Funktion updateScroll () auf oder stellen Sie einen Timer ein:

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

Wenn Sie NUR aktualisieren möchten, wenn sich der Benutzer nicht bewegt hat:

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

$("#yourDivID").on('scroll', function(){
    scrolled=true;
});
Mr. Manhattan
quelle
3
So gut scrollen Sie es beim Laden der Seite nach unten, aber ich brauche es, um unten zu bleiben, wenn dynamischer Inhalt hinzugefügt wird, es sei denn, der Benutzer hat nach oben gescrollt.
Robert E. McIntosh
12
Soweit ich das
beurteilen
@ TVE kann es nicht, dass wir Unterstützung hinzugefügt werden?
Barkermn01
6
Schlechte Lösung. Es gibt keinen Grund, ein setIntervalfür dieses leichte Problem hinzuzufügen .
Ethancrist
6
@ethancrist bieten Sie jedoch keine Alternative ... Achselzucken.
Jarett Lloyd
180

Ich konnte dies nur mit CSS zum Laufen bringen.

Der Trick ist, display: flex;und zu verwendenflex-direction: column-reverse;

Der Browser behandelt die Unterseite wie die Oberseite. Angenommen, die Browser, auf die Sie abzielen, unterstützen flex-box, besteht die einzige Einschränkung darin, dass das Markup in umgekehrter Reihenfolge erfolgen muss.

Hier ist ein Arbeitsbeispiel. https://codepen.io/jimbol/pen/YVJzBg

Jim Hall
quelle
42
Sie können umgehen, indem Sie den Inhalt umkehren müssen, indem Sie einen zusätzlichen Wrapper hinzufügen und ihn overflow:auto; display:flex; flex-direction:column-reverse;auf den äußeren Wrapper anstelle des inneren Wrappers anwenden .
Nathan Arthur
6
wahrscheinlich die beste Lösung, weil es kein Javascript benötigt.
Amit Kumar Khare
3
@ NathanArthur u da real mvp
php_nub_qq
13
@ NathanArthur In der Tat, wenn Sie nur ein div unter Container hinzufügen, um alles rückgängig zu machen: codepen.io/anon/pen/pdrLEZ
Coo
6
Leider scheint diese Lösung in Firefox nicht zu funktionieren :(
Stuart
166

Ich habe das gerade implementiert und vielleicht können Sie meinen Ansatz verwenden.

Angenommen, wir haben den folgenden HTML-Code:

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

Dann können wir überprüfen, ob es nach unten gescrollt hat mit:

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

scrollHeight gibt die Höhe des Elements an, einschließlich aller nicht sichtbaren Bereiche aufgrund von Überlauf. clientHeight gibt Ihnen die CSS-Höhe oder auf andere Weise die tatsächliche Höhe des Elements an. Beide Methoden geben die Höhe ohne zurück margin, sodass Sie sich darüber keine Sorgen machen müssen. scrollTop gibt Ihnen die Position des vertikalen Bildlaufs an . 0 ist oben und max ist die scrollHeight des Elements minus der Elementhöhe selbst. Bei Verwendung der Bildlaufleiste kann es schwierig sein (für mich in Chrome), die Bildlaufleiste ganz nach unten zu bringen. Also warf ich eine 1px Ungenauigkeit ein. So isScrolledToBottomwird wahr sein , selbst wenn die Scrollbar von unten ist 1px. Sie können dies auf das einstellen, was sich für Sie richtig anfühlt.

Dann geht es einfach darum, das scrollTop des Elements nach unten zu setzen.

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

Ich habe eine Geige für Sie gemacht, um das Konzept zu zeigen: http://jsfiddle.net/dotnetCarpenter/KpM5j/

BEARBEITEN: Code-Snippet hinzugefügt, um zu verdeutlichen, wann dies der Fall isScrolledToBottomist true.

Scrollen Sie die Bildlaufleiste nach unten

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
quelle
22
Dies ist tatsächlich die einzige Lösung, die die angegebene Frage erfüllt. Und sollte als die richtige Antwort markiert worden sein.
preezzzy
1
@dotnetCarpenter: Es sieht für mich so aus, als ob Sie es brauchen if(!isScrolledToBottom): Der Test sieht für mich falsch aus (und hat in meinem Code nicht funktioniert , bis ich ihn behoben habe).
luskwater
1
@luskwater können Sie eine fsfiddle mit Ihrem Fix bereitstellen? Ich verstehe das Problem nicht mit out.scrollHeight - out.clientHeight <= out.scrollTop + 1. Verwenden Sie Padding in Ihrem CSS?
dotnetCarpenter
2
Das habe ich gesucht. Und dies ist die Antwort auf die gestellte Frage OP. Danke dotnetCarperter.
Luis Menjivar
1
Wenn jemand 0 erhält, wenn er scrollTop aufruft, schlage ich vor, document.getScrollingElementwie hier vorgeschlagen zu verwenden: stackoverflow.com/questions/36227559/scrolltop-always-returns-0/…
Dane Jordan
29
$('#yourDiv').scrollTop($('#yourDiv')[0].scrollHeight);

Live-Demo: http://jsfiddle.net/KGfG2/

Alvaro
quelle
4
So gut scrollen Sie es beim Laden der Seite nach unten, aber ich brauche es, um unten zu bleiben, wenn dynamischer Inhalt hinzugefügt wird, es sei denn, der Benutzer hat nach oben gescrollt.
Robert E. McIntosh
Das funktioniert perfekt. Ich aktualisiere mit dynamischem Inhalt und die Schriftrolle befindet sich immer unten.
Andy Bajka
14
$('#div1').scrollTop($('#div1')[0].scrollHeight);

Or animated:

$("#div1").animate({ scrollTop: $('#div1')[0].scrollHeight}, 1000);
Sasidharan
quelle
1
So gut scrollen Sie es beim Laden der Seite nach unten, aber ich brauche es, um unten zu bleiben, wenn dynamischer Inhalt hinzugefügt wird, es sei denn, der Benutzer hat nach oben gescrollt.
Robert E. McIntosh
Dies funktioniert nicht, wenn div beim ersten Schuss stark wächst. Beispiel: In Angular-js, reagieren Sie auf js, laden Sie die Meteor Blaze-Vorlage. Dies funktioniert nicht.
Ankur Soni
Das hat bei mir funktioniert. Ich denke, es funktioniert gut, wenn der betreffende Div eine konstante Höhe behält. Habe es nicht mit dynamischen Höhen getestet.
doij790
10

Im Jahr 2020 können Sie CSS-Snap verwenden , aber vor Chrome 81 löst die Layoutänderung keinen erneuten Snap aus . Eine reine CSS-Chat-Benutzeroberfläche funktioniert unter Chrome 81. Sie können auch überprüfen, ob ich CSS-Snap verwenden kann .

Diese Demo fängt das letzte Element ein, wenn es sichtbar ist. Scrollen Sie nach unten, um den Effekt zu sehen.

.container {
  overflow-y: scroll;
  overscroll-behavior-y: contain;
  scroll-snap-type: y mandatory;
}

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

Geben Sie hier die Bildbeschreibung ein

wener
quelle
5

.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 snippetum den Effekt zu sehen. (PS: Wenn Run code snippetes nicht funktioniert, versuchen Sie Folgendes: https://jsfiddle.net/Yeshen/xm2yLksu/3/ )

  2. Wie es funktioniert:

Der Standardüberlauf ist das Scrollen von oben nach unten.

transform: rotate(180deg) kann den dynamischen Block von unten nach oben scrollen oder laden.

  1. Originale Idee:

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

yisheng wu
quelle
Bitte fügen Sie weitere Erklärungen hinzu, wie Ihr Code die Frage des OP löst
jro
1, hat eine zusätzliche Einführung hinzugefügt. 2, Bitte Run code snippetsehen Sie direkt den Effekt.
Yisheng Wu
Die Schaltfläche zum Ausführen des Code-Snippets wird für mich nicht angezeigt. Überprüfen Sie Ihre Formatierung
jro
Das ist großartig. Bitte
fügen
2
Sehr kreative Lösung. Es kehrt jedoch den normalen Betrieb des Mausrads um. Um nach oben zu gehen, muss ich "nach unten" scrollen und umgekehrt.
Mfluehr
3
$('#yourDivID').animate({ scrollTop: $(document).height() }, "slow");
return false;

Dadurch wird die ScrollTop-Position aus der Höhe der #yourDivIDVerwendung der $(document).height()Eigenschaft berechnet, sodass sich der Scroller auch dann an der unteren Position befindet, wenn dem div dynamische Inhalte hinzugefügt werden. Hoffe das hilft. Aber es hat auch einen kleinen Fehler, selbst wenn wir nach oben scrollen und den Mauszeiger vom Scroller lassen, wird es automatisch an die unterste Position gebracht. Wenn jemand das auch korrigieren könnte, wäre es schön.

Krishnadas PC
quelle
2
//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;

Hier ist meine Version basierend auf der Antwort von dotnetCarpenter. Mein Ansatz ist eine reine jQuery und ich habe die Variablen benannt, um die Dinge ein bisschen klarer zu machen. Was passiert, ist, wenn die Inhaltshöhe größer ist als der Container, den wir den zusätzlichen Abstand nach unten scrollen, um das gewünschte Ergebnis zu erzielen.

Funktioniert in IE und Chrome ..

KingOfDaNorth
quelle
2

Die Antwort von Jim Hall ist vorzuziehen, da sie beim Scrollen zwar nicht nach unten scrollt, aber auch reines CSS ist.

Leider ist dies jedoch keine stabile Lösung: In Chrome (möglicherweise aufgrund des von dotnetCarpenter oben beschriebenen 1-px-Problems) scrollTopverhält es sich auch ohne Benutzerinteraktion (beim Hinzufügen von Elementen) um 1 Pixel ungenau. Sie können festlegen scrollTop = scrollHeight - clientHeight, aber das hält das div in Position, wenn ein anderes Element hinzugefügt wird, auch bekannt als die Funktion "Selbst unten bleiben" funktioniert nicht mehr.

Kurz gesagt, wenn Sie eine kleine Menge Javascript (Seufzer) hinzufügen, wird dies behoben und alle Anforderungen erfüllt:

So etwas wie https://codepen.io/anon/pen/pdrLEZ this (Beispiel von Coo) und nach dem Hinzufügen eines Elements zur Liste auch das Folgende:

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

Dabei ist 29 die Höhe einer Linie.

Wenn der Benutzer eine halbe Zeile nach oben scrollt (wenn das überhaupt möglich ist?), Ignoriert das Javascript diese und scrollt nach unten. Aber ich denke, das ist vernachlässigbar. Und es behebt das Chrome 1 px-Ding.

phil294
quelle
2

Hier ist eine Lösung, die auf einem Blogbeitrag von Ryan Hunt basiert . Dies hängt von der overflow-anchorCSS-Eigenschaft ab, mit der die Bildlaufposition an ein Element am unteren Rand des Bildlaufinhalts angehängt wird.

const messages = [
  'Expect rain today.',
  'Tomorrow will be sunny.',
  'Snow is coming next week.',
  'Hailstorms are imminent.',
];

function addMessage() {
  const $message = document.createElement('div');
  $message.className = 'message';
  $message.innerText = messages[(Math.random() * messages.length) | 0];
  $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>

Beachten Sie, dass overflow-anchordies derzeit nicht in Safari oder Edge funktioniert, sodass diese Lösung derzeit nicht in allen Browsern funktioniert.

mfluehr
quelle
1

Sie können so etwas verwenden,

var element = document.getElementById("yourDivID");
window.scrollTo(0,element.offsetHeight);
Yashesh Chauhan
quelle
Erklären Sie es bitte!
Szabolcs Páll
1.scrollTo ist eine Methode, mit der das gesamte Fenster zu bestimmten Koordinaten gescrollt wird.2.offsetHeight gibt die Höhe Ihres Elements an, sodass die zweite Zeile des obigen Codes das Fenster weiter nach unten scrollt, während Sie etwas zuweisen.
Yashesh Chauhan
0

Hier ist, wie ich es angegangen bin. Meine Div-Höhe beträgt 650px. Ich entschied, dass wenn die Bildlaufhöhe innerhalb von 150px vom Boden liegt, automatisch gescrollt wird. Andernfalls überlassen Sie es dem Benutzer.

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