Делаем блок, в котором шапка залипает при прокрутке без JS
Опубликовано 26 сент. 2024 г.
Относительно недавно ко мне обратился клиент, занимающийся разработкой своего сайта-блога про криптовалюту, блокчейн и всякое такое. Большую часть работы человек сделал сам, используя визуальные редакторы на одной известной системе управления контентом, но с одним пунктом у клиента возникли проблемы.
Оказывается у данной темы огромное количество терминов - и официальных, и прошедших через перефразирование и русификацию в увлекающемся этой историей народе. Для этого вороха неологизмов и англицизмов срочно нужен был предметно-именной указатель, или глоссарий, или словарь, называйте как хотите. И чтобы по алфавиту. Вот его то я и сделал.
Глоссарий моей мечты
Не стал сильно грузится, заказчик сам хотел как можно проще и без лишнего кода, поэтому вверху страницы глоссария разместил буквы в алфавитном порядке, а ниже список терминов и их определений. Про клике на букву происходил скролл на блок терминов, начинающихся с данной буквы. Решение так себе, но клиенту нужно было подешевле и побыстрее. Помнится, что я делал что-то похожее на Ghost CMS, но с использованием скрипта, который вписанные на страницу термины препарировал, извлекал из них первые буквы, и сам вставлял их вверх страницы, создавая из них якорные ссылки к нужному блоку терминов. Здесь ситуация попроще, никаких скриптов, чистый scroll-behavior: smooth
.
Спустя пару дней заказчик вернулся с новой идеей. Показал мне анимацию, где на мобильном при прокрутке глоссария, буква вверху блока залипала до момента пока ее снизу не подбивала исчезнуть с экрана другая буква. Объяснять долго, вот вам ниже гифка (вообще-то видео, но похоже на гифку).
Я объяснил что сделать такое без скрипта не получится, а первоначальная идея, вроде бы, была именно в том, что обойтись без сложностей. «Ну, может есть решение без скриптов», - сказал клиент. Я ответил, что поищу, хотя делать этого не собирался, ведь точно без скриптов такого не сделать, как я думал тогда. Однако от скуки загуглил, или яндексанул (как там теперь правильно?) и нашел чудесный и очень простой, как оказалось, трюк. О нем и расскажу далее.
Я графоман, очень люблю писать, но ниже есть код, который можно скопировать себе и не читать все, что я тут пишу. Хотя мне было бы приятно, если бы вы читали
Скроллим чужие списки
Один креативный разработчик с западно-европейских берегов по имени Филипп Браунен пытался сделать залипающий хэдер, который мог бы вписаться в общую высоту контейнера и при этом нормально координироваться с другими элементами для создания вместе с ними общей высоты. Спойлер: ему это почти удалось, но с костылями, которые всегда возникают когда приходится делать фиксированную шапку и при этом не уродовать нижестоящий блок несуразными отступами, заступами и еще какими-нибудь затупами (я не про себя 😀).
Хорошим решением для такого эффекта является использование position: sticky
. Автор его и использовал, но под его задачи, нужно было использовать еще много чего из CSS. Потому что sticky
сочетает в себе два других вида позиционирования и находится в потоке документа в позиции relative
до тех пор, пока не достигнет краев своего прокручиваемого родительского контейнера, после чего занимает позицию fixed
.
Элемент с position: fixed
не заботится о родителе, в котором он находится, или о любом из его предков. Он вырвется из потока документа и разместится непосредственно в том месте, где вы ему укажете с помощью свойств top
, left
и так далее, оставаясь в зоне видимости на экране. А sticky-элемент с удовольствием сбежит из области просмотра, но никогда не выйдет за пределы границ своего прямого родителя.
Последнее свойство position: sticky
, как оказалось, можно использовать для создания того, что мне было поручено заказчиком - прокручиваемый глоссарий с закреплением вверху текущей буквы, с которой начинаются термины.
Теперь код.
Прокручиваем и прилепляем
Итак, основная идея состоит в том, чтобы создать список, состоящий из нескольких блоков, вверху каждого из которых должен быть «липкий хэдер».
<section class="roll">
<div class="roll-list">
<h2 class="roll-sticky">Буква</h2>
<ul>
<li></li>
<li></li>
<li></li>
</ul>
</div>
<div class="roll-list">
<h2 class="roll-sticky">Буква</h2>
<ul>
<li></li>
<li></li>
<li></li>
</ul>
</div>
<div class="roll-list">
<h2 class="roll-sticky">Буква</h2>
<ul>
<li></li>
<li></li>
<li></li>
</ul>
</div>
</section>
Элементов с классом .roll-list
может быть сколько угодно, главное не забыть в каждый из них добавить вверху залипающий заголовок, в моем случае roll-sticky
.
Далее нужно побеспокоиться о CSS. Сначала сделаем родитель прокручиваемым и ограничим его высоту. Последнее нам необходимо, чтобы появился эффект залипания. У меня тут небольшой элемент для примера, но если вы будете делать что-то большее, то можно указать высоту равную хоть 100vh.
.roll {
max-height: 18rem;
overflow-y: scroll;
}
Из обязательного у нас остается лишь задать нужные объявления непосредственно для залипающей шапки. Обязательно указываем top: 0
, чтобы элемент понял, что ему нужно оказаться вверху.
.roll-sticky {
position: sticky;
top: 0;
}
Можно добавить ряд стилей для того, чтобы все выглядело более или менее красиво. В CodePen ниже я добавил рамки, отступы и цвета, но обязательными же правилами являются лишь те, что находятся чуть выше.
Вот весь код:
Вот такое простое решение для такой нетривиальной задачи. Добавить здесь собственно нечего. Все работает как нужно. Возможно и вам такой эффект без JavaScript когда-нибудь пригодится для работы или для своих собственных проектов.
Спасибо, что дочитали статью. Я буду продолжать искать интересные CSS-решения, так как это очень увлекательно, и позволяет отдохнуть от однообразных трудовых будней. Всего доброго 👋