Mantenga el div de desbordamiento desplazado hacia abajo a menos que el usuario se desplace hacia arriba

223

Tengo un div de solo 300 píxeles de tamaño y quiero que cuando la página se cargue, desplácese hasta la parte inferior del contenido. Este div tiene contenido agregado dinámicamente y debe mantenerse desplazado hasta el fondo. Ahora, si el usuario decide desplazarse hacia arriba, no quiero que salte hacia abajo hasta que el usuario vuelva a desplazarse hacia abajo

¿Es posible tener un div que permanezca desplazado hacia la parte inferior a menos que el usuario se desplace hacia arriba y cuando el usuario retroceda hacia la parte inferior necesita mantenerse en la parte inferior incluso cuando se agrega nuevo contenido dinámico? ¿Cómo haría para crear esto?

Robert E. McIntosh
fuente
1
use css position top y manténgalo en la parte inferior {position : relative; bottom:0;}. Elimine la propiedad css una vez que el usuario tenga desplazamiento.
TCHdvlp
Como no aceptó una respuesta, quiero preguntar: ¿funcionó para usted?
Mr.Manhattan
44
Suena como un chatbox que quieres lograr
Thielicious
1
Para los nuevos en esta pregunta, debería probar css snap en 2020 .
Wener

Respuestas:

136

Esto podría ayudarte:

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

[EDITAR], para que coincida con el comentario ...

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

cada vez que se agrega contenido, llame a la función updateScroll () o configure un temporizador:

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

si desea actualizar SÓLO si el usuario no se movió:

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

$("#yourDivID").on('scroll', function(){
    scrolled=true;
});
Mr.Manhattan
fuente
3
Esto lo desplaza hacia abajo al cargar la página, pero necesito que permanezca en la parte inferior cuando se agrega contenido dinámico a menos que el usuario se haya desplazado hacia arriba.
Robert E. McIntosh
12
Por lo que puedo decir, esto no vuelve a habilitar el desplazamiento dinámico cuando el usuario se desplaza hacia abajo ...
TvE
@TvE, ¿no podríamos agregar ese soporte?
Barkermn01
66
Mala solución No hay razón para agregar setIntervalun problema tan leve como este.
Ethancrist
66
@ethancrist sin embargo, no ofreces alternativa ... encoge de hombros.
Jarett Lloyd el
180

Pude hacer que esto funcionara solo con CSS.

El truco es usar display: flex;yflex-direction: column-reverse;

El navegador trata la parte inferior como si fuera la parte superior. Suponiendo que los navegadores que está buscando son compatibles flex-box, la única advertencia es que el marcado debe estar en orden inverso.

Aquí hay un ejemplo de trabajo. https://codepen.io/jimbol/pen/YVJzBg

Jim Hall
fuente
42
Puede evitar la necesidad de revertir el contenido agregando un envoltorio adicional y aplicando overflow:auto; display:flex; flex-direction:column-reverse;el envoltorio externo en lugar del envoltorio interno.
Nathan Arthur
66
probablemente la mejor solución porque no necesita javascript.
Amit Kumar Khare
3
@NathanArthur u da real mvp
php_nub_qq
13
@NathanArthur De hecho, si solo agrega un div debajo del contenedor para deshacer
Coo
66
Desafortunadamente, esta solución no parece funcionar en Firefox :(
Stuart
166

Acabo de implementar esto y quizás puedas usar mi enfoque.

Digamos que tenemos el siguiente HTML:

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

Luego podemos verificar si se desplazó hacia abajo con:

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

scrollHeight le proporciona la altura del elemento, incluida cualquier área no visible debido al desbordamiento. clientHeight le proporciona la altura CSS o, dicho de otro modo, la altura real del elemento. Ambos métodos devuelven la altura sin margin, por lo que no debe preocuparse por eso. scrollTop le da la posición del desplazamiento vertical. 0 es superior y max es la altura de desplazamiento del elemento menos la altura del elemento en sí. Cuando se usa la barra de desplazamiento, puede ser difícil (para mí estaba en Chrome) obtener la barra de desplazamiento hasta el final. así que agregué una imprecisión de 1px. Entonces isScrolledToBottomserá cierto incluso si la barra de desplazamiento es 1px desde la parte inferior. Puede configurar esto para lo que le parezca correcto.

Entonces es simplemente una cuestión de establecer el scrollTop del elemento en la parte inferior.

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

He hecho un violín para que muestres el concepto: http://jsfiddle.net/dotnetCarpenter/KpM5j/

EDITAR: Fragmento de código agregado para aclarar cuándo isScrolledToBottomes true.

Pegue la barra de desplazamiento hacia abajo

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
fuente
22
Esta es en realidad la única solución que cumple con la pregunta planteada. Y debería haber sido marcado como la respuesta correcta.
preezzzy
1
@dotnetCarpenter: Me parece que lo necesita if(!isScrolledToBottom): la prueba me parece incorrecta (y no funcionó en mi código hasta que lo arreglé).
luskwater
1
@luskwater, ¿puede proporcionar un fsfiddle con su solución? No entiendo el problema con out.scrollHeight - out.clientHeight <= out.scrollTop + 1. ¿Estás usando relleno en tu CSS?
dotnetCarpenter
2
Esto es lo que estaba buscando. Y, esta es la respuesta a la pregunta que hizo OP. Gracias dotnetCarperter.
Luis Menjivar
1
Si alguien obtiene 0 cuando llaman scrollTop, sugiero usar document.getScrollingElementcomo se sugiere aquí: stackoverflow.com/questions/36227559/scrolltop-always-returns-0/…
Dane Jordan
29
$('#yourDiv').scrollTop($('#yourDiv')[0].scrollHeight);

Demostración en vivo: http://jsfiddle.net/KGfG2/

Alvaro
fuente
44
Esto lo desplaza hacia abajo al cargar la página, pero necesito que permanezca en la parte inferior cuando se agrega contenido dinámico a menos que el usuario se haya desplazado hacia arriba.
Robert E. McIntosh
Esto funciona a la perfección. Estoy actualizando con contenido dinámico y el desplazamiento siempre está en la parte inferior.
Andy Bajka
14
$('#div1').scrollTop($('#div1')[0].scrollHeight);

Or animated:

$("#div1").animate({ scrollTop: $('#div1')[0].scrollHeight}, 1000);
Sasidharan
fuente
1
Esto lo desplaza hacia abajo al cargar la página, pero necesito que permanezca en la parte inferior cuando se agrega contenido dinámico a menos que el usuario se haya desplazado hacia arriba.
Robert E. McIntosh
Esto no funciona cuando div crece mucho en el primer disparo. por ejemplo, en Angular-js, react js, Meteor Blaze template loading, esto no funcionará.
Ankur Soni
Esto funcionó para mí. Creo que funciona bien si el div en cuestión se mantendrá a una altura constante. No lo he probado con alturas dinámicas.
doij790
11

En 2020, puede usar css snap , pero antes de Chrome 81 el cambio de diseño no activará el re-snap , una interfaz de usuario de css chat pura funciona en Chrome 81, también puede marcar ¿Puedo usar CSS snap ?

Esta demostración tomará el último elemento si está visible, desplácese hacia abajo para ver el efecto.

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

ingrese la descripción de la imagen aquí

Wener
fuente
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 snippetpara ver el efecto (PD: si Run code snippetno funciona, intente esto: https://jsfiddle.net/Yeshen/xm2yLksu/3/ )

  2. Como funciona:

El desbordamiento predeterminado es desplazarse de arriba a abajo.

transform: rotate(180deg) puede hacer que se desplace o cargue el bloque dinámico de abajo hacia arriba.

  1. Idea original:

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

yisheng wu
fuente
Agregue más explicaciones sobre cómo su código resuelve la pregunta del OP
jro
1, ha agregado una introducción adicional. 2, por favor Run code snippet, vea directamente el efecto.
yisheng wu
El botón Ejecutar fragmento de código no aparece para mí. Compruebe su formato
jro
Eso es genial. Incluya el enlace en su respuesta
jro
2
Solución muy creativa. Sin embargo, invierte el funcionamiento normal de la rueda de desplazamiento de mi mouse. Para subir, tengo que desplazarme "hacia abajo" y viceversa.
mfluehr
3
$('#yourDivID').animate({ scrollTop: $(document).height() }, "slow");
return false;

Esto calculará la posición ScrollTop desde la altura de #yourDivIDuso de la $(document).height()propiedad, de modo que incluso si se agregan contenidos dinámicos al div, el desplazador siempre estará en la posición inferior. Espero que esto ayude. Pero también tiene un pequeño error, incluso si nos desplazamos hacia arriba y dejamos el puntero del mouse del desplazador, automáticamente se colocará en la posición inferior. Si alguien pudiera corregir eso, también sería bueno.

Krishnadas PC
fuente
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;

Aquí está mi versión basada en la respuesta de dotnetCarpenter. Mi enfoque es un jQuery puro y nombré las variables para aclarar un poco las cosas. Lo que sucede es que si la altura del contenido es mayor que el contenedor, desplazamos la distancia adicional hacia abajo para lograr el resultado deseado.

Funciona en IE y Chrome.

KingOfDaNorth
fuente
2

La respuesta de Jim Hall es preferible porque, si bien no se desplaza hacia abajo cuando se desplaza hacia arriba, también es CSS puro.

Sin embargo, lamentablemente, esta no es una solución estable: en Chrome (posiblemente debido al problema de 1 px descrito anteriormente por dotnetCarpenter), se scrollTopcomporta de manera incorrecta por 1 píxel, incluso sin interacción del usuario (al agregar el elemento). Puede establecer scrollTop = scrollHeight - clientHeight, pero eso mantendrá el div en posición cuando se agregue otro elemento, es decir, la función "mantenerse en la parte inferior" ya no funciona.

En resumen, agregar una pequeña cantidad de Javascript (suspiro) solucionará esto y cumplirá con todos los requisitos:

Algo así como https://codepen.io/anon/pen/pdrLEZ this (ejemplo de Coo), y después de agregar un elemento a la lista, también lo siguiente:

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

donde 29 es la altura de una línea.

Entonces, cuando el usuario se desplaza hacia arriba media línea (si eso es posible?), El Javascript lo ignorará y se desplazará hacia la parte inferior. Pero supongo que esto es descuidado. Y repara la cosa de Chrome 1 px.

phil294
fuente
2

Aquí hay una solución basada en una publicación de blog de Ryan Hunt . Depende de la overflow-anchorpropiedad CSS, que fija la posición de desplazamiento a un elemento en la parte inferior del contenido desplazado.

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>

Tenga en cuenta que overflow-anchoractualmente no funciona en Safari o Edge, por lo que esta solución no funciona actualmente en todos los navegadores.

mfluehr
fuente
1

Puedes usar algo como esto,

var element = document.getElementById("yourDivID");
window.scrollTo(0,element.offsetHeight);
Yashesh Chauhan
fuente
¡Explícalo por favor!
Szabolcs Páll
1.scrollTo es un método que desplaza toda la ventana a coordenadas particulares. 2. offsetHeight le dará la altura de su elemento para que la segunda línea del código anterior siga desplazando la ventana hacia abajo mientras asigna algo.
Yashesh Chauhan
0

Así es como lo enfoqué. Mi altura div es de 650 px. Decidí que si la altura de desplazamiento está dentro de 150 px de la parte inferior, entonces desplácese automáticamente. De lo contrario, déjelo al usuario.

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