Headroom.js — это лёгкая библиотека для управления поведением шапки страницы при скролле. Она основывается на прямом взаимодействии с DOM, что создаёт ряд особенностей при использовании с серверным рендерингом (SSR) в таких фреймворках, как Next.js, Nuxt.js или других решениях на основе Node.js. В условиях SSR необходимо учитывать отсутствие реального окна браузера на этапе генерации HTML.
При серверной генерации страницы объекты window и
document недоступны. Прямой вызов
new Headroom(element) на сервере приведёт к ошибке. Чтобы
избежать этого:
let headroom;
if (typeof window !== "undefined") {
const element = document.querySelector(".header");
headroom = new Headroom(element, {
tolerance: 5,
offset: 50,
classes: {
pinned: "header--pinned",
unpinned: "header--unpinned",
top: "header--top",
notTop: "header--not-top"
}
});
headroom.init();
}
Ключевой момент — проверка
typeof window !== "undefined". Это гарантирует, что код
Headroom.js выполнится только в браузере, а серверная сборка останется
безопасной.
Иногда требуется более тонкая интеграция с жизненным циклом компонентов. В React или Vue рекомендуется использовать хуки или lifecycle методы:
React (Next.js):
import { useEffect, useRef } from "react";
import Headroom from "headroom.js";
export default function Header() {
const headerRef = useRef(null);
useEffect(() => {
if (headerRef.current) {
const headroom = new Headroom(headerRef.current, {
tolerance: 5,
offset: 50
});
headroom.init();
return () => headroom.destroy();
}
}, []);
return <header ref={headerRef} className="header">Мой сайт</header>;
}
Vue 3:
import { onMounted, ref } from "vue";
import Headroom from "headroom.js";
export default {
setup() {
const header = ref(null);
onMounted(() => {
if (header.value) {
const headroom = new Headroom(header.value, { tolerance: 5, offset: 50 });
headroom.init();
}
});
return { header };
}
};
Использование useEffect и onMounted
гарантирует запуск Headroom.js только на клиенте, после того как DOM
доступен.
Headroom.js добавляет CSS-классы к элементу в зависимости от положения скролла:
headroom--pinned — шапка зафиксирована, видна.headroom--unpinned — шапка скрыта при скролле
вниз.headroom--top — скролл находится в верхней точке
страницы.headroom--not-top — страница прокручена вниз.При SSR эти классы не добавляются на сервере, поэтому важно обеспечить корректные стили для начального состояния. Рекомендуется добавить базовый класс, который отражает дефолтное состояние шапки:
<header class="header header--top">...</header>
Для плавного появления и скрытия шапки удобно использовать CSS-переходы:
.header {
transition: transform 0.3s ease-in-out;
}
.header--unpinned {
transform: translateY(-100%);
}
.header--pinned {
transform: translateY(0);
}
Поскольку на сервере шапка будет рендериться с классом
header--top, а остальные состояния активируются только на
клиенте, визуальный переход не ломается.
Если шапка на сервере рендерится с дефолтным классом, а при первом рендере на клиенте Headroom сразу меняет класс из-за позиции скролла, возможны мигания (flash). Решение:
opacity: 0 на шапку в начальном
состоянии.opacity: 1 через JavaScript или CSS-анимацию.header.style.opacity = "1";
При разработке гибридных приложений важно:
useEffect, onMounted) для запуска
библиотеки.Параметры библиотеки работают одинаково, но стоит учитывать особенности:
offset — учитывается после гидратации, на сервере не
имеет значения.tolerance — чувствительность к скроллу.classes — желательно полностью настроить для управления
стилями, так как на сервере базовый класс нужен для корректного
визуального отображения.const options = {
tolerance: 10,
offset: 100,
classes: {
pinned: "header--pinned",
unpinned: "header--unpinned",
top: "header--top",
notTop: "header--not-top",
initial: "header--top" // начальный класс при SSR
}
};
Использование свойства initial позволяет задать
состояние шапки сразу на сервере, предотвращая рассинхрон визуального
состояния.
Headroom.js в условиях серверного рендеринга требует корректного разделения кода между сервером и клиентом, управления дефолтными классами и правильной инициализации в жизненном цикле компонентов. Эти подходы обеспечивают плавную работу шапки, отсутствие ошибок на сервере и визуальную согласованность между SSR и клиентским рендером.