Разработка чата и вертикальный скролл

Недавно разрабатывал WebApps-чат для телеграма и столкнулся с тем, что при добавлении новых сообщений в чат нужно автоматически прокручивать контейнер с сообщениями. В месенджерах и чатах одинаковый, UX 🤷.

“Стандартная” реализация делается с помощью JS и scrollTop. Такие методы решения легко гуглятся, но не о них сегодня речь.

Прокрутка с помощью чистого CSS

Во время поисков решения этой задачи, случайно обнаружил другой метод скроллинга. Метод заключается в использовании чистого CSS 😲 и свойства flex-direction. Этот метод будет работать, если добавить обёртку для содержимого внутри элемента прокрутки.

Хитрость заключается в изменении направления содержимого с помощью значения column-reverse в скроллере. Поскольку элементы в другом контейнере, то они не “переворачиваются”, а вместо этого выстраиваются в линию внизу. Это заставляет скроллер прокручиваться вниз при добавлении контента.

Дополнительный бонус: сохраняется положение прокрутки.

Метод крутой, так как отсутствуют раздражающие скачки при добавлении новых сообщений и, чтобы отслеживать текущую позицию прокрутки, не нужен дополнительный код 🔥.

В случае, если пользователь пролистает сообщения вверх, скроллер не потеряет позицию прокрутки при добавлении новых сообщений. Скроллер будет “прилипать” к нижней части только в том случае, если уже установлен в нижней части, по умолчанию или пользователем.

Демка

Основные стили:

.chat {
    overflow: auto;
    height: 300px;
    display: flex;
    flex-direction: column-reverse;
}

.chat-content {
    padding: 20px;
    max-width: 500px;
    margin: auto;
    width: 100%;
}

.msg {
    position: relative;
    max-width: 75%;
    padding: 7px 15px;
    margin-bottom: 5px;
}

Верстка:

<div class="chat">
    <div class="chat-content">
        <div class="msg sent">Message 1</div>
        <div class="msg rcvd">Message 2</div>
        <div class="msg sent">Message 3</div>
        <div class="msg sent">Message 4</div>
        <div class="msg sent">Message 5</div>
        <div class="msg rcvd">Message 6</div>
        <div class="msg rcvd">Message 7</div>
    </div>
</div>

<br/><br/>
<div class="btn">
    <button id="addItems">Добавить сообщение</button>
</div>

Обработчик кнопки, для добавления новых сообщений:

let chatContent = document.querySelector('.chat-content');

document.getElementById('addItems').addEventListener('click', function() {
    let newMsg = document.createElement('div');
    newMsg.classList.add('msg', (chatContent.children.length % 2) ? 'sent' : 'rcvd');
    newMsg.innerHTML = "Message " + (chatContent.children.length + 1)
    chatContent.appendChild(newMsg);
});

Рабочий пример можно посмотреть на CodePen