Фиксирующаяся при скролле панель навигации, только CSS

Как закрепить панель навигации в верхней части страницы только с помощью CSS и не скроллить её вместе с контентом.

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

Чтобы получить аналогичный эффект, можно использовать только простое CSS-свойство.

position: sticky

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

.sticky {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
}
<nav class="sticky">
  <ul>
    <li><a href="#a">Section A</a></li>
    <li><a href="#b">Section B</a></li>
    <li><a href="#c">Section C</a></li>
    <li><a href="#d">Section D</a></li>
  </ul>
</nav>

See this code position sticky on x.xhtml.ru.

На первый взгляд всё работает нормально. Но, если приглядеться, клик по ссылке в навигации скроллит контент так, что заголовок секции самым бесстыдным образом оказывается под зафиксировавшейся панелью с навигацией. Это поправимо.

scroll-margin-top

Свойство scroll-margin-top укажет браузеру высоту отступа, которую он должен использовать при скролле к контейнеру. Это свойство следует указывать элементам с якорями, на которые ведут ссылки из панели навигации.

Добавим контейнерам свойство scroll-margin-top и присвоим ему значение 1em. Теперь, когда браузер перейдёт по ссылке к якорю, он оставит сверху отступ 1em.

И ещё: этот отступ применяется только к прокрутке. Сам элемент-контейнер по-прежнему сохраняет свои обычные отступы в контексте документа.

See this code position sticky on x.xhtml.ru.

HTML-код примера фиксирующейся при прокрутке панели навигации

<h1>Scroll Margin</h1>

<nav class="sticky">
  <ul class="list-inline">
    <li><a href="#a">Section A</a></li>
    <li><a href="#b">Section B</a></li>
    <li><a href="#c">Section C</a></li>
    <li><a href="#d">Section D</a></li>
  </ul>
</nav>

<main>
  <article class="section" id="a"><h2>Section A</h2></article>
  <article class="section" id="b"><h2>Section B</h2></article>
  <article class="section" id="c"><h2>Section C</h2></article>
  <article class="section" id="d"><h2>Section D</h2></article>
</main>

CSS-код примера фиксирующейся панели скролл-навигации

body {
  margin: 0 auto;
  max-width: 40em;
  width: 88%;
}

.section {
  color: #ffffff;
  height: 75vh;
  margin: 0;
  scroll-margin-top: 1em;
}

#a { background-color: #0074d9; }
#b { background-color: #2ecc40; }
#c { background-color: #ff851b; }
#d { background-color: #b10dc9; }

h2 {
  margin: 0;
  padding: 0;
}

.sticky {
  background-color: #ffffff;
  position: -webkit-sticky;
  position: sticky;
  top: 0;
}

.list-inline {
  list-style: none;
  margin-left: -0.5em;
  margin-right: -0.5em;
  padding: 0;
}

.list-inline > li {
  display: inline-block;
  margin-left: 0.5em;
  margin-right: 0.5em;
}

.list-inline > li:before {
  content: "\200B"; /* 1 */
  position: absolute; /* 2 */
}

Пара слов о поддержке position: sticky и scroll-margin-top браузерами

Свойство position: sticky работает во всех современных браузерах, но на момент написания этой заметки не работает с элементами thead и tr в Chrome и Edge (хотя оно работает с th), а также table в Firefox.

Свойство scroll-margin-top работает во всех современных браузерах.

Оба CSS свойства не работают в маргинальном IE-11 и более старых версиях IE.

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

position: sticky