Работа с прокруткой в современном JavaScript

Плавная прокрутка к нужному элементу

Раньше самым популярным способом сделать плавную прокрутку до нужного элемента было использование функции animate из JQuery. Но в современных броузерах есть более простой способ, не требующий сторонних библиотек: через функцию scrollIntoView, которая есть у каждого DOM-элемента. Чтобы прокрутка была плавной, ей нужно передать объект с параметром behavior: 'smooth'. Также есть параметр block, который задаёт, где окажется элемент после прокрутки: сверху ('start') области просмотра, посередине ('center') или внизу ('end'). Также можно указать 'nearest' для минимальной прокрутки до попадания в зону видимости.
Тогда ссылка для прокрутки к нужному элементу будет выглядеть так:
<a href="#идентификатор" onclick="document.getElementById('идентификатор').scrollIntoView({behavior:'smooth',block:'nearest'});return false" >К самому интересному!</a>
Вместо document.getElementById можно получать нужный элемент и другими способами, например, через document.querySelector.
А ссылку для прокрутки наверх страницы можно сделать без идентификатора вообще, используя в качестве элемента body:
<a href="#" onclick="document.body.scrollIntoView({behavior:'smooth',block:'start'});return false"> Наверх</a>

Проверка, что элемент попал в зону видимости

Ещё одна задача, с которой приходится часто сталкиваться, — это обработка ситуаций, когда элемент появляется в зоне видимости или исчезает из неё. Раньше для этого приходилось вешать обработчик на событие scroll и дальше высчитывать смещение элемента и проверять, попадает ли оно в нужный диапазон. При этом, если код обработчика выполнялся долго, терялась плавность прокрутки страницы. Сейчас появилось более простое решение — интерфейс IntersectionObserver.

Используется он так: сначала создаём объект через new и передаём ему функцию-обработчик и объект с опциями. Функция-обработчик имеет один параметр — массив объектов IntersectionObserverEntry, наиболее важными свойствами которых являются isIntersecting — признак того, появился объект в зоне видимости или ушёл, и target — указание на сам DOM-элемент.

Две наиболее важных опции:
root — элемент, внутри которого делается прокрутка и внутри которого должны находиться наблюдаемые элементы (если его не указать, отслеживание будет вестись во всём документе), и
tresholds — массив числовых значений, который определяет, насколько должен появиться элемент в зоне видимости, чтобы IntersectionObserver вызвал функцию-обработчик. Например, tresholds: [0.0,0.33,1.0] означает, что когда элемент будет входить в зону видимости, функция обработчик будет вызвана трижды: когда появится только его край (значение 0), когда он появится на треть (значение 0.33) и когда войдёт в зону видимости полностью (значение 1).

Далее для созданного объекта нужно вызвать функцию observe, в которую передать элементы, появление/исчезновение которых нужно отслеживать. Прекратить отслеживание можно с помощью метода disconnect.

Пример кода, который загружает ролик с YouTube в тот момент, когда пользователь прокручивает страницу до него:
<!-- создаем пустой iframe --> <iframe class="scalable" width="269" height="150" src="about:blank" id="youtube_video" allowfullscreen=""></iframe> <script> // создаем сам объект-наблюдатель и объявляем функцию-обработчик let observer = new IntersectionObserver(function(entries) { //  проверка, что элемент стал видимым if(entries[0].isIntersecting === true) { // меняем атрибут src iframe на реальный адрес ролика       entries[0].target.src="https://www.youtube.com/embed/WUYPb8bOr1c"; // поскольку ролик нужно загрузить всего один раз, отключаем дальнейшее отслеживание       observer.disconnect();     }     else { // если бы мы не сделали disconnect, // здесь можно было бы повесить обработчик для ситуаций, когда iframe уходит из области видимости     }   } }, // Блок опций: начинаем грузить ролик сразу, как только iframe хоть немного попадает в зону видимости { threshold: [0] }); // указываем, за каким элементом нам надо следить observer.observe(document.getElementById('youtube_video')); </script>
На этом пока всё. Возможно, позже, в отдельном сообщении распишу, как сделать загрузку в iframe preview-изображения для видео и обеспечить его работу даже в том случае, если JavaScript отключен.