Как сделать ненавязчивую кнопку прокрутки вверх

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

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

Вариант 1. Будьте проще

Сначала мы выбираем кнопку в JavaScript.

var scrollToTopBtn = document.getElementById("scrollToTopBtn")

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

var rootElement = document.documentElement

Мы добавим к кнопке прослушиватель событий клика:

function scrollToTop { // scroll to top logic
} scrollToTopBtn.addEventListener("click", scrollToTop)

Затем внутри функции scrollToTop мы заставим страницу прокручиваться в верхнюю часть экрана с помощью метода scrollTo.

function scrollToTop() { // Scroll to top logic rootElement.scrollTo({ top: 0, behavior: "smooth" })
}

Мы также можем немного изменить стиль кнопки:

#scrollToTopBtn { background-color: black; border: none; border-radius: 50%; color: white; cursor: pointer; font-size: 16px; line-height: 48px; width: 48px;
}

Теперь мы можем разместить кнопку где-нибудь внизу страницы, например, в футере:

<footer> <!-- Scroll to top button --> <button id="scrollToTopBtn">Up</button>
</footer>

И получаем вот что:

Вариант 2: Определение положения прокрутки

Мы можем обнаружить прокрутку с помощью прослушивателя событий прокрутки.

function handleScroll() { // Do something on scroll
}
document.addEventListener("scroll", handleScroll)

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

scrollHeight дает высоту элемента, включая ту часть, которая не видна из-за переполнения.

clientHeight дает внутреннюю высоту элемента в пикселях, которая является высотой видимой части.

Если мы вычтем из scrollHeight clientHeight, мы получим общее количество пикселей, которые мы можем прокрутить:

var scrollTotal = rootElement.scrollHeight - rootElement.clientHeight

Теперь у нас есть переменная scrollTotal, которая представляет максимальное количество пикселей, которые можно прокручивать по вертикали. Разделив количество прокручиваемых пикселей на общее количество пикселей, которые мы можем прокрутить, мы получим соотношение от 0 до 1. Играя с этим соотношением, мы можем легко включать и выключать кнопку.

Например, мы добавим условие, которое показывает кнопку прокрутки вверх, когда пользователь прокручивает вниз на 80% (или 0,80) от общей высоты страницы. 80% — произвольное число. По сути, чем ближе мы к 1, тем больше пользователь должен прокрутить, прежде чем увидит кнопку.

Вот код JavaScript:

var rootElement = document.documentElement


function handleScroll() { // Do something on scroll var scrollTotal = rootElement.scrollHeight - rootElement.clientHeight if ((rootElement.scrollTop / scrollTotal ) > 0.80 ) { // Show button scrollToTopBtn.classList.add("showBtn") } else { // Hide button scrollToTopBtn.classList.remove("showBtn") }
}


document.addEventListener("scroll", handleScroll)

Нам понадобится некоторый CSS для правильного позиционирования кнопки, когда она появится в поле зрения:

.scrollToTopBtn { /* same general styles as before */ /* place it at the bottom-right corner */ position: fixed; bottom: 30px; right: 30px;

 /* keep it at the top of everything else */ z-index: 100;

 /* hide with opacity */ opacity: 0;

 /* also add a translate effect */ transform: translateY(100px);

 /* and a transition */ transition: all .5s ease
}


.showBtn { opacity: 1; transform: translateY(0)
}

При этом кнопка появляется, когда пользователь опускается на 80% по странице, а затем скрывается, когда это значение превышено.

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

Есть еще один вариант…

Вариант 3: Intersection Observer

Intersection Observer API — отличное решение вышеуказанной проблемы. Это довольно новый API браузера, который позволяет разработчикам передать большинство этих задач браузеру более оптимизированным способом. Вот как это определяет MDN:

Intersection Observer API обеспечивает способ асинхронного наблюдения за изменениями пересечения целевого элемента с элементом-предком или с окном просмотра документа верхнего уровня.

Довольно аккуратно! Это означает, что кнопка может быть нашим целевым элементом:

// We select the element we want to target
var target = document.querySelector("footer");

Затем мы пишем функцию обратного вызова, которая что-то делает, когда наш элемент «пересекается» с окном просмотра — что является причудливым способом сказать, когда он появляется в поле зрения.

И как только футер входит в область просмотра или покидает ее, все, что нам действительно нужно — это добавить или удалить класс. Обратный вызов получает в качестве параметра массив записей.

function callback(entries, observer) { // The callback will return an array of entries, even if you are only observing a single item entries.forEach(entry => { if (entry.isIntersecting) { // Show button scrollToTopBtn.classList.add('showBtn') } else { // Hide button scrollToTopBtn.classList.remove('showBtn') } });
}

Нам нужно создать новый экземпляр IntersectionObserver и передать ему только что написанную функцию обратного вызова.

let observer = new IntersectionObserver(callback);

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

observer.observe(target);

А что насчет плавной прокрутки?

Конечно возможно! Фактически, Крис показал нам, как это можно сделать с помощью CSS еще в 2019 году:

<html id="top"> <body> <!-- the entire document --> <a href="#top">Jump to top of page</a> </body>
</html>

Здесь есть еще немного нюансов, например, улучшения доступности, о которых Крис также рассказывает в своем посте. Дело в том, что CSS приобретает новые возможности, которые могут выполнять то, для чего мы использовали JavaScript.

Вот и все! Мы начали с довольно простой идеи. Мы улучшили ее, отображая и скрывая кнопку в зависимости от положения прокрутки пользователя. Затем мы улучшили производительность, реализовав Intersection Observer API вместо отслеживания текущей позиции прокрутки. И, наконец, мы увидели, как можно использовать CSS для плавной прокрутки. Сложив все вместе мы получаем кнопку с прокруткой вверх, которую легко увидеть и использовать, не блокируя при этом другие элементы на странице.

Автор: Marcel Rojas

Источник: css-tricks.com

Редакция: Команда webformyself.