Реализация Sticky Header/Footer на сайте

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Реализация Sticky Header/Footer на сайте
Простая
~1 рабочий день
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Реализация Sticky Header/Footer на сайте

Sticky-элементы — тривиальны через position: sticky, но правильная реализация учитывает прокрутку вниз/вверх, производительность анимаций, safe-area на мобильных и конфликт с anchor-ссылками.

Базовый sticky header

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: #fff;
  /* Оптимизация: отдельный слой для compositing */
  will-change: transform;
  /* Тень только когда прилип */
  transition: box-shadow 0.2s ease;
}

.site-header--scrolled {
  box-shadow: 0 2px 20px rgba(0, 0, 0, 0.1);
}
const header = document.querySelector('.site-header')!
let lastScrollY = 0

function onScroll() {
  const currentScrollY = window.scrollY

  // Добавляем тень после первых пикселей
  header.classList.toggle('site-header--scrolled', currentScrollY > 10)

  lastScrollY = currentScrollY
}

// Throttle через rAF — не чаще 60fps
let ticking = false
window.addEventListener('scroll', () => {
  if (!ticking) {
    requestAnimationFrame(() => {
      onScroll()
      ticking = false
    })
    ticking = true
  }
}, { passive: true })

Hide-on-scroll: прячем при прокрутке вниз

Популярный паттерн: хедер исчезает при скролле вниз и появляется при скролле вверх:

const THRESHOLD = 100  // не прятать при коротком скролле вниз
const HIDE_AFTER = 50  // минимальный скролл для скрытия
let scrollStart = 0
let hidden = false

function onScroll() {
  const y = window.scrollY
  const diff = y - lastScrollY

  if (diff > 0) {
    // Скролл вниз
    if (!hidden && y > THRESHOLD && y - scrollStart > HIDE_AFTER) {
      header.classList.add('site-header--hidden')
      hidden = true
    }
  } else {
    // Скролл вверх
    if (hidden) {
      header.classList.remove('site-header--hidden')
      hidden = false
      scrollStart = y
    }
  }

  lastScrollY = y
}
.site-header {
  transition: transform 0.3s ease;
}

.site-header--hidden {
  transform: translateY(-100%);
}

transform вместо top: -100px — анимация на GPU, без reflow.

React: хук для sticky-логики

import { useState, useEffect, useRef } from 'react'

interface StickyHeaderState {
  isScrolled: boolean
  isVisible: boolean
  scrollY: number
}

function useStickyHeader(hideOnScrollDown = true): StickyHeaderState {
  const [state, setState] = useState<StickyHeaderState>({
    isScrolled: false,
    isVisible: true,
    scrollY: 0,
  })
  const lastScrollY = useRef(0)
  const scrollStart = useRef(0)

  useEffect(() => {
    let ticking = false

    const handler = () => {
      if (ticking) return
      ticking = true

      requestAnimationFrame(() => {
        const y = window.scrollY
        const diff = y - lastScrollY.current

        setState(prev => {
          let isVisible = prev.isVisible

          if (hideOnScrollDown) {
            if (diff > 0 && y > 100 && y - scrollStart.current > 50) {
              isVisible = false
            } else if (diff < 0) {
              if (!isVisible) scrollStart.current = y
              isVisible = true
            }
          }

          return {
            isScrolled: y > 10,
            isVisible,
            scrollY: y,
          }
        })

        lastScrollY.current = y
        ticking = false
      })
    }

    window.addEventListener('scroll', handler, { passive: true })
    return () => window.removeEventListener('scroll', handler)
  }, [hideOnScrollDown])

  return state
}

export function SiteHeader() {
  const { isScrolled, isVisible } = useStickyHeader(true)

  return (
    <header
      className={[
        'site-header',
        isScrolled ? 'site-header--scrolled' : '',
        !isVisible ? 'site-header--hidden' : '',
      ].filter(Boolean).join(' ')}
    >
      {/* ... */}
    </header>
  )
}

Sticky footer / bottom navigation

/* Bottom navigation для мобильных */
.bottom-nav {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 100;
  background: #fff;
  border-top: 1px solid #e2e8f0;

  /* iOS safe area — отступ от системной навигации */
  padding-bottom: env(safe-area-inset-bottom);
  padding-bottom: max(env(safe-area-inset-bottom), 8px);
}
<!-- Viewport meta для safe-area -->
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
/* Компенсация на странице — контент не должен быть под navbar */
.page-content {
  padding-bottom: calc(60px + env(safe-area-inset-bottom));
}

Sticky sidebar

/* Sticky sidebar — остаётся при скролле контента рядом */
.sidebar {
  position: sticky;
  top: calc(var(--header-height) + 24px);  /* учитываем sticky header */
  max-height: calc(100vh - var(--header-height) - 48px);
  overflow-y: auto;
  overscroll-behavior: contain;
}

Конфликт с anchor-ссылками

position: sticky header перекрывает якорные ссылки. Решение через CSS scroll-margin:

/* Добавляем отступ сверху для всех элементов с id (потенциальных якорей) */
[id] {
  scroll-margin-top: calc(var(--header-height) + 16px);
}

Или JavaScript-версия для устаревших браузеров:

document.querySelectorAll('a[href^="#"]').forEach(link => {
  link.addEventListener('click', (e) => {
    e.preventDefault()
    const targetId = (link as HTMLAnchorElement).hash.slice(1)
    const target = document.getElementById(targetId)
    if (!target) return

    const headerHeight = (document.querySelector('.site-header') as HTMLElement)?.offsetHeight ?? 0
    const top = target.getBoundingClientRect().top + window.scrollY - headerHeight - 16

    window.scrollTo({ top, behavior: 'smooth' })
  })
})

Индикатор прогресса в header

const progressBar = document.createElement('div')
progressBar.style.cssText = `
  position: fixed;
  top: 0;
  left: 0;
  height: 3px;
  background: linear-gradient(to right, #6366f1, #8b5cf6);
  z-index: 9999;
  transition: width 0.1s linear;
  transform-origin: left;
`
document.body.appendChild(progressBar)

window.addEventListener('scroll', () => {
  const scrollable = document.documentElement.scrollHeight - window.innerHeight
  const progress = scrollable > 0 ? (window.scrollY / scrollable) * 100 : 0
  progressBar.style.width = `${progress}%`
}, { passive: true })

Сроки

Sticky header с тенью при скролле — 1–2 часа. С hide-on-scroll анимацией и React-хуком — полдня. С bottom nav, safe-area, sticky sidebar и anchor-фиксом — 1 день.