Прилипающие CSS Grid элементы

Источник: «Sticky CSS Grid Items»
Если вы когда-нибудь пытались разместить прилипающий элемент в макетной сетке grid и наблюдали, как элемент прокручивается вместе с остальным содержимым, вы могли прийти к выводу, что position: sticky не работает с CSS Grid.

Проблема

Давайте начнём с основной проблемы, с которой вы, вероятно, столкнётесь, потому что сначала не всегда очевидно, почему ваш grid-элемент не прилипает.

Допустим, мы собираем шаблон макета для статей о различных сладостях. У нас есть заголовок в левом столбце grid макета, и мы установили его "липким":

article {
display: grid;
grid-template-columns: 20em 1fr;
grid-gap: 4em;
}

.title {
position: sticky;
top: 2rem;
}

К сожалению, наш заголовок не прилипает к верхней части области просмотра, а вместо этого прокручивается с остальным текстом. Посмотреть пример на CodePen.

Если мы добавим границы (border: 10px solid;) к нашему "липкому" заголовку (или используем инспектор GSS Grid), наша основная проблема станет более очевидной. Посмотреть пример на CodePen.

Алгоритм изменения размера элементов CSS Grid эффективно определяет размер grid элемента (нашего "липкого" заголовка), что бы заполнить высоту grid слота, в который он был помещён. Мы не видим ни каких эффектов "прилипания", потому что его вычисленная высота такая же, как и у содержимого в соседнем grid слоте.

Мелкие подробности о размерах

Сейчас всё станет скучным, просто перейдите к раздела "Как это исправить", если нужно только решение проблемы!

Поскольку мы не использовали какие-либо CSS свойства определяющие размер наших grid элементов (скоро мы к ним вернёмся), CSS Grid по умолчанию использовал свой "нормальный" алгоритм определения размера при определении размера "липкого" заголовка.

Наш заголовок h1...

...поэтому алгоритм вернулся к "растянутой" схеме определения размеров. В основном это гарантирует, что размер блока в этом измерении установлен таким образом, что бы заполнять контейнер макета в котором он находится (или упрощая grid слот).

Как это исправить

Один из способов решения этой проблемы - указать внешний размер высоты для нашего "липкого" заголовка, например: height: 10em, max-height: 50vh, или что-то подобное. Однако указывать конкретную высоту для нашего контента это халтура, на м не нужна конкретная высота, мы хотим, что бы вычисленная высота была достаточной для размещения содержимого элемента. Вместо этого мы можем изменить способ выравнивания этого элемента по grid слоту.

Мы можем указать одно из следующих свойств:

place-self и place-items так же будут работать; они обрабатывают обе оси, ось блока (или ось столбца) и внутренней оси (или ось строки)

Было бы неплохо выровнять базовую линию текста нашего "липкого" заголовка и базовую линию текста первого абзаца. Если мы установим align-items: baseline; в article, которая заставляет алгоритм определения размера использовать схему "подгонки содержимого". В этом есть некоторая сложность, но в нашем случае алгоритм использовал "максимальный размер содержимого" нашего grid элемента или "наименьший размер, который блок может занимать по этой оси, при этом всё ещё вписываясь в его содержимое".

Поскольку размер "липкого" заголовка теперь изменяется в соответствии с его содержимым, мы получаем поведение position: sticky, которое нам нужно. Посмотреть пример на CodePen.

Наши обновлённые стили:

article {
display: grid;
grid-template-columns: 20em 1fr;
grid-gap: 4em;

/* The new line we added! */
align-items: baseline;
}

.title {
position: sticky;
top: 2rem;
}

Вот и всё! Надеюсь это поможет вам выйти из "липкой" ситуации.

Дополнительные материалы

Предыдущая Статья

Объяснение Git: Диапазоны коммитов

Следующая Статья

Отзывчивые макеты, меньше медиа запросов