Прокрутка: событие scroll

Событие onscroll происходит, когда элемент прокручивается.

В отличие от события onwheel (колесико мыши), его могут генерировать только прокручиваемые элементы или окно window. Но зато оно генерируется всегда, при любой прокрутке, не обязательно «мышиной».

Например, следующая функция при прокрутке окна выдает количество прокрученных пикселей:

window.onscroll = function() {
  var scrolled = window.pageYOffset || document.documentElement.scrollTop;
  document.getElementById('showScroll').innerHTML = scrolled + 'px';
}

В действии: Текущая прокрутка = прокрутите окно

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

Некоторые области применения onscroll:

  • Показ дополнительных элементов навигации при прокрутке.
  • Подгрузка и инициализация элементов интерфейса, ставших видимыми после прокрутки.

Вашему вниманию предлагаются несколько задач, которые вы можете решить сами или посмотреть использование onscroll на их примере.

Задачи

важность: 5

Сделайте так, чтобы при прокрутке ниже элемента #avatar (картинка с Винни-Пухом) – он продолжал показываться в левом-верхнем углу.

При прокрутке вверх – должен возвращаться на обычное место.

Прокрутите вниз, чтобы увидеть:

Открыть песочницу для задачи.

важность: 3

Создайте кнопку навигации, которая помогает при прокрутке страницы.

Работать должна следующим образом:

  • Пока страница промотана меньше чем на высоту экрана вниз – кнопка не видна.
  • При промотке страницы вниз больше, чем на высоту экрана, появляется кнопка «стрелка вверх».
  • При нажатии на нее страница прыгает вверх, но не только. Дополнительно, кнопка меняется на «стрелка вниз» и при клике возвратит на старое место. Если же в этом состоянии посетитель сам прокрутит вниз больше, чем один экран, то она вновь изменится на «стрелка вверх».

Должен получиться удобный навигационный помощник.

Посмотрите, как оно должно работать, в ифрейме ниже. Прокрутите ифрейм, навигационная стрелка появится слева-сверху.

Открыть песочницу для задачи.

Добавим в документ DIV с кнопкой:

<div id="updown"></div>

Сама кнопка должна иметь position:fixed.

#updown {
  position: fixed;
  top: 30px;
  left: 10px;
  cursor: pointer;
}

Кнопка является CSS-спрайтом, поэтому мы дополнительно добавляем ей размер и два состояния:

#updown {
  height: 9px;
  width: 14px;
  position: fixed;
  top: 30px;
  left: 10px;
  cursor: pointer;
}

#updown.up {
  background: url(...updown.gif) left top;
}

#updown.down {
  background: url(...updown.gif) left -9px;
}

Для решения необходимо аккуратно разобрать все возможные состояния кнопки и указать, что делать при каждом.

Состояние – это просто класс элемента: up/down или пустая строка, если кнопка не видна.

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

window.onscroll = function() {
  var pageY = window.pageYOffset || document.documentElement.scrollTop;
  var innerHeight = document.documentElement.clientHeight;

  switch (updownElem.className) {
    case '':
      if (pageY > innerHeight) {
        updownElem.className = 'up';
      }
      break;

    case 'up':
      if (pageY < innerHeight) {
        updownElem.className = '';
      }
      break;

    case 'down':
      if (pageY > innerHeight) {
        updownElem.className = 'up';
      }
      break;
  }
}

При клике:

var pageYLabel = 0;

updownElem.onclick = function() {
  var pageY = window.pageYOffset || document.documentElement.scrollTop;

  switch (this.className) {
    case 'up':
      pageYLabel = pageY;
      window.scrollTo(0, 0);
      this.className = 'down';
      break;

    case 'down':
      window.scrollTo(0, pageYLabel);
      this.className = 'up';
  }

}

Открыть решение в песочнице.

важность: 4

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

С целью экономии трафика и более быстрой загрузки страницы изображения на ней заменяются на «макеты».

Вместо такого изображения:

<img src="yozhik.jpg" width="128" height="128">

Стоит вот такое:

<img src="1.gif" width="128" height="128" realsrc="yozhik.jpg">

То есть настоящий URL находится в атрибуте realsrc (название атрибута можно выбрать любое). А в src поставлен серый GIF размера 1x1, и так как width/height правильные, то он растягивается, так что вместо изображения виден серый прямоугольник.

При этом, чтобы браузер загрузил изображение, нужно заменить значение src на то, которое находится в realsrc.

Если страница большая, то замена больших изображений на такие макеты существенно убыстряет полную загрузку страницы. Это особенно заметно в случае, когда на странице много анонсов новостей с картинками или изображений товаров, из которых многие находятся за пределами прокрутки.

Кроме того, для мобильных устройств JavaScript может подставлять URL уменьшенного варианта картинки.

Напишите код, который при прокрутке окна загружает ставшие видимыми изображения.

То есть, как только изображение попало в видимую часть документа – в src нужно прописать правильный URL из realsrc.

Пример работы вы можете увидеть в iframe ниже, если прокрутите его:

Особенности реализации:

  • При начальной загрузке некоторые изображения должны быть видны сразу, до прокрутки. Код должен это учитывать.
  • Некоторые изображения могут быть обычными, без realsrc. Их код не должен трогать вообще.
  • Также код не должен перегружать уже показанное изображение.
  • Желательно предусмотреть загрузку изображений не только видимых сейчас, но и на страницу вперед и назад от текущего места.

P.S. Горизонтальной прокрутки нет.

Открыть песочницу для задачи.

Функция должна по текущей прокрутке определять, какие изображения видимы, и загружать их.

Она должна срабатывать не только при прокрутке, но и при загрузке. Вполне достаточно для этого – указать ее вызов в скрипте под страницей, вот так:

...страница...

function isVisible(elem) {

  var coords = elem.getBoundingClientRect();

  var windowHeight = document.documentElement.clientHeight;

  // верхняя граница elem в пределах видимости ИЛИ нижняя граница видима
  var topVisible = coords.top > 0 && coords.top < windowHeight;
  var bottomVisible = coords.bottom < windowHeight && coords.bottom > 0;

  return topVisible || bottomVisible;
}

showVisible();
window.onscroll = showVisible;

При запуске функция ищет все видимые картинки с realsrc и перемещает значение realsrc в src. Обратите внимание, т.к. атрибут realsrc нестандартный, то для доступа к нему мы используем get/setAttribute. А src – стандартный, поэтому можно обратиться по DOM-свойству.

Функция проверки видимости isVisible(elem) получает координаты текущей видимой области и сравнивает их с элементом.

Для видимости достаточно, чтобы координаты верхней(или нижней) границы элемента находились между границами видимой области.

В решении также указан вариант с isVisible, который расширяет область видимости на ±1 страницу (высота страницы – document.documentElement.clientHeight).

Открыть решение в песочнице.

Карта учебника

Комментарии

перед тем как писать…
  • Приветствуются комментарии, содержащие дополнения и вопросы по статье, и ответы на них.
  • Для одной строки кода используйте тег <code>, для нескольких строк кода — тег <pre>, если больше 10 строк — ссылку на песочницу (plnkr, JSBin, codepen…)
  • Если что-то непонятно в статье — пишите, что именно и с какого места.