Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Прокрутка

Прокрутку браузер делает сам, но CSS умеет её настроить: сделать переход к якорю плавным, остановить карусель точно на слайде, не дать прокрутке «перетечь» на страницу. В примерах прокручивается не окно, а блок с overflow: auto из урока о переполнении — свойства работают одинаково.

Плавная прокрутка

Ссылка вида <a href="#prices"> из урока о ссылках мгновенно перебрасывает к нужному месту. scroll-behavior: smooth делает этот переход плавным. В примере вместо ссылок кнопки: они делают такой же переход из JavaScript, а container: 'nearest' просит прокрутить только ближайший блок, а не всю страницу урока:

<style>
  .box { height: 140px; overflow: auto; scroll-behavior: smooth; border: 1px solid silver; }
  .box p { height: 120px; margin: 0; padding: 8px; }
</style>
 
<button onclick="document.querySelector('#end').scrollIntoView({ container: 'nearest' })">Вниз</button>
<button onclick="document.querySelector('#start').scrollIntoView({ container: 'nearest' })">Наверх</button>
<div class="box">
  <p id="start">Начало</p>
  <p>Середина</p>
  <p id="end">Конец</p>
</div>

Для всей страницы правило пишут так: html { scroll-behavior: smooth; }.

Якорь под липкой шапкой

Если шапка прилипает к верху (position: sticky или fixed), при переходе к якорю заголовок раздела прячется под ней. scroll-margin-top оставляет над целью отступ:

<style>
  .page { height: 160px; overflow: auto; border: 1px solid silver; }
  .page header { position: sticky; top: 0; padding: 8px; background: steelblue; color: white; }
  .page section { height: 150px; padding: 0 8px; scroll-margin-top: 44px; }
</style>
 
<button onclick="document.querySelector('#delivery').scrollIntoView({ container: 'nearest' })">К доставке</button>
<div class="page">
  <header>Магазин</header>
  <section><h3>Каталог</h3></section>
  <section id="delivery"><h3>Доставка</h3></section>
  <section><h3>Контакты</h3></section>
</div>

Отступ равен высоте шапки с небольшим запасом. Уберите scroll-margin-top — заголовок «Доставка» окажется под шапкой.

Карусель: scroll-snap

Привязка прокрутки (scroll snap) останавливает прокрутку точно на элементе, а не где придётся. Контейнеру задают scroll-snap-type, элементам — точку привязки scroll-snap-align. Прокрутите ленту вбок:

<style>
  .carousel { display: flex; gap: 8px; overflow-x: auto; scroll-snap-type: x mandatory; }
  .slide { flex: 0 0 80%; height: 100px; display: grid; place-items: center; scroll-snap-align: center; color: white; font-size: 24px; }
</style>
 
<div class="carousel">
  <div class="slide" style="background: tomato;">1</div>
  <div class="slide" style="background: seagreen;">2</div>
  <div class="slide" style="background: steelblue;">3</div>
</div>

Где бы вы ни отпустили ленту, она доедет до ближайшего слайда и выровняет его по центру.

Значения привязки

СвойствоЗначениеЧто делает
scroll-snap-typex или yось, по которой работает привязка
mandatoryвсегда останавливаться на элементе
proximityтолько если остановились рядом с ним
scroll-snap-alignstart, center, endкакой край элемента выравнивать

overscroll-behavior

Когда вложенный блок прокручен до конца, следующие движения колёсика начинают прокручивать страницу. Это называют цепочкой прокрутки. overscroll-behavior: contain останавливает её на границе блока:

<style>
  .lists { display: flex; gap: 8px; }
  .list { flex: 1; height: 110px; overflow: auto; border: 1px solid silver; }
  .list p { margin: 0; padding: 6px 8px; }
  .contain { overscroll-behavior: contain; }
</style>
 
<div class="lists">
  <div class="list"><p>Обычный список</p><p>Анна</p><p>Борис</p><p>Вера</p><p>Глеб</p><p>Дина</p></div>
  <div class="list contain"><p>contain</p><p>Анна</p><p>Борис</p><p>Вера</p><p>Глеб</p><p>Дина</p></div>
</div>

Прокрутите каждый список колёсиком до конца и продолжайте: в левом начнёт прокручиваться страница урока, в правом — нет. Так делают выпадающие меню, чаты и модальные окна.

Частая ошибка

scroll-snap-type пишут элементам, а не контейнеру, — и привязка не работает. Тип привязки задаётся тому, кто прокручивается, а элементам — только scroll-snap-align:

<style>
  .carousel { display: flex; gap: 8px; overflow-x: auto; }
  .slide { flex: 0 0 80%; height: 80px; background: gold; scroll-snap-type: x mandatory; scroll-snap-align: start; }
</style>
 
<div class="carousel">
  <div class="slide">Лента</div>
  <div class="slide">останавливается</div>
  <div class="slide">где попало</div>
</div>

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.