Верстка с помощью CSS Grid Layout
23-07-2018Время чтения ~ 8 мин.CSS, HTML, LESS, SASS 9818
Спецификация по Grid Layout опубликована уже достаточно давно, но вебмастера всё ещё редко используются grid-вёрстку. Тут две основные причины. Первая — распространенность IE11 (по статистике около 2%), которая, к тому же поддерживает только старую версию спецификации. Вторая — реальная потребность в grid не очень высока: существующего flex хватает для 90% стоящих задач.
C другой cтороны, все современные браузеры уже полноценно поддерживают grid, поэтому можно потихонечку разбираться в его основах и решать некоторые задачи.
Grid — это не flex
Flex — тоже сетка, но с предопределенным поведением, когда ячейки всегда располагаются вдоль основной оси. Grid — более гибкий инструмент, который оперирует ячейками уже в более привычном для нас понимании — строками и столбцами.
Grid очень похож на Flex. Более того, grid позволяет оперировать новыми сущностями, которых не хватает во flex — области ячеек, линии между строками/столбцами, зазоры и т.д. Поэтому, если стоит задача сделать сложную сетку, то grid — хороший выбор.
Основы построения grid-сетки
Как и во flex, для задания grid используется только контейнер, в котором все непосредственные потомки будут являться ячейками.
<style>
.grid1 { display: grid; }
</style>
<div class="grid1">
<div class="pad10 bg-gray100">A</div>
<div class="pad10 bg-gray200">B</div>
<div class="pad10 bg-gray300">C</div>
<div class="pad10 bg-gray400">D</div>
</div>
В данном случае у нас сетка из 4-х ячеек. Поскольку мы ещё не задали «формат» сетки, то браузер их отобразил как обычные блоки.
В примерах я буду использовать классы Berry CSS.
Для задания «формата» сетки используются свойства контейнера grid-template-columns и grid-template-rows.
<style>
.grid2 {
display: grid;
grid-template-columns: 100px 200px 300px;
}
</style>
<div class="grid2">
<div class="pad10 bg-gray100">A</div>
<div class="pad10 bg-gray200">B</div>
<div class="pad10 bg-gray300">C</div>
<div class="pad10 bg-gray400">D</div>
</div>
В данном примере я указал три колонки с разной шириной. Теперь добавим размеры строк.
<style>
.grid3 {
display: grid;
grid-template-columns: 100px 200px 300px;
grid-template-rows: 50px 100px;
}
</style>
<div class="grid3">
<div class="pad10 bg-gray100">A</div>
<div class="pad10 bg-gray200">B</div>
<div class="pad10 bg-gray300">C</div>
<div class="pad10 bg-gray400">D</div>
</div>
Если бы мы делали такую сетку на flex, то пришлось указывать размеры у самих ячеек. Здесь же мы всё ещё работаем с контейнером.
Единица измерения fr
В качестве единиц измерения, можно использовать привычные пиксели или проценты, но лучше использовать «фракцию» (fraction) — долю. По поведению она похожа на flex-свойство grow («жадность»).
<style>
.grid4 {
display: grid;
grid-template-columns: 1fr 2fr 3fr;
grid-template-rows: 50px 100px;
}
</style>
<div class="grid4">
<div class="pad10 bg-gray100">A</div>
<div class="pad10 bg-gray200">B</div>
<div class="pad10 bg-gray300">C</div>
<div class="pad10 bg-gray400">D</div>
</div>
Расчёт примерно такой: 1fr 2fr 3fr = 6fr, следовательно 3fr = 50% всей ширины сетки, 2fr = 1/3 и 1fr = 1/6 части.
Если все колонки/строки одинаковые, то можно использовать функцию repeat(колво, размер)
:
<style>
.grid5 {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: 50px 100px;
}
</style>
<div class="grid5">
<div class="pad10 bg-gray100">A</div>
<div class="pad10 bg-gray200">B</div>
<div class="pad10 bg-gray300">C</div>
<div class="pad10 bg-gray400">D</div>
</div>
Кроме этого, часто нужно указывать размеры ячеек в каком-то диапазоне. Например колонка может быть от 100px до 200px. Для таких задач используется функция minmax(минимум, максимум)
.
<style>
.grid6 {
display: grid;
grid-template-columns: minmax(100px, 200px) 2fr 3fr;
grid-template-rows: 50px 100px;
}
</style>
<div class="grid6">
<div class="pad10 bg-gray100">A</div>
<div class="pad10 bg-gray200">B</div>
<div class="pad10 bg-gray300">C</div>
<div class="pad10 bg-gray400">D</div>
</div>
Зазоры между ячейками
Зазоры (gap) — это что-то вроде padding/margin, только без привязки к самим ячейкам. Свойство grid-gap задаёт зазоры между строками и столбцами.
<style>
.grid7 {
display: grid;
grid-template-columns: minmax(100px, 200px) 2fr 3fr;
grid-template-rows: 50px 100px;
grid-gap: 10px 30px;
}
</style>
<div class="grid7">
<div class="pad10 bg-gray100">A</div>
<div class="pad10 bg-gray200">B</div>
<div class="pad10 bg-gray300">C</div>
<div class="pad10 bg-gray400">D</div>
</div>
Задание области
Ячейки можно задавать в виде «области» (area). Сделать это можно с помощью grid-template-areas и grid-area.
<style>
.grid8 {
display: grid;
grid-template-columns: 1fr 2fr 2fr 1fr;
grid-template-rows: auto;
grid-template-areas: "a a a a"
"b b c c"
"d d d d";
}
.grid8 .item-a { grid-area: a; }
.grid8 .item-b { grid-area: b; }
.grid8 .item-c { grid-area: c; }
.grid8 .item-d { grid-area: d; }
</style>
<div class="grid8">
<div class="item-a pad10 bg-gray100">A</div>
<div class="item-b pad10 bg-gray200">B</div>
<div class="item-c pad10 bg-gray300">C</div>
<div class="item-d pad10 bg-gray400">D</div>
</div>
То есть каждая ячейка может иметь идентификатор (class, id), которому задаётся имя в пределах grid-шаблона. В grid-template-columns указываются колонки, а в grid-template-areas их имя в пределах сетки. Через grid-area мы связываем эти ячейки с областями сетки.
На базе этой схемы можно формировать произвольные области ячеек.
<style>
.grid9 {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: 50px 100px 50px;
grid-template-areas: "a a c c"
"b b c c"
"b b d d";
}
.grid9 .item-a { grid-area: a; }
.grid9 .item-b { grid-area: b; }
.grid9 .item-c { grid-area: c; }
.grid9 .item-d { grid-area: d; }
</style>
<div class="grid9">
<div class="item-a pad10 bg-gray100">A</div>
<div class="item-b pad10 bg-gray200">B</div>
<div class="item-c pad10 bg-gray300">C</div>
<div class="item-d pad10 bg-gray400">D</div>
<div class="pad10 bg-green100">E</div>
<div class="pad10 bg-green200">F</div>
<div class="pad10 bg-green300">G</div>
<div class="pad10 bg-green400">H</div>
</div>
Следует учитывать, что области должны быть прямоугольными.
Обратите внимание на зеленые ячейки, которые не имеют идентификации в сетке. Браузер их выводит уже «обычными». То есть способ задания областей может комбинироваться с «типовым» поведением ячеек.
Индивидуальное поведение ячеек
Также можно задать индивидуальное поведение ячеек с помощью свойств
grid-column-start: 1;
grid-column-end: 4;
grid-row-start: 1;
grid-row-end: 2;
По сути это тоже самое, что и с помощью grid-template-areas, только отдельными свойствами.
<style>
.grid10 {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
}
.grid10 .item-a {
grid-column-start: 1;
grid-column-end: 4;
}
.grid10 .item-b {
grid-column-start: 1;
grid-column-end: 3;
}
</style>
<div class="grid10">
<div class="item-a pad10 bg-gray100">A</div>
<div class="item-b pad10 bg-gray200">B</div>
<div class="item-c pad10 bg-gray300">C</div>
<div class="item-d pad10 bg-gray400">D</div>
</div>
Здесь нужно учитывать, что расположение ячейки указывается между грид-треками, а не между грид-линиями. Поскольку у нас 4 колонки, то треков будет 5.
Именно поэтому в ячейке A последняя секция оказалась пустой, а вторая ячейка B заняла две секции.
При таком задании положения, может возникнуть ситуация, когда ячейки окажутся в одной позиции. Для grid-сетки это нормальное поведение и чтобы определить какая ячейка должна быть сверху используется привычное z-index. Посмотрите на пример, где ячейки A и B накладываются друг на друга, но слой A поднимаем выше.
<style>
.grid11 {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
}
.grid11 .item-a {
grid-column-start: 1;
grid-column-end: 4;
grid-row-start: 1;
grid-row-end: 2;
z-index: 1;
}
.grid11 .item-b {
grid-column-start: 1;
grid-column-end: 5;
grid-row-start: 1;
grid-row-end: 2;
}
</style>
<div class="grid11">
<div class="item-a pad10 bg-yellow400">A</div>
<div class="item-b pad10 bg-blue300 t-right">B</div>
<div class="item-c pad10 bg-gray300">C</div>
<div class="item-d pad10 bg-gray400">D</div>
</div>
Такой приём удобно использовать, когда нужно задать поведение индивидуальной ячейки. В html-коде просто задаётся класс ячейки, а в css уже его положение. Если же нужно задать поведение всей сетки, то лучше всё-таки сделать это в контейнере с помощью grid-template-areas.
Короткие записи свойств
Разработчики CSS Grid Layout постарались на славу. Многие grid-свойства можно задать короткой записью. Я не привожу примеры, поскольку их слишком много (например свойство grid) и это пугает. Разобраться, так с ходу, довольно сложно, поэтому я думаю, что лучше запомнить азы, а дальше уже двигаться в сторону усложнений.
Применение Grid
Совершенно очевидно, что grid следует применять там, где подразумевается сложное расположение элементов/блоков. С точки зрения адаптивности, grid — не самый лучший выбор, поскольку он оперирует сразу двумя коордионатами, что делает его использование более сложным чем flex.
Второй момент — grid очень сильно завязан на верстку конкретной сетки. Это не позволяет вынести его верстку на уровень HTML в виде css-классов (atomic design).
Поэтому правило довольно простое: там где можно использовать flex, grid использовать не стоит. :-)
Здравствуйте!
Обалденные у Вас статьи. Дар у Вас -доходчиво объяснять.
Пара пожеланий:
Сам текст ответа даже не обязательно присылать (SEO все таки, пусть кликают). А вот сканить все статьи в поисках своих комментов и возможных ответов - это ужас.
https://max-3000.com/page/donation
Зарегистрируйтесь на сайте, будет уведомление. Либо используйте RSS.