Gardez la div de débordement défilée vers le bas, sauf si l'utilisateur fait défiler vers le haut

223

J'ai un div qui ne fait que 300 pixels de large et je le souhaite lorsque la page se charge, faites défiler vers le bas du contenu. Ce div a du contenu ajouté dynamiquement et doit rester défilé jusqu'en bas. Maintenant, si l'utilisateur décide de faire défiler vers le haut, je ne veux pas qu'il revienne en bas jusqu'à ce que l'utilisateur défile à nouveau vers le bas

Est-il possible d'avoir un div qui restera défilé vers le bas à moins que l'utilisateur ne fasse défiler vers le haut et lorsque l'utilisateur défile vers le bas, il doit se maintenir en bas même lorsqu'un nouveau contenu dynamique est ajouté. Comment pourrais-je aller créer ceci.

Robert E. McIntosh
la source
1
utilisez la position css en haut, gardez-la en bas {position : relative; bottom:0;}. Supprimez la propriété css une fois que l'utilisateur a fait défiler.
TCHdvlp
comme vous n'avez pas accepté de réponse, je veux vous demander: cela a-t-il fonctionné pour vous?
Mr.Manhattan
4
Cela ressemble à une boîte de discussion que vous souhaitez accomplir
Thielicious
1
Pour les nouveaux à cette question, devrait essayer css snap en 2020 .
wener

Réponses:

136

Cela pourrait vous aider:

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

[EDIT], pour correspondre au commentaire ...

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

chaque fois que du contenu est ajouté, appelez la fonction updateScroll () ou réglez une minuterie:

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

si vous souhaitez mettre à jour UNIQUEMENT si l'utilisateur n'a pas bougé:

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

$("#yourDivID").on('scroll', function(){
    scrolled=true;
});
Mr.Manhattan
la source
3
Cela fait bien défiler vers le bas lors du chargement de la page, mais j'en ai besoin pour rester en bas lorsque du contenu dynamique est ajouté, sauf si l'utilisateur a fait défiler vers le haut.
Robert E. McIntosh
12
Pour autant que je sache, cela ne permet pas de réactiver le défilement dynamique lorsque l'utilisateur fait défiler vers le bas ...
TvE
@TvE ne pourrait-on pas ajouter ce support?
Barkermn01
6
Mauvaise solution. Il n'y a aucune raison d'ajouter un setIntervalpour ce léger problème.
ethancrist
6
@ethancrist cependant, vous n'offrez aucune alternative ... hausse les épaules.
Jarett Lloyd
180

J'ai pu faire fonctionner cela avec CSS uniquement.

L'astuce consiste à utiliser display: flex;etflex-direction: column-reverse;

Le navigateur traite le bas comme le haut. En supposant que les navigateurs que vous ciblez prennent en charge flex-box, la seule mise en garde est que le balisage doit être dans l'ordre inverse.

Voici un exemple de travail. https://codepen.io/jimbol/pen/YVJzBg

Jim Hall
la source
42
Vous pouvez contourner le besoin d'inverser le contenu en ajoutant un wrapper supplémentaire et en appliquant overflow:auto; display:flex; flex-direction:column-reverse;au wrapper externe au lieu du wrapper interne.
Nathan Arthur
6
probablement la meilleure solution car elle n'a pas besoin de javascript.
Amit Kumar Khare
3
@NathanArthur u da real mvp
php_nub_qq
13
@NathanArthur En fait, si vous ajoutez simplement un div sous le conteneur pour tout inverser: codepen.io/anon/pen/pdrLEZ
Coo
6
Malheureusement, cette solution ne semble pas fonctionner dans Firefox :(
Stuart
166

Je viens de l'implémenter et vous pouvez peut-être utiliser mon approche.

Disons que nous avons le code HTML suivant:

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

Ensuite, nous pouvons vérifier s'il a défilé vers le bas avec:

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

scrollHeight vous donne la hauteur de l'élément, y compris toute zone non visible en raison d'un débordement. clientHeight vous donne la hauteur CSS ou dit d'une autre manière, la hauteur réelle de l'élément. Les deux méthodes renvoient la hauteur sans margin, vous n'avez donc pas à vous en soucier. scrollTop vous donne la position du défilement vertical. 0 est le haut et max est le scrollHeight de l'élément moins la hauteur de l'élément lui-même. Lorsque vous utilisez la barre de défilement, il peut être difficile (c'était dans Chrome pour moi) de descendre la barre de défilement jusqu'en bas. j'ai donc ajouté une inexactitude de 1px. Il en isScrolledToBottomsera de même même si la barre de défilement est à 1 px du bas. Vous pouvez définir ce paramètre comme bon vous semble.

Il suffit ensuite de régler le scrollTop de l'élément au bas.

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

J'ai fait un violon pour vous montrer le concept: http://jsfiddle.net/dotnetCarpenter/KpM5j/

EDIT: extrait de code ajouté pour préciser quand isScrolledToBottomest true.

Collez la barre de défilement vers le bas

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
la source
22
C'est en fait la seule solution qui répond à la question posée. Et aurait dû être marqué comme la bonne réponse.
preezzzy
1
@dotnetCarpenter: Il me semble que vous en avez besoin if(!isScrolledToBottom): le test me semble faux (et n'a pas fonctionné dans mon code jusqu'à ce que je le corrige).
luskwater
1
@luskwater pouvez-vous fournir à un fsfiddle votre correctif? Je ne comprends pas le problème avec out.scrollHeight - out.clientHeight <= out.scrollTop + 1. Utilisez-vous un remplissage dans votre CSS?
dotnetCarpenter
2
C'est ce que je cherchais. Et, c'est la réponse à la question posée par OP. Merci dotnetCarperter.
Luis Menjivar
1
Si quelqu'un obtient 0 quand il appelle scrollTop, je suggère d'utiliser document.getScrollingElementcomme suggéré ici: stackoverflow.com/questions/36227559/scrolltop-always-returns-0/…
Dane Jordan
29
$('#yourDiv').scrollTop($('#yourDiv')[0].scrollHeight);

Démo en direct: http://jsfiddle.net/KGfG2/

Alvaro
la source
4
Cela fait bien défiler vers le bas lors du chargement de la page, mais j'en ai besoin pour rester en bas lorsque du contenu dynamique est ajouté, sauf si l'utilisateur a fait défiler vers le haut.
Robert E. McIntosh
Cela fonctionne parfaitement. Je mets à jour avec un contenu dynamique et le défilement est toujours en bas.
Andy Bajka
14
$('#div1').scrollTop($('#div1')[0].scrollHeight);

Or animated:

$("#div1").animate({ scrollTop: $('#div1')[0].scrollHeight}, 1000);
Sasidharan
la source
1
Cela fait bien défiler vers le bas lors du chargement de la page, mais j'en ai besoin pour rester en bas lorsque du contenu dynamique est ajouté, sauf si l'utilisateur a fait défiler vers le haut.
Robert E. McIntosh
Cela ne fonctionne pas lorsque div grandit beaucoup au premier coup. par exemple dans Angular-js, react js, Meteor Blaze template loading, cela ne fonctionnera pas.
Ankur Soni
Cela a fonctionné pour moi. Je pense que cela fonctionne bien si le div en question va rester une hauteur constante. Je ne l'ai pas testé avec des hauteurs dynamiques.
doij790
11

En 2020, vous pouvez utiliser l' accrochage css , mais avant Chrome 81, le changement de disposition ne déclenchera pas de réaccrochage , une interface utilisateur de chat css pure fonctionne sur Chrome 81, vous pouvez également vérifier Puis-je utiliser l'accrochage CSS .

Cette démo va casser le dernier élément s'il est visible, faites défiler vers le bas pour voir l'effet.

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

entrez la description de l'image ici

wener
la source
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 snippetpour voir l'effet. (PS: si cela Run code snippetne fonctionne pas, essayez ceci: https://jsfiddle.net/Yeshen/xm2yLksu/3/ )

  2. Comment ça marche:

Le débordement par défaut est le défilement de haut en bas.

transform: rotate(180deg) peut le faire défiler ou charger un bloc dynamique de bas en haut.

  1. Idée originale:

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

yisheng wu
la source
S'il vous plaît ajouter plus d' explications sur la façon dont votre code permet de résoudre la question de l'OP
JRO
1, a ajouté une introduction supplémentaire. 2, veuillez Run code snippetvoir directement l'effet.
yisheng wu
Le bouton d'extrait de code d'exécution ne s'affiche pas pour moi. Vérifiez votre formatage
jro
C'est génial. Veuillez inclure le lien dans votre réponse
jro
2
Solution très créative. Cependant, il inverse le fonctionnement normal de la molette de défilement de ma souris. Pour monter, je dois faire défiler "vers le bas" et vice versa.
mfluehr
3
$('#yourDivID').animate({ scrollTop: $(document).height() }, "slow");
return false;

Cela calculera la position ScrollTop à partir de la hauteur d' #yourDivIDutilisation de la $(document).height()propriété, de sorte que même si du contenu dynamique est ajouté à la division, le défilement sera toujours en position basse. J'espère que cela t'aides. Mais il a aussi un petit bug même si on fait défiler vers le haut et laisse le pointeur de la souris du scroller il arrivera automatiquement en position basse. Si quelqu'un pouvait aussi corriger cela, ce serait bien.

Krishnadas PC
la source
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;

Voici ma version basée sur la réponse de dotnetCarpenter. Mon approche est une pure jQuery et j'ai nommé les variables pour rendre les choses un peu plus claires.

Fonctionne dans IE et chrome ..

KingOfDaNorth
la source
2

La réponse de Jim Hall est préférable car bien qu'elle ne défile pas vers le bas lorsque vous faites défiler vers le haut, elle est également pure CSS.

Malheureusement, ce n'est pas une solution stable: dans Chrome (peut-être en raison du problème de 1 px décrit par dotnetCarpenter ci-dessus), scrollTopse comporte de manière inexacte de 1 pixel, même sans interaction de l'utilisateur (lors de l'ajout d'élément). Vous pouvez définir scrollTop = scrollHeight - clientHeight, mais cela gardera la div en position lorsqu'un autre élément est ajouté, alias la fonction "se garder en bas" ne fonctionne plus.

Donc, en bref, l'ajout d'une petite quantité de Javascript (soupir) résoudra cela et remplira toutes les conditions:

Quelque chose comme https://codepen.io/anon/pen/pdrLEZ this (exemple par Coo), et après avoir ajouté un élément à la liste, également ce qui suit:

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

où 29 est la hauteur d'une ligne.

Ainsi, lorsque l'utilisateur fait défiler une demi-ligne (si c'est possible?), Le Javascript l'ignore et défile vers le bas. Mais je suppose que c'est négligeable. Et, il corrige le truc Chrome 1 px.

phil294
la source
2

Voici une solution basée sur un article de blog de Ryan Hunt . Cela dépend de la overflow-anchorpropriété CSS, qui épingle la position de défilement à un élément au bas du contenu défilé.

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>

Notez que overflow-anchorcela ne fonctionne pas actuellement dans Safari ou Edge, donc cette solution ne fonctionne pas actuellement dans tous les navigateurs.

mfluehr
la source
1

Vous pouvez utiliser quelque chose comme ça,

var element = document.getElementById("yourDivID");
window.scrollTo(0,element.offsetHeight);
Yashesh Chauhan
la source
Expliquez-le s'il vous plaît!
Szabolcs Páll
1.scrollTo est une méthode qui fait défiler toute la fenêtre jusqu'à des coordonnées particulières.
Yashesh Chauhan
0

Voici comment je l'ai abordé. Ma hauteur de div est de 650 pixels. J'ai décidé que si la hauteur de défilement est à moins de 150 px du bas, faites-la défiler automatiquement. Sinon, laissez-le à l'utilisateur.

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