Позиционирование перекрывающего содержимого с помощью CSS-сетки

Позиционирование перекрывающего содержимого с помощью CSS-сетки

От автора: недавно я экспериментировал с CSS-сеткой и свойствами выравнивания для создания макетов компонентов, содержащих несколько перекрывающихся элементов. Эти макеты могут быть оформлены с использованием абсолютного позиционирования и сочетания значений смещения (top, right, bottom, left), отрицательными полями и преобразованиями.

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

Расширение изображений в ограниченном размере

В демонстрации есть checkbox, который переключает видимость переполнения, чтобы мы могли видеть, где размеры изображения выходят за пределы контейнера при большей ширине области просмотра.

Вот обычный hero-раздел с заголовком, перекрывающим изображение. Несмотря на то, что изображение имеет верхнюю границу max-width, при отображении на настольном компьютере оно становится достаточно высоким. Из-за этого команда контентной стратегии попросила, чтобы часть соответствующего контента страницы, оставалась видимой в области просмотра в максимально возможной степени. Комбинируя технику компоновки и свойство контейнера max-height используя функцию CSS clamp(), мы можем разработать что-то, что настраивается на основе доступного пространства окна просмотра, при этом hero-изображение привязано к центру контейнера.

Откройте этот CodePen и измените размер окна просмотра. В зависимости от размеров изображения высота контейнера увеличивается, пока не достигнет максимальной высоты. Обратите внимание, что изображение продолжает расти, оставаясь в центре контейнера. Измените размер области просмотра, и контейнер будет изменятся между значениями нижней и верхней границы, определенными в функции clamp().

Прежде чем использовать сетку для стилей макета, я мог бы попробовать абсолютное позиционирование на изображении и заголовке, использовать трюк с заполнением соотношения сторон, чтобы создать отзывчивую высоту и сохранить соотношение изображения object-fit. Могло бы получиться что-то вроде этого:

.container { position: relative; max-height: clamp(400px, 50vh, 600px);
} .container::before { content: ''; display: block; padding-top: 52.25%;
} .container > * { max-width: 1000px;
} .container .image { position: absolute; top: 0; left: 50%; transform: translateX(-50%); width: 100%; height: 100%; object-fit: cover;
} .container .title { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 100%; text-align: center;
}

Возможно, можно еще немного урезать код, но все же необходимо сохранить хороший стиль. Управление одним и тем же адаптивным макетом с помощью CSS Grid упростит правила стиля макета, сделав код более читабельным. Посмотрите на следующий код:

.container { display: grid; grid-template: "container"; place-items: center; place-content: center; overflow: hidden; max-height: clamp(450px, 50vh, 600px);
} .container > * { grid-area: container; max-width: 1000px;
}

place-content:center указывает изображению продолжать расти из середины контейнера. Удалите эту строку и посмотрите, что, хотя изображение все еще находится в вертикальном центрировании place-items, как только будет достигнута точка max-height, изображение будет прилипать к верхней части блока контейнера и продолжит масштабирование за его нижнюю часть. Установив place-content:end center вы увидите, как изображение выходит за границы контейнера.

Это поведение может показаться концептуально похожим на применение object-fit: cover к изображению в качестве метода стилизации для сохранения его внутреннего соотношения при изменении размера для заполнения размеров всего содержимого. Однако в этом контексте сетки элемент изображения управляет высотой своего родителя, и при достижении max-height родительского элемента изображение продолжает расширяться, сохраняя свое соотношение, и остается полностью видимым, если отображается родительское переполнение. object-fit можно даже использовать со свойством aspect-ratio, чтобы создать согласованный шаблон соотношения сторон для hero-изображения:

.container .image { width: 100%; height: auto; object-fit: cover; aspect-ratio: 16 / 9;
}

Перекрытие grid-area

Перейдем к дочерним элементам контейнера, grid-area расположит каждый из них так, чтобы они перекрывали одно и то же пространство. В этом примере именованная область сетки grid-template-areas делает код более читабельным и хорошо работает в качестве шаблона для других макетов перекрытия компонентов. При этом можно получить тот же результат, удалив правило шаблона и вместо grid-area:container использовать целые числа:

.container > * { grid-area: 1 / 1;
}

Это сокращение для grid-row-start, grid-column-start, grid-row-end, и grid-column-end. Поскольку все наследники в этой демонстрации используют одну и ту же область строки /столбца, для достижения желаемого результата необходимо установить только начальные строки.

Использование place-self

Другой распространенный шаблон наложения можно увидеть на каруселях изображений. Интерактивные элементы часто размещаются поверх области просмотра карусели. Я расширил первую демонстрацию и заменил статичное hero-изображение каруселью.

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

Позиционирование перекрывающего содержимого с помощью CSS-сетки

С объявлением в контейнере place-items:center все его прямые дочерние элементы будут перекрывать друг друга

Следующим шагом является установка значений выравнивания для отдельных элементов. Свойство-сокращение place-self для align-self и justify-self обеспечивает точный контроль над положением элемента внутри контейнера. Вот и все стили макета:

.container { display: grid; grid-template:"container"; place-items: center; place-content: center; overflow: hidden; max-height: clamp(450px, 50vh, 600px);
} .container > * { grid-area: container; max-width: 1000px;
} .title { place-self: start center;
} .carousel-control.prev { place-self: center left;
} .carousel-control.next { place-self: center right;
} .carousel-dots { place-self: end center;
}

Есть только одна небольшая проблема: индикаторы заголовка и карусели вытягиваются наружу, когда изображение превышает размеры контейнера.

Чтобы правильно содержать эти элементы в родительском элементе, значение grid-template-row должно составлять 100% контейнера, установленное здесь как одна дробная единица.

.container { grid-template-areas: "container"; grid-template-rows: 1fr;
}

Для этой демонстрации я опирался на сокращение grid-template (которую мы увидим позже в этой статье еще раз).

.container { grid-template: "container" 1fr;
}

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

Выравнивание grid-template-areas

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

Для первой итерации объявляется именованная область шаблона для наложения дочерних элементов на пространство родительских элементов, как и в предыдущих демонстрациях:

.box { display: grid; grid-template-areas: "box";
} .box > *,
.box::before { grid-area: box;
}

Изображение и полупрозрачное наложение теперь покрывают область блока, но правила стиля также растягивают другие элементы по всему пространству. Похоже, сейчас подходящее время для того, чтобы добавить к этим элементам магию выравнивания place-self!

.tag { place-self: start;
} .title { place-self: center;
} .tagline { place-self: end start;
} .actions { place-self: end;
}

Выглядит отлично! Каждый элемент размещается в своих определенных местах на изображении, как задумано. Ну, почти. В нижней части, где расположены слоган и кнопки действий, есть небольшой нюанс. Наведите указатель мыши на изображение, чтобы открыть слоган. Это может хорошо выглядеть с короткой строкой текста на экране рабочего стола, но если слоган станет длиннее (или поля в окне просмотра уменьшатся), он в конечном итоге выйдет за кнопки действий.

Позиционирование перекрывающего содержимого с помощью CSS-сетки

Обратите внимание, как слоган в первом столбце во втором ряду перекрывает кнопки действий

Чтобы избавится от этого, в grid-template-areas будем использовать именованные области для слогана и действий.

.box { display: grid; grid-template-areas: "tagline actions"; grid-template-columns: 1fr auto;
}

Это также можно комбинировать с сокращением grid-template. Значения столбца определяются после косой черты, например:

.box { grid-template: "tagline actions" / 1fr auto;
}

Затем, grid-area преобразуется в integer и ключевое слово box будет удалено.

.box > *,
.box::before { grid-area: 1 / 1 / -1 / -1;
}

Все должно выглядеть так, как было раньше. Теперь последний штрих. Устанавливаем соответствующие значения grid-area для ключевых слова tagline и actions:

.tagline { grid-area: tagline; place-self: end start;
} .actions { grid-area: actions; place-self: end;
}

vТеперь, при наведении курсора на карточки в демонстрации, слоган переносится на несколько строк, когда текст становится слишком длинным, вместо того, чтобы проходить мимо кнопок действий, как это было раньше.

Именованные линии сетки

Оглядываясь назад на первую итерацию этого кода, мне очень понравилось, что по умолчанию для grid-area было установлено ключевое слово box. Есть способ вернуть это.

Я собираюсь добавить в шаблон несколько именованных линий сетки. В приведенном ниже правиле grid-template первая строка определяет именованные области шаблона, которые также представляют строку. После косой черты указаны явные размеры столбцов (перенесены в новую строку для удобства чтения). Пользовательские идентификаторы [box-start] и [box-end] представляют область box.

.box { display: grid; grid-template: [box-start] "tagline actions" [box-end] / [box-start] 1fr auto [box-end];
} .box > *,
.box::before { grid-area: box;
}

Передача имени с –start и –end в скобках определяет область для этого имени. Это имя, известное как пользовательский идентификатор, может быть любым, кроме слов из спецификации CSS, которых следует избегать.

Значения логического размещения

Одна из действительно интересных частей для наблюдения в последнем примере — использование логических значений, таких как start и end, для размещения элементов. Если изменить значения direction или writing-mode, то элементы будут переставлены соответствующим образом.

Когда в раскрывающемся списке выбрано направление «справа налево», начальная и конечная позиции инлайн меняются местами. Этот макет готов для работы с такими языками, как арабский или иврит, которые читаются справа налево, без необходимости переопределять какой-либо из существующих CSS.

Заключение

Я надеюсь, что вам понравились эти демонстрации и что они предоставляют некоторые новые идеи для макетов ваших собственных проектов — я собрал коллекцию примеров, которые вы можете посмотреть на CodePen. В спецификации CSS Grid заложена невероятная мощь. Найдите минутку, чтобы поразмышлять о использовании float и clearfix для примитивного дизайна сетки, а затем вернитесь в наши дни и взгляните на великолепный макет и свойства отображения сегодняшнего CSS. Сделать так, чтобы эти вещи работали хорошо — непростая задача, поэтому давайте аплодируем членам рабочей группы CSS. Веб продолжает развиваться, и рабочая группа CSS продолжает делать его интересным местом для творчества.

Автор: Ryan Mulligan

Источник: css-tricks.com

Редакция: Команда webformyself.

Читайте нас в Telegram, VK, Яндекс.Дзен