Плавная прокрутка к якорю без jQuery

532

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

var $page = $('html, body');
$('a[href*="#"]').click(function() {
    $page.animate({
        scrollTop: $($.attr(this, 'href')).offset().top
    }, 400);
    return false;
});

Есть также код написаный на чистом javascript. Выглядит он так:

document.querySelectorAll('a[href*="#"]').forEach(anchor => {
  anchor.addEventListener('click', function (e) {
    const blockID = anchor.getAttribute('href').substr(1);
    if(document.getElementById(blockID)) {
      e.preventDefault();

      document.getElementById(blockID).scrollIntoView({
        behavior: 'smooth',
        block: 'start'
      });
    }
  });
});

что в первом, что во втором случае код срабатывает на ссылки вида:

<a href="#anchor-1">Ссылка к якорю 1</a>

и перемещает к блоку с id anchor-1

<div id="anchor-1"> ... </div>

Скролл по якорным ссылкам с учетом высоты элементов

Если при скролле нужно учитывать высоту каких либо элементов, то код будет следующим:

/** Скролл по якорным ссылкам с учетом элементов с классом .js-margin-scroll */
const anchors = document.querySelectorAll('a[href*="#"]');

anchors.forEach(anchor => {
    anchor.addEventListener("click", function (e) {
        if(!document.getElementById(this.getAttribute('href').substr(1))) return;
        e.preventDefault();

        const $blockTo = document.getElementById(this.getAttribute('href').substr(1));
        const marginScroll = Array.from(document.querySelectorAll(".js-margin-scroll")).map(item => item.offsetHeight).reduce((prev, current) => prev + current) || 0;

        window.scrollTo({ top: $blockTo.offsetTop - marginScroll, behavior: "smooth" });
    })
});
/** --- Скролл по якорным ссылкам с учетом элементов с классом .js-margin-scroll */

А для учета элементов, высоту которых надо учесть, надо добавить им класс js-margin-scroll.