Sticky header
Шапка сайта остаётся видимой при скролле; при прокрутке вниз добавляется тень и уменьшается высота.
Задача
Нужна шапка, которая фиксируется вверху страницы при скролле. Бонус: при прокрутке она визуально «уменьшается» и получает тень для отделения от контента.
Решение
<header class="header" id="header">
<div class="header__inner">
<a class="header__logo" href="/">Logo</a>
<nav class="header__nav">
<a href="#about">О нас</a>
<a href="#services">Услуги</a>
<a href="#contact">Контакт</a>
</nav>
</div>
</header>
<main style="margin-top: 70px;">
<!-- контент -->
</main>
.header {
position: sticky;
top: 0;
z-index: 100;
background: #fff;
transition: box-shadow 0.3s, padding 0.3s;
}
.header__inner {
display: flex;
align-items: center;
justify-content: space-between;
max-width: 1200px;
margin: 0 auto;
padding: 16px 24px;
transition: padding 0.3s;
}
.header.scrolled {
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.header.scrolled .header__inner {
padding-top: 8px;
padding-bottom: 8px;
}
.header__logo { font-size: 1.3rem; font-weight: 700; text-decoration: none; color: #1e293b; }
.header__nav { display: flex; gap: 24px; }
.header__nav a { text-decoration: none; color: #64748b; font-size: 0.95rem; }
.header__nav a:hover { color: #1e293b; }
const header = document.getElementById('header');
const observer = new IntersectionObserver(
([entry]) => {
// scrolled когда шапка касается верха (не видно пространства над ней)
header.classList.toggle('scrolled', !entry.isIntersecting);
},
{ rootMargin: '-1px 0px 0px 0px', threshold: 0 }
);
// Наблюдаем за сигнальным элементом в самом верху страницы
const sentinel = document.createElement('div');
document.body.prepend(sentinel);
observer.observe(sentinel);
Ключевые моменты
position: sticky; top: 0— нативный способ без JS; шапка прилипает к верху при скролле.IntersectionObserverна sentinel-элемент — производительнее, чем слушательscroll; не блокирует main thread.z-index: 100— чтобы шапка перекрывала контент при скролле.margin-topнаmainне нужен приsticky(в отличие отfixed); добавляй только если шапкаposition: fixed.
Варианты
- Hide on scroll down, show on scroll up (паттерн autohide header):
let prevY = 0; window.addEventListener('scroll', () => { const curr = window.scrollY; header.classList.toggle('hidden', curr > prevY && curr > 100); prevY = curr; }, { passive: true });.header { transition: transform 0.3s; } .header.hidden { transform: translateY(-100%); }