Уменьшающаяся при прокрутке “шапка” страницы без JavaScript

Представьте себе красивую и массивную “шапку” (header) веб-страницы с множеством отступов сверху и снизу от содержимого. Когда страница прокручивается (скроллится) вниз, “шапка” сжимается, уменьшая отступы и содержимое, чтобы оставить больше места на экране для остального контента.

Обычно, чтобы добавить такой эффект уменьшения шапки при скролле страницы, используется немного JavaScript и CSS, но с появлением position: sticky то же самое можно сделать, используя только CSS.

Начинаем, как обычно, с HTML-разметки. Здесь нет ничего сложного: <header> с одним потомком <div>, который, содержит логотип и навигацию.

<header class="header-outer">
  <div class="header-inner">
    <div class="header-logo">...</div>
    <nav class="header-navigation">...</nav>
  </div>
</header>

Затем в CSS, объявим высоту для <header> (120 пикселей) и настроим его как flex-контейнер, который выравнивает содержимое по центру. Затем сделаем его “липким” (sticky).

.header-outer {
  display: flex;
  align-items: center;
  position: sticky;
  height: 120px;
}

Все остальные элементы “шапки”: логотип и навигация – размещаются во внутреннем контейнере. В некотором смысле этот контейнер и является “шапкой”, тогда как единственная функция родительского HTML-элемента <header> – обозначить её размеры, чтобы было что сокращать.

Настроим внутренний контейнер, указываем для .header-inner высоту 70 пикселей и тоже делаем его “липким” (sticky).

.header-inner {
  height: 70px;
  position: sticky;
  top: 0; 
}

Для чего top: 0;? Это нужно для того, чтобы контейнер, когда он становится “липким” (sticky), крепился к самому верху окна.

А теперь хитрость! Чтобы внутренний контейнер прилипал к верхнему краю страницы, нужно указать родительскому элементу <header> отрицательное значение top, равное разнице высот между двумя контейнерами, чтобы он прилипал чуть выше окна. Это 70 пикселей минус 120 пикселей, так и напишем -50 пикселей.

.header-outer {
  display: flex;
  align-items: center;
  position: sticky;
  height: 120px;
  /* top равно разнице высот
  между внешним и внутренним
  контейнерами */
  top: -50px;
}

Собираем теперь это всё воедино. <header> выдвигается за пределы экрана, а внутренний контейнер аккуратно помещается в верхней части области просмотра.

See this code Shrinking header on scroll without Javascript on x.xhtml.ru.

Таким образом можно приклеить к верхней части окна любой элемент. Например, важное объявление.

See this code Sticky banner on x.xhtml.ru.

При всём великолепии этого метода приклеивания элементов к верху окна при скролле с помощью только CSS, у него есть ограничения. Например, для внутреннего и внешнего контейнера нужно указать фиксированную высоту. При этом, они становятся уязвимыми для изменений, например, когда элементы навигации переносятся, потому что количество пунктов меню превышает количество отведенного для них места.

Еще одно ограничение? Не уменьшается логотип. Это, пожалуй, самый большой недостаток, поскольку логотипы часто являются самым большим потребителем свободного места. Наверное, когда-нибудь получится применять стили, основанные на липкости элемента…

Поддержка CSS position: sticky в вашем браузере

position: sticky