Кнопка «Наверх» возвращает читателя в начало длинной страницы. Сделаем её на HTML, CSS и JavaScript: ссылка отвечает за переход, CSS — за плавную прокрутку, а IntersectionObserver — за появление после первого экрана.
Пример работает без jQuery. Кнопка доступна с клавиатуры и учитывает системную настройку уменьшения анимации. В конце показано, как подключить её в WordPress.
1. HTML-разметка кнопки «Наверх»
Добавь перед закрывающим </body> ссылку и невидимый маркер первого экрана:
<div class="to-top-sentinel" aria-hidden="true"></div>
<a class="to-top" href="#top" data-hidden>
<svg width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
<path d="M12 5l-7 7 1.4 1.4 4.6-4.6V19h2V8.8l4.6 4.6L19 12z" fill="currentColor"/>
</svg>
<span class="visually-hidden">Наверх</span>
</a>
Ссылка href="#top" работает без обработчика клика. Если элемента с id="top" нет, браузер перейдёт в начало документа. Если такой элемент есть, ссылка приведёт к нему.
После перехода проверь навигацию клавишей Tab: обход должен продолжиться с начала страницы. В адресной строке появится #top; вариант без якоря разобран ниже.
Иконка скрыта от скринридеров, а доступное имя даёт текст «Наверх». Если в теме уже есть элемент с id="top", например шапка, ссылка приведёт к нему — это тоже подходящий вариант.
2. CSS: положение кнопки и плавная прокрутка
.to-top {
position: fixed;
right: 16px;
bottom: max(16px, env(safe-area-inset-bottom));
z-index: 100;
display: grid;
place-items: center;
width: 48px;
height: 48px;
border-radius: 50%;
background: #1f2937;
color: #fff;
transition: opacity 0.2s, transform 0.2s, visibility 0.2s;
}
.to-top[data-hidden] {
opacity: 0;
visibility: hidden;
transform: translateY(8px);
}
.to-top:focus-visible {
outline: 3px solid #f59e0b;
outline-offset: 3px;
}
@media (hover: hover) {
.to-top:hover {
background: #374151;
}
}
.to-top-sentinel {
position: absolute;
top: 0;
left: 0;
width: 1px;
height: 100vh;
pointer-events: none;
}
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
}
@media (prefers-reduced-motion: no-preference) {
html {
scroll-behavior: smooth;
}
}
@media (prefers-reduced-motion: reduce) {
.to-top {
transition: none;
}
}
Что здесь важно:
- Размер 48 × 48 пикселей удобен для пальца.
visibility: hiddenубирает спрятанную кнопку из порядка фокуса. Однойopacity: 0для этого мало: на невидимую ссылку можно было бы перейти клавиатурой.env(safe-area-inset-bottom)не даёт кнопке залезть под системную полосу на iPhone. Чтобы значение было ненулевым, в<meta name="viewport">должен бытьviewport-fit=cover; без него сработает обычный отступ 16 пикселей.- Подсветка при наведении включена только там, где есть настоящее наведение. Подробнее — в статье про :hover и :active на сенсорных устройствах.
- Плавная прокрутка отключается для тех, кто включил в системе уменьшение анимации.
scroll-behavior: smooth на html влияет на все якорные ссылки сайта. Если фиксированная шапка закрывает заголовки при переходе по якорям, добавь scroll-margin-top, как описано в статье о якорных ссылках.
3. JavaScript: показать кнопку после первого экрана
const toTop = document.querySelector('.to-top');
const sentinel = document.querySelector('.to-top-sentinel');
if (toTop && sentinel && 'IntersectionObserver' in window) {
const observer = new IntersectionObserver(([entry]) => {
toTop.toggleAttribute('data-hidden', entry.isIntersecting);
});
observer.observe(sentinel);
}
Маркер занимает первый экран страницы. Пока он виден, у кнопки есть атрибут data-hidden. Когда маркер уходит вверх за край окна, атрибут снимается и кнопка появляется. Браузер сообщает только о смене состояния, поэтому код не выполняется на каждом пикселе прокрутки, как обработчик scroll.
Атрибут data-hidden стоит в разметке изначально, поэтому кнопка не мелькает при загрузке. Если JavaScript не выполнится, кнопка останется скрытой, а страница продолжит работать как обычно.
Прокрутка наверх без #top в адресе
Когда якорь в адресе недопустим, например в SPA с роутингом по hash, используй <button type="button"> и прокрути страницу из скрипта. В этом случае фокус нужно перенести вручную, иначе пользователь клавиатуры останется внизу страницы:
button.addEventListener('click', () => {
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
window.scrollTo({ top: 0, behavior: reduce ? 'auto' : 'smooth' });
// Первый фокусируемый элемент страницы, например ссылка на главную в шапке
document.querySelector('header a')?.focus({ preventScroll: true });
});
Подключение в WordPress
В классической теме вставь разметку в footer.php перед wp_footer(). Стили добавь в основной CSS темы, а скрипт сохрани в assets/js/to-top.js и подключи в functions.php:
function mytheme_enqueue_to_top() {
wp_enqueue_script(
'mytheme-to-top',
get_theme_file_uri( 'assets/js/to-top.js' ),
array(),
wp_get_theme()->get( 'Version' ),
array(
'strategy' => 'defer',
'in_footer' => true,
)
);
}
add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_to_top' );
Параметр strategy поддерживается с WordPress 6.3. Четвёртый аргумент задаёт версию файла для кеша браузера. В примере это версия темы: увеличивай её после изменения скрипта.
Проверка кнопки на компьютере и телефоне
- Кнопка не видна на первом экране и появляется после прокрутки.
- На телефоне она не перекрывает баннер cookie, чат или другие фиксированные элементы.
- С клавиатуры кнопка получает видимый фокус, а после нажатия Tab продолжает обход с начала страницы.
- При включённом уменьшении анимации страница перескакивает наверх без плавной прокрутки.