Smooth Scroll в JavaScript позволяет не только плавно перемещаться по странице, но и управлять положением прокрутки при повторных посещениях или возврате на страницу. Восстановление позиции становится критически важным для SPA (Single Page Application), длинных лендингов и динамических интерфейсов, где пользователь ожидает, что после перехода назад он окажется в том же месте страницы, где остановился.
Для сохранения текущей позиции используется объект
window.scrollY (для вертикальной прокрутки) и
window.scrollX (для горизонтальной). Пример:
let scrollPosition = 0;
window.addEventListener('scroll', () => {
scrollPosition = window.scrollY;
});
Этот подход фиксирует текущую координату прокрутки и позволяет использовать её для последующего восстановления.
В современных приложениях часто используется History API. При переходе между страницами или состояниями можно сохранить позицию в объекте состояния:
window.history.replaceState({ scrollY: window.scrollY }, '');
При возврате на страницу через popstate:
window.addEventListener('popstate', (event) => {
if (event.state && typeof event.state.scrollY === 'number') {
smoothScrollTo(event.state.scrollY);
}
});
Smooth Scroll реализует плавное перемещение к координате, чтобы восстановление позиции выглядело естественно. Минимальная функция:
function smoothScrollTo(y) {
const start = window.scrollY;
const change = y - start;
const duration = 500;
let currentTime = 0;
function animateScroll() {
currentTime += 16; // примерно 60 FPS
const val = easeInOutQuad(currentTime, start, change, duration);
window.scrollTo(0, val);
if (currentTime < duration) {
requestAnimationFrame(animateScroll);
}
}
animateScroll();
}
// Функция плавного ускорения и замедления
function easeInOutQuad(t, b, c, d) {
t /= d / 2;
if (t < 1) return c / 2 * t * t + b;
t--;
return -c / 2 * (t * (t - 2) - 1) + b;
}
Когда контент страницы загружается динамически, координаты элементов
могут меняться. В этом случае лучше сохранять позицию не через численные
значения scrollY, а через идентификаторы элементов:
window.history.replaceState({ anchor: 'section-3' }, '');
Восстановление позиции выполняется через
document.getElementById:
window.addEventListener('popstate', (event) => {
if (event.state && event.state.anchor) {
const element = document.getElementById(event.state.anchor);
if (element) smoothScrollTo(element.offsetTop);
}
});
Современные библиотеки для плавного скролла, такие как smooth-scroll, позволяют упростить восстановление позиции:
const scroll = new SmoothScroll();
window.addEventListener('popstate', (event) => {
if (event.state && event.state.anchor) {
const target = document.querySelector(`#${event.state.anchor}`);
if (target) scroll.animateScroll(target);
}
});
Здесь используется встроенный метод animateScroll,
который учитывает скорость, easing и корректно управляет
позиционированием при возврате назад.
В SPA или страницах с подгрузкой контента через AJAX важно учитывать, что восстановление позиции до загрузки контента может привести к неверному отображению. Решение — отсрочить скролл до полной отрисовки нужного блока:
function restoreScrollPosition(anchor) {
const checkExist = setInterval(() => {
const element = document.getElementById(anchor);
if (element) {
smoothScrollTo(element.offsetTop);
clearInterval(checkExist);
}
}, 50);
}
Такой подход гарантирует, что позиция восстановится корректно, даже если DOM меняется динамически.
popstate с сохранением позиции.localStorage:window.addEventListener('beforeunload', () => {
localStorage.setItem('scrollY', window.scrollY);
});
window.addEventListener('load', () => {
const savedY = parseInt(localStorage.getItem('scrollY'), 10);
if (!isNaN(savedY)) smoothScrollTo(savedY);
});
let scrollPositions = {};
document.querySelectorAll('section').forEach(section => {
section.addEventListener('scroll', () => {
scrollPositions[section.id] = section.scrollTop;
});
});
Восстановление позиции прокрутки в Smooth Scroll требует сочетания:
scrollX, scrollY).localStorage.Такая организация позволяет создавать интерфейсы, где возврат к предыдущему положению страницы будет естественным, удобным и предсказуемым, что особенно важно для длинных и интерактивных страниц.