Как сохранить позицию прокрутки при перемещении элемента

Вопрос или проблема

У меня есть элемент (контейнер) с горизонтальной прокруткой. Например:

<div class="rows">
  <div class="row"></div>
  <div class="row"></div>
  <div class="row"></div>
  <div class="row">
    <div id="container"></div>
  </div>
  <div class="row"></div>
  <div class="row"></div>
  <div class="row"></div>
  <div class="row"></div>
  <div class="row"></div>
</div>

Если переместить элемент в другую строку, горизонтальная прокрутка в контейнере сбросится. Почему это происходит? Как я могу сохранить позицию прокрутки? Возможно ли это исправить только с помощью CSS?

Вот демонстрация:
https://jsbin.com/gugotewane/2/edit?html,css,js,output

Можно воспользоваться трюком. Вы можете сохранить позицию прокрутки перед перемещением в другую строку.

document.getElementById("btn").addEventListener("click", function () {
  const container = document.getElementById("container");
  /* Сохраняя позицию прокрутки */
  const scrollPosition = container.scrollLeft;
  const currentRow = container.parentElement;
  const nextRow = currentRow.nextElementSibling;

  if (nextRow && nextRow.classList.contains("row")) {
    nextRow.appendChild(container);
    /* Устанавливаем позицию прокрутки после перемещения в другую строку */
    container.scrollLeft = scrollPosition;
  }
});

В вашем сниппете JSBin вы манипулируете DOM с помощью Javascript, удаляя одну строку и затем добавляя её в строку ниже. Это заставляет браузер повторно отрисовывать страницу и сбрасывать полосы прокрутки.

Чтобы решить эту проблему (снова на Javascript), вам нужно получить горизонтальную позицию прокрутки перед манипуляцией DOM с помощью:

let hscroll = container.scrollLeft;

А затем повторно применить горизонтальную прокрутку после добавления строки снова с помощью:

container.scrollLeft = hscroll;

где container — это ваш элемент div контейнера.

Причина сброса полос прокрутки (как горизонтальных, так и вертикальных) заключается в том, что браузеры повторно отрисовывают страницу после манипуляции DOM, и по умолчанию браузеры не запоминают позиции полос прокрутки.

Есть интересное свойство CSS, на которое вам может быть интересно обратить внимание, а именно: overflow-anchor, которое, похоже, поддерживает позиции полос прокрутки после отрисовки.

Однако, после чтения CSS Scroll Anchoring, CSSWG, особенно Scroll Adjustment, оказывается, что якорная прокрутка применяется только к вертикальной прокрутке.

Так что я предполагаю, что это невозможно сделать только с помощью CSS.

document.getElementById("btn").addEventListener("click", function() {
  const container = document.getElementById("container");
  const currentRow = container.parentElement;
  const nextRow = currentRow.nextElementSibling;

  let hscroll = container.scrollLeft;

  if (nextRow && nextRow.classList.contains("row")) {
    nextRow.appendChild(container);
  }

  container.scrollLeft = hscroll;
});
.row {
  padding: 20px;
  min-height: 20px;
  border-bottom: 1px solid black;
}

#container {
  background-color: lightgray;
  max-width: 100%;
  overflow: auto;
  padding: 20px;
}

.inner {
  width: 3000px;
  height: 20px;
  background-color: blue;
  padding: 20px 0 20px 400px;
}
<div class="rows">
  <div class="row">
    <div id="container">
      <h2>
        прокрутите меня, а затем нажмите кнопку >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      </h2>
      <div class="inner">
        <button id="btn">Переместить контейнер вниз</button>
      </div>
      <p>Он теряет позицию горизонтальной прокрутки.</p>
    </div>
  </div>
  <div class="row"></div>
  <div class="row"></div>
  <div class="row"></div>
  <div class="row"></div>
  <div class="row"></div>
  <div class="row"></div>
  <div class="row"></div>
  <div class="row"></div>
</div>

Ответ или решение

Для того чтобы сохранить положение горизонтальной прокрутки элемента при его перемещении, необходимо учитывать, что изменение DOM (Document Object Model) часто приводит к сбросу состояния прокрутки. Чтобы избежать этого, можно воспользоваться подходом, который заключается в сохранении текущей позиции прокрутки перед изменением и восстановлении её после.

Вот пример, как это можно реализовать с помощью JavaScript:

  1. Сохраните текущее положение прокрутки перед перемещением элемента.
  2. Выполните перемещение элемента в нужный контейнер.
  3. Восстановите сохраненное положение прокрутки после перемещения.

Пример кода

<div class="rows">
  <div class="row">
    <div id="container">
      <h2>
        Прокрутите меня, а затем нажмите кнопку &gt;&gt;&gt;&gt;&gt;
      </h2>
      <div class="inner">
        <button id="btn">Переместить контейнер вниз</button>
      </div>
      <p>Положение прокрутки будет потеряно без дополнительных действий.</p>
    </div>
  </div>
  <div class="row"></div>
  <div class="row"></div>
  <div class="row"></div>
  <div class="row"></div>
  <div class="row"></div>
  <div class="row"></div>
  <div class="row"></div>
  <div class="row"></div>
</div>

<style>
.row {
  padding: 20px;
  min-height: 20px;
  border-bottom: 1px solid black;
}

#container {
  background-color: lightgray;
  max-width: 100%;
  overflow: auto;
  padding: 20px;
}

.inner {
  width: 3000px;
  height: 20px;
  background-color: blue;
  padding: 20px 0 20px 400px;
}
</style>

<script>
document.getElementById("btn").addEventListener("click", function () {
  const container = document.getElementById("container");
  const currentRow = container.parentElement;
  const nextRow = currentRow.nextElementSibling;

  // Сохраните текущее положение прокрутки
  let hscroll = container.scrollLeft;

  if (nextRow && nextRow.classList.contains("row")) {
    nextRow.appendChild(container);
  }

  // Восстановите положение прокрутки после перемещения
  container.scrollLeft = hscroll;
});
</script>

Объяснение:

  • HTML: Defines a layout with several rows and a container that will be moved.

  • CSS: Stylizes the rows and the container, ensuring that the container can scroll horizontally.

  • JavaScript:

    • Устанавливает обработчик событий на кнопку.
    • Сохраняет текущее положение прокрутки (свойство scrollLeft).
    • Перемещает контейнер вниз на следующую строку, если она существует.
    • Восстанавливает положение прокрутки после перемещения.

Примечание о CSS

С помощью только CSS решение данной проблемы невозможно. Свойство overflow-anchor действительно существует, но оно больше связано с вертикальной прокруткой, и его применение не повлияет на горизонтальную прокрутку. Поэтому JavaScript остается наиболее подходящим инструментом для данного случая.

Таким образом, сохранение и восстановление положения прокрутки при изменении структуры DOM возможно, и приведенный выше код иллюстрирует данный процесс.

Оцените материал
Добавить комментарий

Капча загружается...