Гид по технологиям

Плавная прокрутка на JavaScript — практический гид

5 min read Web‑разработка Обновлено 09 Jan 2026
Плавная прокрутка на JavaScript — практический гид
Плавная прокрутка на JavaScript — практический гид

Крупный план мобильного телефона, удерживаемого двумя руками

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

Что такое плавная прокрутка

Плавная прокрутка — это поведение, при котором браузер или скрипт анимирует изменение положения прокрутки до целевой точки. Термин в одну строку: это анимированный переход окна просмотра к элементу, вместо мгновенного прыжка.

Почему это важно

  • Улучшает визуальную иерархию и делает интерфейс более «шлифованным».
  • Повышает вовлечённость: пользователи реже теряются при длинных страницах и легче находят контент.
  • Упрощает навигацию между секциями и улучшает восприятие взаимосвязи контента.

Важно: не всегда стоит включать анимацию — учитывайте предпочтения пользователей (prefers-reduced-motion) и потенциальное ухудшение производительности на слабых устройствах.

Реализация в JavaScript

Ниже показан пошаговый подход: HTML-разметка, базовый CSS и JavaScript. Исходная разметка и код сохранены для наглядности.

HTML: структура

Сначала создайте навигацию и секции с идентификаторами, к которым будут вести ссылки:

  
  
  
  
   
    
    
  Smooth Scrolling Guide for Web Developers  
  
  
  
    
  
    
    

Section 1

          

Section 2

          

Section 3

     

Комментарий: каждая ссылка содержит href с «#id» целевой секции. Браузер по умолчанию делает мгновенный переход к элементу. Дальше мы заменим это поведение на плавное.

CSS: базовая стилизация

Пример стилей, чтобы увидеть секции как полноэкранные блоки и фиксированную навигацию:

* {  
  margin: 0;  
  padding: 0;  
  box-sizing: border-box;  
}  
  
body {  
  font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;  
}  
  
nav {  
  background: #fff;  
  box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.25);  
  position: sticky;  
  top: 0;  
  padding: 30px;  
}  
  
nav ul {  
  display: flex;  
  gap: 10px;  
  justify-content: center;  
}  
  
nav ul li {  
  list-style: none;  
}  
  
nav ul li a {  
  border-radius: 5px;  
  border: 1.5px solid #909090;  
  text-decoration: none;  
  color: #333;  
  padding: 10px 20px;  
}  
  
section {  
  height: 100vh;  
  display: flex;  
  align-items: center;  
  justify-content: center;  
}  

Примечание: CSS-свойство html { scroll-behavior: smooth; } обеспечивает нативную плавность для якорных ссылок и window.scrollTo с behavior: ‘smooth’ в современных браузерах. Однако оно не даёт контроля над кривой ускорения.

Базовая реализация на JavaScript (scrollIntoView)

scrollIntoView — встроенный метод, который отправляет элемент в видимую область контейнера. Это самый простой способ добавить плавную прокрутку для якорных ссылок.

Слушаем событие DOMContentLoaded и устанавливаем обработчики на ссылки навигации:

document.addEventListener("DOMContentLoaded", makeLinksSmooth);

Функция, которая находит ссылки и навешивает обработчики:

function makeLinksSmooth() {   
  const navLinks = document.querySelectorAll("nav a");   
  
  navLinks.forEach((link) => {  
    link.addEventListener("click", smoothScroll);  
  });  
}

Функция обработчика, которая отменяет дефолт и вызывает scrollIntoView с опцией behavior: ‘smooth’:

function smoothScroll(e) {  
  e.preventDefault();  
  const targetId = this.getAttribute("href");  
  const targetElement = document.querySelector(targetId);  
  
  if (targetElement) {   
    targetElement.scrollIntoView({ behavior: "smooth", });  
  }  
}

Важно: если на странице есть фиксированная шапка (fixed header), scrollIntoView может скрыть верхнюю часть целевого элемента под шапкой. Ниже приведены способы учёта смещения.

Учет фиксированной шапки и смещений

Если у вас есть фиксированный header высотой headerHeight, используйте явную прокрутку с вычислением позиции:

function scrollToWithOffset(element, offset) {
  const elementTop = element.getBoundingClientRect().top + window.pageYOffset;
  const targetPosition = elementTop - offset;
  window.scrollTo({ top: targetPosition, behavior: 'smooth' });
}

// Использование:
const headerHeight = document.querySelector('header')?.offsetHeight || 0;
scrollToWithOffset(targetElement, headerHeight + 16); // добавляем отступ 16px

Этот подход даёт контроль над финальной позицией и предотвращает скрытие заголовков.

Тонкая настройка и кастомные easing-функции

Нативный scroll-behavior поддерживает только значения auto и smooth. Если нужна кастомная кривая ускорения (cubic-bezier), придётся реализовать анимацию вручную или использовать библиотеку.

Пример функции прокрутки с кастомным easing на основе requestAnimationFrame:

// Простая функция easeInOutQuad
function easeInOutQuad(t) { return t < 0.5 ? 2*t*t : -1 + (4 - 2*t)*t; }

function animatedScrollTo(targetY, duration = 600) {
  const startY = window.pageYOffset;
  const diff = targetY - startY;
  let start;

  function step(timestamp) {
    if (!start) start = timestamp;
    const time = Math.min(1, (timestamp - start) / duration);
    const eased = easeInOutQuad(time);
    window.scrollTo(0, Math.round(startY + diff * eased));
    if (time < 1) requestAnimationFrame(step);
  }

  requestAnimationFrame(step);
}

// Использование:
const headerHeight = document.querySelector('header')?.offsetHeight || 0;
const targetY = targetElement.getBoundingClientRect().top + window.pageYOffset - headerHeight - 12;
animatedScrollTo(targetY, 700);

Этот подход даёт полный контроль над длительностью и кривой ускорения.

Доступность и prefers-reduced-motion

Не забывайте учитывать пользователей с повышенной чувствительностью к движению. Используйте CSS-медиа-запрос prefers-reduced-motion и JS-проверку:

/* CSS */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}
// JS
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (reduceMotion) {
  // Отключаем анимации прокрутки
}

Важно: уважайте пользовательские настройки — если prefers-reduced-motion включён, не выполняйте анимированную прокрутку.

Совместимость браузеров и полифилы

Нативная поддержка scroll-behavior и опции behavior в window.scrollTo/scrollIntoView есть в большинстве современных браузеров, но в старых версиях и некоторых мобильных браузерах её может не быть.

Рекомендации:

  • Проверяйте поддержку через сервисы типа “Can I use”.
  • Для старых браузеров используйте полифилы, например “smoothscroll-polyfill” (популярный полифил) или библиотеку с проверкой поддержки.
  • Тестируйте на реальных устройствах с медленными сетями/процессорами.

Иллюстрация поддержки браузерами методов JavaScript

Альтернативные подходы

  • Чистый CSS: html { scroll-behavior: smooth; } — самый простой способ, но без контроля над easing и смещением.
  • JavaScript библиотеки: “smooth-scroll” и другие предлагают конфигурации, offset, callbacks и history-поддержку.
  • Полная кастомная реализация через requestAnimationFrame — максимум контроля, но требует тестирования и оптимизации.

Когда нативное поведение не хватает (нужны кастомные кривые, offsets, callbacks), выбирайте JS-библиотеку или кастомную реализацию.

Практические советы и эвристики

  • Если нужен простой эффект — используйте CSS scroll-behavior.
  • Если есть фиксированная шапка — используйте прокрутку с offset.
  • Всегда учитывайте prefers-reduced-motion.
  • Не делайте длительные анимации (>900 ms) — это может восприниматься как задержка.
  • Кешируйте часто используемые DOM-элементы (например, headerHeight), но обновляйте их при ресайзе.

Готовые сниппеты (cheat sheet)

  • Нативный (CSS):
html { scroll-behavior: smooth; }
  • JS + scrollIntoView:
link.addEventListener('click', function(e) {
  e.preventDefault();
  const id = this.getAttribute('href');
  const el = document.querySelector(id);
  if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
});
  • Учёт фиксированного header:
const headerHeight = document.querySelector('header')?.offsetHeight || 0;
const top = element.getBoundingClientRect().top + window.pageYOffset - headerHeight;
window.scrollTo({ top, behavior: 'smooth' });
  • Отключение анимаций для предпочитающих reduced motion:
if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
  // выполняем анимированную прокрутку
}

Критерии приёмки (Test cases)

  • Навигация по якорям прокручивает страницу плавно в поддерживаемых браузерах.
  • При наличии фиксированной шапки целевой контент не скрыт (проверка с разными высотами header).
  • При включённом prefers-reduced-motion анимация отключена.
  • Работает на мобильных устройствах с медленным CPU (пусть QA проверит на минимально поддерживаемом устройстве).
  • При клике на ссылку фокус перемещается к заголовку (accessibility): document.focus() при необходимости.

Role-based checklist

  • Разработчик:

    • Реализовать плавную прокрутку и учесть header offset.
    • Добавить проверку prefers-reduced-motion.
    • Подключить полифил или graceful fallback.
  • QA:

    • Проверить на десктопе и мобильных устройствах.
    • Проверить с включённым prefers-reduced-motion.
    • Проверить на разных браузерах и версиях.
  • Дизайнер:

    • Утвердить длительность и easing анимации.
    • Подтвердить визуальные отступы после скролла.
  • Product Manager:

    • Убедиться, что анимация улучшает UX и не мешает конверсии.

Decision flowchart

flowchart TD
  A[Начало: нужно ли плавное движение?] --> B{Простой эффект}
  B -- Да --> C[Использовать CSS: scroll-behavior]
  B -- Нет --> D{Нужны offset или кастомная кривая}
  D -- Offset --> E[Использовать window.scrollTo с вычисленным top]
  D -- Кастомная кривая --> F[Реализовать requestAnimationFrame или библиотеку]
  C --> G[Учесть prefers-reduced-motion]
  E --> G
  F --> G
  G --> H[Протестировать на устройствах и браузерах]

Сравнение подходов (матрица)

  • CSS scroll-behavior

    • Плюсы: простой, нативный, мало кода.
    • Минусы: нет контроля over easing, не учитывает header offset.
  • scrollIntoView

    • Плюсы: просто подключать, работает для отдельных элементов.
    • Минусы: поведение по умолчанию может скрывать контент под fixed header; ограниченный контроль.
  • window.scrollTo с вычисленным top

    • Плюсы: контролируемая финальная позиция.
    • Минусы: нужно вычислять позицию и учитывать ресайз.
  • Кастомная анимация (requestAnimationFrame)

    • Плюсы: полный контроль над easing/duration.
    • Минусы: сложнее реализовать и протестировать; возможны баги на слабых устройствах.

Edge cases и распространённые проблемы

  • Скрытие цели под фиксированной шапкой — решается offset.
  • Несовместимость со старым браузером — решается полифилом или fallback в auto.
  • Переключение фокуса и порядок чтения экранными читалками — убедитесь, что фокус устанавливается на целевой элемент.
  • Одновременные вызовы анимации — добавьте дебаунс/блокировку во время прокрутки.

Краткое резюме

  • Для простых случаев используйте CSS scroll-behavior.
  • Для контроля позиции при фиксированных элементах используйте window.scrollTo с offset.
  • Для кастомного easing — requestAnimationFrame или проверенная библиотека.
  • Всегда учитывайте prefers-reduced-motion и тестируйте на мобильных устройствах.

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

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

RDP: полный гид по настройке и безопасности
Инфраструктура

RDP: полный гид по настройке и безопасности

Android как клавиатура и трекпад для Windows
Гайды

Android как клавиатура и трекпад для Windows

Советы и приёмы для работы с PDF
Документы

Советы и приёмы для работы с PDF

Calibration в Lightroom Classic: как и когда использовать
Фото

Calibration в Lightroom Classic: как и когда использовать

Отключить Siri Suggestions на iPhone
iOS

Отключить Siri Suggestions на iPhone

Рисование таблиц в Microsoft Word — руководство
Office

Рисование таблиц в Microsoft Word — руководство