Как сделать липкий хедер в React

Некоторые дизайны веб‑страниц используют заголовок, который «прилипает» к верхней части экрана при прокрутке. Такой заголовок обычно называют липким или sticky header.
Вы можете сделать липкий заголовок в React собственным кодом или с помощью сторонней библиотеки.
Что такое липкий хедер
Липкий хедер — это блок заголовка, который остаётся зафиксированным вверху окна при прокрутке страницы. Это удобно для постоянного отображения навигации, логотипа или важных действий.
Короткое определение: липкий хедер — фиксированный вверху контейнер, видимый при прокрутке.
Важно: липкий заголовок уменьшает доступную область экрана. Делайте его компактным и минималистичным.
Создание липкого хедера через хуки
Основная идея: подписаться на событие прокрутки окна и менять состояние компонента. Ниже — минимальный пример с использованием хуков React.
Пример с useEffect и addEventListener:
import React, { useState, useEffect } from 'react';
function StickyHeader() {
const [isSticky, setSticky] = useState(false);
const handleScroll = () => {
const windowScrollTop = window.scrollY;
if (windowScrollTop > 10) {
setSticky(true);
} else {
setSticky(false);
}
};
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
const items = [
{
name: 'Home',
link: '/'
},
{
name: 'About',
link: '/about'
},
{
name: 'Contact',
link: '/contact'
}
];
const data = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36 ]
return (
{items.map(item => (
{item.name}
))}
{data.map((x) => {
return (- {x}
)
})}
);
}
export default StickyHeader;Этот пример использует встроенные стили в JSX. Можно вместо этого вынести стили в CSS-класс:
.sticky {
position: fixed;
top: 0;
width: 100%;
z-index: 999;
}Результат примерно такой:
.jpg)
Дополнительные функции
Чтобы улучшить удобство, добавьте кнопку «вверх» или делайте заголовок прозрачным при прокрутке. Пример с кнопкой “Back to top”:
import React, { useState, useEffect } from 'react';
function StickyHeader() {
const [isSticky, setSticky] = useState(false);
const [showBackToTop, setShowBackToTop] = useState(false);
const handleScroll = () => {
const windowScrollTop = window.scrollY;
if (windowScrollTop > 10) {
setSticky(true);
setShowBackToTop(true);
} else {
setSticky(false);
setShowBackToTop(false);
}
};
const scrollToTop = () => {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
};
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
const items = [
{
name: 'Home',
link: '/'
},
{
name: 'About',
link: '/about'
},
{
name: 'Contact',
link: '/contact'
}
];
const data = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36 ]
return (
);
}
export default StickyHeader;Вы также можете стилизовать компонент с помощью Tailwind CSS или любой другой библиотеки стилей.
Альтернативные методы и сторонние библиотеки
Иногда проще использовать готовую библиотеку. Ниже — два распространённых варианта.
react-sticky
Установите:
npm install react-stickyПример использования:
import React from 'react';
import { StickyContainer, Sticky } from 'react-sticky';
function App() {
const data = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36 ]
return (
{({ style }) => (
This is a sticky header
)}
{data.map((x) => {
return (- {x}
)
})}
);
}
export default App;
react-stickynode
Установите:
npm install react-stickynodeПример использования:
import React from 'react';
import Sticky from 'react-stickynode';
function App() {
const data = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36 ]
return (
This is a sticky header
{data.map((x) => {
return (- {x}
)
})}
);
}
export default App;
Когда стоит использовать и когда нет
- Используйте, если навигация или действия должны быть доступны постоянно.
- Не используйте, если экран и так перегружен или место критично (например, на очень маленьких мобильных экранах).
- Избегайте крупных и высоких хедеров; лучше скрывать лишние элементы при прокрутке.
Критерии приёмки
- Заголовок остаётся видимым при прокрутке вниз.
- На мобильных экранах заголовок не перекрывает основной контент.
- Фокус клавиатуры и скринридеры корректно работают с элементами в заголовке.
- Плавность анимаций и отсутствие заметных «заиканий» при скролле.
Чек‑лист по ролям
- Разработчик:
- Реализовать обработчик прокрутки с отпиской в useEffect.
- Обеспечить адаптивные стили (mobile-first).
- Добавить тесты для видимости/позиции в разных разрешениях.
- Дизайнер:
- Утвердить высоту и контент хедера.
- Предусмотреть состояние «мини» для мобильных устройств.
- QA:
- Проверить на iOS Safari, Android Chrome, десктопных браузерах.
- Проверить доступность (keyboard, focus, aria).
Руководство по внедрению (короткая SOP)
- Оцените необходимость: навигация/CTA должны быть постоянными.
- Выберите подход: собственная реализация или библиотека.
- Реализуйте базовый вариант и добавьте адаптивные стили.
- Протестируйте производительность (devtools FPS, профайлер React).
- Проверьте доступность и корректировку перекрытий контента.
- Деплой на staging и сбор обратной связи от пользователей.
Сравнение подходов
| Подход | Плюсы | Минусы |
|---|---|---|
| Самописный (хуки) | Полный контроль, нет зависимостей | Нужно позаботиться о производительности и доступности |
| react-sticky | Готовая логика и контейнеры | Доп. зависимость, может быть тяжеловат в простых случаях |
| react-stickynode | Опции bottomBoundary и включения | Настройки могут конфликтовать с layout’ом |
UX и производительность — практические советы
- Дебаунс/троттлинг: если обработчик прокрутки делает тяжёлую работу, примените throttle или requestAnimationFrame.
- Высота хедера: укажите фиксированную высоту и резервируйте отступы у основного контента (padding-top), чтобы избежать «прыжков».
- Анимации: используйте transform (translateY) и opacity вместо top для лучшей производительности.
- Мобильный UX: на маленьких экранах скрывайте лишние элементы, оставляйте ключевые действия.
- Доступность: добавьте aria-label для навигации, проверяйте порядок фокуса.
Приступая к реализации — тесты и критерии
Тесты/приёмка:
- Заголовок фиксируется после прокрутки на 20px.
- Кнопка «вверх» появляется после 300px и прокручивает плавно.
- На iPhone и Android нет визуального наложения на содержимое.
- Скринридер читает элементы хедера в корректном порядке.
Частые ошибки и как их избежать
- Забытая отписка от события scroll → утечки памяти.
- Изменение layout без резервирования места → контент «прыгает».
- Стили с тяжелыми repaint (например, top вместо transform) → тормоза.
Короткое объявление для команды (100–200 слов)
Липкий заголовок в нашем React‑приложении обеспечит быстрый доступ к навигации и основным действиям на длинных страницах. Реализацию можно сделать собственным хуком с минимальными зависимостями или подключить react-sticky/react-stickynode для более сложных сценариев. Важно учесть мобильный UX и доступность: заголовок должен быть компактным, не перекрывать контент и корректно работать с клавиатурой и скринридерами. Перед выпуском проведите тестирование на основных устройствах и измерьте влияние на производительность.
Итог
Липкий хедер — полезный инструмент, но с побочными эффектами: уменьшение видимой области и возможные проблемы с производительностью. Выбирайте подходящий способ реализации, тестируйте на устройствах и проверяйте доступность. Минимизируйте высоту хедера, используйте аппаратно‑ускоренные свойства для анимаций и обязательно отписывайтесь от обработчиков событий.
Важно: если вы используете сторонние библиотеки, следите за совместимостью версий React и поддержкой SSR при необходимости.