Не допускати прокручування діва вгору, коли наткнувся на дів під ним?


10

Я вчора поставив подібне запитання, але пояснив це погано і не вказав на своє бажання чистого CSS рішення, яке, на мою думку, повинно бути можливим, тому я намагаюся знову.

В основному, у мене є проблема, де у мене є розділ прокручуваних повідомлень та поле введення під ним. Коли я натискаю кнопку, я б хотів, щоб поле введення збільшилося на 100 пікселів, не маючи також прокрутки розділів повідомлень.

Ось загадка, яка демонструє проблему в повному обсязі

Як бачите, при натисканні на кнопку "Додати маржина" також повідомлення прокручується вгору. Я хотів би, щоб він залишився там, де був. Аналогічно, якщо ви злегка прокручені вгору, щоб ви могли бачити лише друге до останнього повідомлення, натискання на кнопку також має зберегти цю позицію після натискання.

Цікавим є те, що така поведінка «іноді» зберігається. Наприклад, за деяких обставин (які я не можу зовсім зрозуміти) позиція прокрутки зберігається. Мені б просто хотілося, щоб він постійно поводився як такий.

window.onload = function(e) {
  document.querySelector(".messages").scrollTop = 10000;
};

function test() {
  document.querySelector(".send-message").classList.toggle("some-margin");
}
.container {
     width: 400px;
     height: 300px;
     border: 1px solid #333;
     display: flex;
     flex-direction: column;
}
 .messages {
     overflow-y: auto;
     height: 100%;
}
 .send-message {
     width: 100%;
     display: flex;
     flex-direction: column;
}
 .some-margin {
     margin-bottom: 100px;
}
<div class="container">
   <div class="messages">
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
   </div>
   <div class="send-message">
      <input />
   </div>
</div>
<button onclick="test()">add margin</button>

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


1
Привіт ще раз, я відповів на ваше запитання за допомогою JS. Я хотів би повідомити вас про те, що ви, можливо, неправильно трактували. Ви згадали: також повідомлення прокручується вгору . Власне, це не те, divщо прокручується вгору, це висота діва, яка зменшується. То чому це має значення? Що ж, це означає, що scrollbarце не коригує свою позицію. Панель прокрутки запам'ятовує лише її положення відносно верхньої частини контейнера. Коли висота Div зменшується, здається, що смуга прокрутки прокручується вгору, але насправді це не так.
Річард

1
Ваша публікація має ідеальний сенс (в тому сенсі, що люди знають, якого результату ви хочете), але я просто ділюсь чимось у тому випадку, якщо це знання вам не видно (на випадок, якщо це може допомогти вам прийти до ідеї вирішити сказана проблема) ;-)
Річард

Так, правда, дякую за пояснення. Це лише "схоже", як прокручування вгору, тому що ви не можете бачити нижній вміст, який ви могли колись. Насправді позиція прокрутки не змінюється. Трохи ілюзії. Так, це може допомогти знайти рішення.
Райан Пешель

Відповіді:


5

Це смішне рішення, яке вам може сподобатися.

Що ми знаємо про div, що він зберігає лише верхнє положення смуги прокрутки, тому якщо висота зміниться через будь-яку причину, смуга прокрутки залишиться такою ж, і саме це викликає вашу проблему.

Як вирішення, ви можете перевернути на .messages180 градусів за допомогою transform: rotate(180deg) scaleX(-1);та повернути назад, .messageщоб скасувати гортання вмісту, тоді div буде підтримувати нижню панель прокрутки (яка вгорі) автоматично.

function test() {
  document.querySelector(".send-message").classList.toggle("some-margin")
}
.container {
  width: 400px;
  height: 300px;
  border: 1px solid #333;
  display: flex;
  flex-direction: column;
}

.messages {
  overflow-y: auto;
  height: 100%;
  transform: rotate(180deg) scaleX(-1);
}

.message
{
  transform: rotate(180deg) scaleX(-1);
}
.send-message {
  width: 100%;
  display: flex;
  flex-direction: column;
}

.some-margin {
  margin-bottom: 100px;
}
<div class="container">
  <div class="messages">
  <div class="message">hello1</div>
  <div class="message">hello2</div>
  <div class="message">hello3</div>
  <div class="message">hello4</div>
  <div class="message">hello5</div>
  <div class="message">hello6</div>
  <div class="message">hello7</div>
  <div class="message">hello8</div>
  <div class="message">hello9</div>
  <div class="message">hello10</div>
  <div class="message">hello11</div>
  <div class="message">hello12</div>
  <div class="message">hello13</div>
  <div class="message">hello14</div>
  <div class="message">hello15</div>
  <div class="message">hello16</div>
  <div class="message">hello17</div>
  <div class="message">hello18</div>
  <div class="message">hello19</div>
  <div class="message">hello20</div>
  </div>
  <div class="send-message">
  <input />
  </div>
</div>

<button onclick="test()">add margin</button>


Тут виникає проблема, коли прокрутка мишоподібного колеса повертається назад (прокрутка вгору знижується, а прокрутка вниз йде вгору)
Райан Пешель

Гаразд, я витратив багато часу на це, але все ж зараз інші розробники мають 3 відповіді, яких ви не шукаєте :) Я сподівався допомогти вам побажати вам удачі. але як рекомендація, яка витрачає час, намагаючись відповісти на ваше запитання, вам не стягуватиметься.
Василь

2
Певна річ. Все одно дякую
Райан Пешель

Це дуже розумно ;-) На жаль, перевернута прокрутка трохи відхиляє.
Річард

3

Нормальна поведінка смуги прокрутки, щоб вона знаходилася вгорі, тому коли ви встановлюєте її внизу при завантаженні сторінки, ви повинні підтримувати її, оскільки коли-небудь нижчий вміст її натискає, то дірка прокрутки переміститься на верх.

Тож у мене є два рішення для вас:

  1. Зворотній бік повідомлень всередині div повідомлень, щоб останнє повідомлення було першим, тому прокрутка завжди буде вгорі.

  2. Я створив функцію javascript, щоб прокрутити її донизу будь-якого елемента, тому ви просто викликаєте його, коли хочете прокрутити його донизу.

function scrollbottom(e)
    {
      e.scrollTop = e.clientHeight;
    }

Перевірте фрагмент

var elem = document.querySelector(".messages");

window.onload = function(e){ 
  scrollbottom(elem);
}

function test() {
  document.querySelector(".send-message").classList.toggle("some-margin");
  scrollbottom(elem);
}

function scrollbottom(e)
{
  e.scrollTop = e.clientHeight;
}
.container {
  width: 400px;
  height: 300px;
  border: 1px solid #333;
  display: flex;
  flex-direction: column;
}

.messages {
  overflow-y: auto;
  height: 100%;
}

.send-message {
  width: 100%;
  display: flex;
  flex-direction: column;
}

.some-margin {
  margin-bottom: 100px;
}
<div class="container">
  <div class="messages">
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  </div>
  <div class="send-message">
  <input />
  </div>
</div>

<button onclick="test()">add margin</button>


На жаль, я не хочу прокручувати, а просто прокручувати донизу. Я хочу зберегти своє становище. Крім того, цілком ймовірно, що це можна зробити без Javascript. З ОП: "Аналогічно, якщо ви злегка прокручуються вгору, щоб ви могли бачити лише повідомлення" Друге до останнього ", натискання кнопки має аналогічно зберегти це місце при натисканні."
Райан Пешель

3

Ви можете це зробити навпаки, додавши висоту .messages замість того, щоб давати його .containerв цьому випадку, це не вплине на повідомлення, divале якщо ви будете надавати його, .containerвін підштовхне ваш дів, тому що поле знаходиться всередині основного div, які мають висоту.

Перевірте цей фрагмент

function test() {
  document.querySelector(".send-message").classList.toggle("some-margin");
}
.container {
  width: 400px;
  border: 1px solid #333;
  display: flex;
  flex-direction: column;
}

.messages {
  height: 300px;
  overflow-y: auto;
}

.send-message {
  width: 100%;
  display: flex;
  flex-direction: column;
}

.some-margin {
  margin-bottom: 50px;
}
<div class="container">
  <div class="messages">
  <div class="message">hello1</div>
  <div class="message">hello2</div>
  <div class="message">hello3</div>
  <div class="message">hello4</div>
  <div class="message">hello5</div>
  <div class="message">hello6</div>
  <div class="message">hello7</div>
  <div class="message">hello8</div>
  <div class="message">hello9</div>
  <div class="message">hello10</div>
  <div class="message">hello11</div>
  <div class="message">hello12</div>
  <div class="message">hello13</div>
  <div class="message">hello14</div>
  <div class="message">hello15</div>
  <div class="message">hello16</div>
  <div class="message">hello17</div>
  <div class="message">hello18</div>
  <div class="message">hello19</div>
  <div class="message">hello20</div>
  </div>
  <div class="send-message">
  <input />
  </div>
</div>

<button onclick="test()">add margin</button>


Це не працює, оскільки до нього потрібно застосувати маржу .send-message. Якщо ви подивитесь на моє попереднє запитання, це зроблено, тому що це схоже на відмінність поля від відкриття віртуальної клавіатури на мобільних пристроях (нижнє поле - це лише заміна 1: 1 для налагодження рішення)
Райан Пешель

3

Простий спосіб вирішити - встановити попередній scrollTopрежим перемикання. Тут я використовую набір даних для зберігання попереднього scrollTopзначення, ви можете використовувати змінну.

window.onload = function(e) {
  document.querySelector(".messages").scrollTop = 10000;
}

function test() {
  let state = document.querySelector(".send-message").classList.toggle("some-margin")
  let div = document.querySelector(".messages");

  if (state) {
    div.dataset.top = div.scrollTop;
    div.scrollTop += 100 // same as margin-bottom of .some-margin
  } else {
    div.scrollTop = div.dataset.top;
  }
}
.container {
  width: 400px;
  height: 300px;
  border: 1px solid #333;
  display: flex;
  flex-direction: column;
}

.messages {
  overflow-y: auto;
  height: 100%;
}

.send-message {
  width: 100%;
  display: flex;
  flex-direction: column;
}

.some-margin {
  margin-bottom: 100px;
}
<div class="container">
  <div class="messages">
    <div class="message">hello1</div>
    <div class="message">hello2</div>
    <div class="message">hello3</div>
    <div class="message">hello4</div>
    <div class="message">hello5</div>
    <div class="message">hello6</div>
    <div class="message">hello7</div>
    <div class="message">hello8</div>
    <div class="message">hello9</div>
    <div class="message">hello10</div>
    <div class="message">hello11</div>
    <div class="message">hello12</div>
    <div class="message">hello13</div>
    <div class="message">hello14</div>
    <div class="message">hello15</div>
    <div class="message">hello16</div>
    <div class="message">hello17</div>
    <div class="message">hello18</div>
    <div class="message">hello19</div>
    <div class="message">hello20</div>
  </div>
  <div class="send-message">
    <input />
  </div>
</div>

<button onclick="test()">add margin</button>


0

Я маю на увазі, наступне - це лише CSS-рішення, яке вирішує саме ваш приклад:

.some-margin{margin-bottom:100px;}

.messages{margin-top:-100px;}

але я не думаю, що це допоможе вам у вирішенні первісної проблеми віртуальної клавіатури. Але, можливо, це може надихнути когось іншого на рішення.

Основна проблема, здається, полягає в тому, що смуга прокрутки вже робить саме те, що ви хочете:

Збереження своєї позиції, щоб було видно останній час прочитаний вміст.

За винятком того, що смуга прокрутки вирішує, що ви хотіли бачити ТОП поточного видимого вмісту, а не нижню частину. (Простіше зрозуміти, чи використовуєте ви цифри: https://jsfiddle.net/1co3x48n/ )

Якщо ви готові використовувати javascript, є всілякі відповіді: https://www.google.com/search?q=scrollbar+always+on+bottom+css+site:stackoverflow.com

Чесно кажучи, той факт, що ви можете пройти ~ 3 + сторінки цієї сторінки та знайти лише відповіді на Javascript, говорить про те, що ви не збираєтесь знайти відповідь, що відповідає лише CSS, звичайно не та, яка широко сумісна з браузером.


0

Жодне із запропонованих рішень, на жаль, не працює, на жаль. Проблема використання onFocusтекстового поля полягає в тому, що воно не застосовуватиметься, якщо текстове поле вже має фокус. Я годинами возився з цим, і найближче рішення, яке я придумав поки що, це:

componentDidMount() {
  this.screenHeight = window.innerHeight;

  let chatElem = document.querySelector(".conversations-chat");

  window.addEventListener('resize', () => {
    let diff = this.screenHeight - window.innerHeight;

    chatElem.scrollTop += diff;

    this.screenHeight = window.innerHeight;      
  });
}

Однак це, здається, іноді спрацьовує. Він працює 100% часу при натисканні на текстове поле, але чомусь при закритті віртуальної клавіатури він працює лише в тому випадку, якщо він був прокручений досить вгору. В іншому випадку він щоразу скидається в одне і те ж положення (біля нижнього, але не зовсім нижнього).

Не впевнений, що це викликає. Я думаю, завтра доведеться розслідувати більше. Це найближчий поки що.


Як ми всі говорили у своїх відповідях, здається, що неможливо зробити лише лише CSS. (Існує проблема з вашим кодом JS, який полягає в тому, що chatElem.scrollTop не може бути менше 0 , тому якщо він занадто близько до верху, він намагається стати від'ємним числом, натомість стає 0, тоді коли ви зробите екран більше знову з’являється сувій, де раніше не було.)
Еліезер Берлін,

З іншого боку, chatElem.scrollTop не може бути більше, ніж chatElem.scrollHeight - chatElem.offsetHeight , тому він створить додаткову прокрутку там, де раніше її не було, якщо ви спробуєте це зробити.
Eliezer Berlin

0

Створіть контейнер, як у наведених вище прикладах, але тоді просто змініть CSS, коли ви почнете вводити текст.

Я не встановлюю положення смуги прокрутки, просто переміщую весь контейнер повідомлень вгору. Тож, яким би не був ваш список прокрутки, залишиться колишнім. Принаймні вниз, звичайно, ви не зможете побачити рядки вгорі.

Ви повинні мати можливість налаштувати CSS на свої потреби. Ви можете навіть без JS, якщо використовуєте: фокус або дещо інше налаштування CSS, будьте креативні :)

function activate(){
    document.querySelector("#container").classList.toggle("active");
  }
#container{
    position:relative;
    width:300px;
    height:100vh;
    max-height:230px;
    overflow:hidden;
  }
  #messages{
    position:absolute;
    bottom:30px;
    overflow:auto;
    height:200px;
    width:100%;
    background:#eee;
  }
  #container.active #messages {
    bottom:100px;
  }
  #send-message{
    position:absolute;
    border:1px solid #ccc;
    bottom:0;
    height:28px;
  }
  #container.active #send-message{
    height:100px;
  }
<div id="container">
  <div id="messages">
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  </div>
  <div id="send-message">
    <input id="newmessage" onclick="activate()" type="text" />
  </div>
</div>


0

Ви повинні додати document.querySelector(".messages").scrollTop = 10000;до testфункції , коли додатковий запас потім scrollTopперейти до кінця навантаження ви встановлюєте scrolltopі при додаванні поля або запас видалити scrolltopне встановлено знову змінити вам скрипт, як це

<script>
    window.onload = function(e){ 
    document.querySelector(".messages").scrollTop = 10000;
}

function test() {
    document.querySelector(".send-message").classList.toggle("some-margin")
            document.querySelector(".messages").scrollTop = 10000;
}
    </script>

0

Здається, є проблема з функцією перемикання js. Я змінив це на просте приховування та шоу. Також я додав ширину на вхідний тег. Вам також потрібно додати позицію: абсолютну на адресу відправлення повідомлення і знизу: 0, щоб вона залишалася внизу. потім розмістіть позицію: відносно контейнера, щоб div відправлене повідомлення залишалося в контейнері. Це означає, що контейнер повідомлень не вплине на самі повідомлення і не підштовхне їх.

window.onload = function(e) {
  document.querySelector(".messages").scrollTop = 10000;
};

function test() {
  var x = document.querySelector(".send-message");

  if (x.style.display === "none") {
    x.style.display = "block";
  } else {
    x.style.display = "none";
  }
}
.container {
     width: 400px;
     height: 300px;
     border: 1px solid #333;
     display: flex;
     flex-direction: column;
     position: relative;
}
 .messages {
     overflow-y: auto;
     height: 100%;
}
 .send-message {
     width: 100%;
     display: flex;
     flex-direction: column;
     position: absolute;
     bottom: 0;
}
 .send-message input {
     width:100%;
}
 .some-margin {
     margin-bottom: 100px;
}

 
 
<div class="container">
   <div class="messages">
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">test</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
   </div>
   <div class="send-message">
      <input />
   </div>
</div>
<button onclick="test()">add margin</button>


Я не розумію цього рішення. Це, здається, приховує текстове поле відправки, коли натискаєте кнопку "Додати маржу"?
Райан Пешель

-1

Чистий недосконалий підхід CSS, який я можу придумати, полягає в наступному:

window.onload = function(e){ 
  document.querySelector(".messages").scrollTop = 10000;
}

document.querySelector('button').addEventListener('click', test)

function test() {
  document.querySelector(".send-message").classList.toggle("some-margin")
  document.querySelector('.wrapper').classList.toggle('wrapper--transformed')
}
.container {
  width: 400px;
  height: 300px;
  border: 1px solid #333;
  display: flex;
  flex-direction: column;
}

.messages {
  position: relative;
  overflow-y: auto;
  height: 100%;
}

.wrapper {
  display: block;
}

.wrapper--transformed {
  transform: translateY(-100px);
  margin-bottom: -100px;
}

.send-message {
  width: 100%;
  display: flex;
  flex-direction: column;
}

.some-margin {
  margin-bottom: 100px;
}
<div class="container">
  <div class="messages">
    <div class = "wrapper">
      <div class="message">hello1</div>
      <div class="message">hello2</div>
      <div class="message">hello3</div>
      <div class="message">hello4</div>
      <div class="message">hello5</div>
      <div class="message">hello6</div>
      <div class="message">hello7</div>
      <div class="message">hello8</div>
      <div class="message">hello9</div>
      <div class="message">hello1</div>
      <div class="message">hello2</div>
      <div class="message">hello3</div>
      <div class="message">hello4</div>
      <div class="message">hello5</div>
      <div class="message">hello6</div>
      <div class="message">hello7</div>
      <div class="message">hello8</div>
      <div class="message">hello9</div>
      <div class="message">hello1</div>
      <div class="message">hello2</div>
    </div>
  </div>
  <div class="send-message">
    <input />
  </div>
</div>
<button>add margin</button>

У верхньому розділі є невелика проблема, коли маржа є. Трюк тут полягає у використанні негативної маржі та використанні перекладу для "прокручування вгору" (насправді не прокрутки, просто ілюзія) wrapperдіва.


Питання верхнього розділу - це певна проблема. Крім того, чи передбачає це, знаючи точний розмір мобільної клавіатури, щоб знати, скільки компенсувати? Я не впевнений, чи маю я доступ до цієї інформації.
Райан Пешель

Щоб відповісти на ваше запитання: так. Вищеописана техніка повинна знати точну висоту клавіатури. Однак є способи використання JS для визначення висоти елемента та зміни CSS.
Річард

Як би ви визначили висоту віртуальної клавіатури для мобільних пристроїв?
Райан Пешель

@RyanPeschel Це віртуальна клавіатура - елемент HTML (наприклад div)?
Річард

Я не впевнений, як це закодовано.
Райан Пешель

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.