Держите переполнение div прокрутки вниз, если пользователь не прокручивает вверх

224

У меня есть div, размер которого составляет всего 300 пикселей, и я хочу, чтобы, когда страница загружается, прокрутите страницу вниз. К этому div динамически добавляется контент, и его необходимо прокручивать до конца. Теперь, если пользователь решит прокрутить вверх, я не хочу, чтобы он прыгал вниз до тех пор, пока пользователь снова не прокрутит весь путь вниз.

Возможно ли иметь div, который будет прокручиваться вниз, если пользователь не прокручивает вверх, а когда пользователь прокручивает обратно вниз, ему нужно оставаться внизу, даже когда добавляется новый динамический контент. Как бы я пошел, создавая это.

Роберт Э. Макинтош
источник
1
используйте позицию css top, держите ее внизу {position : relative; bottom:0;}. Удалите свойство css после прокрутки пользователем.
TCHdvlp
так как вы не приняли ответ, я хочу спросить: он работал для вас?
Мистер Манхэттен
4
Звучит как чат, который вы хотите
создать
1
Для новичков в этом вопросе стоит попробовать css snap в 2020 году .
Wener

Ответы:

136

Это может помочь вам:

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;
});
Mr.Manhattan
источник
3
Это хорошо прокручивает его вниз при загрузке страницы, но мне нужно, чтобы оно оставалось внизу при добавлении динамического контента, если пользователь не прокрутил вверх.
Роберт Э. Макинтош
12
Насколько я могу судить, это не приводит к повторному включению динамической прокрутки, когда пользователь прокручивает назад до дна ...
TvE
@TvE разве мы не можем добавить поддержку?
Barkermn01
6
Плохое решение Там нет причин, чтобы добавить setIntervalдля этой легкой проблемы.
этанкрист
6
@ethancrist, однако, вы не предлагаете альтернативы ... пожимает плечами.
Джаретт Ллойд
180

Я смог заставить это работать только с CSS.

Хитрость заключается в использовании display: flex;иflex-direction: column-reverse;

Браузер рассматривает дно как его верх. Предполагая поддержку браузеров, на которые вы ориентируетесь flex-box, единственное предостережение заключается в том, что разметка должна быть в обратном порядке.

Вот рабочий пример. https://codepen.io/jimbol/pen/YVJzBg

Джим Холл
источник
42
Вы можете обойти необходимость перевернуть содержимое, добавив дополнительную обертку и применив overflow:auto; display:flex; flex-direction:column-reverse;к внешней обертке вместо внутренней обертки.
Натан Артур
6
вероятно, лучшее решение, потому что это не нуждается в JavaScript.
Амит Кумар
3
@NathanArthur у тебя настоящий mvp
php_nub_qq
13
@NathanArthur На самом деле, если вы просто добавляете div под контейнером, чтобы отменить все: codepen.io/anon/pen/pdrLEZ
Coo
6
К сожалению, это решение, похоже, не работает в Firefox :(
Stuart
166

Я только что реализовал это, и, возможно, вы можете использовать мой подход.

Скажем, у нас есть следующий 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 - это верх, а max - это scrollHeight элемента за вычетом высоты самого элемента. При использовании полосы прокрутки может быть трудно (это было в Chrome для меня) получить полосу прокрутки полностью вниз до дна. поэтому я добавил неточность в 1 пиксель. Так isScrolledToBottomбудет верно, даже если полоса прокрутки будет 1px снизу. Вы можете установить это так, как считаете нужным.

Тогда это просто вопрос установки scrollTop элемента внизу.

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

Я сделал скрипку для вас, чтобы показать концепцию: http://jsfiddle.net/dotnetCarpenter/KpM5j/

EDIT: Добавлен фрагмент кода , чтобы выяснить , когда 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
источник
22
На самом деле это единственное решение, которое решает поставленный вопрос. И должен был быть помечен как правильный ответ.
preezzzy
1
@dotnetCarpenter: Мне кажется, что вам нужно if(!isScrolledToBottom): тест выглядит неправильно для меня (и не работал в моем коде, пока я его не исправил).
Luskwater
1
@luskwater Можете ли вы предоставить fsfiddle свое исправление? Я не понимаю проблему с out.scrollHeight - out.clientHeight <= out.scrollTop + 1. Вы используете padding в своем CSS?
dotnetCarpenter
2
Это то, что я искал. И это ответ на вопрос, заданный ОП. Спасибо dotnetCarperter.
Луис
1
Если кто-то получает 0, когда они вызывают scrollTop, я предлагаю использовать, document.getScrollingElementкак предложено здесь: stackoverflow.com/questions/36227559/scrolltop-always-returns-0/…
Дейн Джордан
29
$('#yourDiv').scrollTop($('#yourDiv')[0].scrollHeight);

Живая демоверсия: http://jsfiddle.net/KGfG2/

Alvaro
источник
4
Это хорошо прокручивает его вниз при загрузке страницы, но мне нужно, чтобы оно оставалось внизу при добавлении динамического контента, если пользователь не прокрутил вверх.
Роберт Э. Макинтош
Это работает отлично. Я обновляюсь с динамическим контентом и прокрутка всегда внизу.
Энди Байка
14
$('#div1').scrollTop($('#div1')[0].scrollHeight);

Or animated:

$("#div1").animate({ scrollTop: $('#div1')[0].scrollHeight}, 1000);
Sasidharan
источник
1
Это хорошо прокручивает его вниз при загрузке страницы, но мне нужно, чтобы оно оставалось внизу при добавлении динамического контента, если пользователь не прокрутил вверх.
Роберт Э. Макинтош
Это не работает, когда div сильно растет в первом кадре. например, в Angular-js, реагировать на js, загрузка шаблона Meteor Blaze, это не будет работать.
Анкур Сони
Это сработало для меня. Я думаю, что это прекрасно работает, если рассматриваемый div будет оставаться на постоянной высоте. Не проверял это с динамическими высотами.
doij790
11

В 2020 году вы можете использовать css snap , но до Chrome 81 изменение макета не вызовет повторную привязку , в Chrome 81 работает чистый пользовательский интерфейс css chat , также вы можете проверить, могу ли я использовать CSS snap .

Эта демонстрация будет привязывать последний элемент, если он виден, прокрутите вниз, чтобы увидеть эффект.

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

введите описание изображения здесь

Wener
источник
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 snippetчтобы увидеть эффект. (PS: если Run code snippetне работает, попробуйте это: https://jsfiddle.net/Yeshen/xm2yLksu/3/ )

  2. Как это работает:

Переполнением по умолчанию является прокрутка сверху вниз.

transform: rotate(180deg) Можно сделать прокрутку или загрузить динамический блок снизу вверх.

  1. Оригинальная идея:

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

Ишэн Ву
источник
Пожалуйста, добавьте больше объяснений о том, как ваш код решает вопрос OP
Jro
1, добавил дополнительное введение. 2, пожалуйста Run code snippet, непосредственно увидеть эффект.
yisheng wu
Кнопка фрагмента кода запуска не отображается для меня. Проверьте форматирование
JRO
Замечательно. Пожалуйста,
включите
2
Очень креативное решение. Однако, это полностью изменяет нормальную работу колеса прокрутки моей мыши. Чтобы подняться, мне нужно прокрутить «вниз» и наоборот.
mfluehr
3
$('#yourDivID').animate({ scrollTop: $(document).height() }, "slow");
return false;

Это рассчитает ScrollTop Position из высоты #yourDivIDиспользования $(document).height()свойства, так что даже если динамическое содержимое добавлено в div, скроллер всегда будет в нижней позиции. Надеюсь это поможет. Но он также имеет небольшую ошибку, даже если мы прокручиваем вверх и оставляем указатель мыши на скроллере, он автоматически перейдет в нижнюю позицию. Если кто-то сможет это исправить, это тоже будет хорошо.

Кришнадас ПК
источник
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;

Вот моя версия, основанная на ответе dotnetCarpenter. Мой подход - чистый jQuery, и я назвал переменные, чтобы сделать вещи немного яснее. Что происходит, если высота содержимого больше, чем контейнер, который мы прокручиваем на дополнительное расстояние вниз для достижения желаемого результата.

Работает в IE и Chrome.

KingOfDaNorth
источник
2

Ответ Джима Холла предпочтительнее, потому что, хотя он и не прокручивается до самого дна при прокрутке вверх, это также чистый CSS.

Однако, к сожалению, это нестабильное решение: в chrome (возможно, из-за проблемы 1-px, описанной выше dotnetCarpenter), 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 вещь.

phil294
источник
2

Вот решение, основанное на сообщении в блоге Райана Ханта . Это зависит от overflow-anchorсвойства CSS, которое прикрепляет позицию прокрутки к элементу в нижней части прокручиваемого содержимого.

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>

Обратите внимание, что в overflow-anchorнастоящее время не работает в Safari или Edge, поэтому это решение в настоящее время не работает во всех браузерах.

mfluehr
источник
1

Вы можете использовать что-то вроде этого,

var element = document.getElementById("yourDivID");
window.scrollTo(0,element.offsetHeight);
Яшеш Чаухан
источник
Объясни пожалуйста!
Сабольч Палл
1.scrollTo - это метод, который прокручивает все окно до определенных координат. 2. offsetHeight даст высоту вашего элемента, поэтому вторая строка приведенного выше кода продолжает прокручивать окно вниз, пока вы что-то назначаете.
Яшеш Чаухан
0

Вот как я подошел к этому. Мой рост div составляет 650 пикселей. Я решил, что если высота прокрутки находится в пределах 150px от нижней части, то автоматически прокручиваю ее. Иначе, оставьте это для пользователя.

if (container_block.scrollHeight - container_block.scrollTop < 800) {
                    container_block.scrollTo(0, container_block.scrollHeight);
}
Marco
источник