Верстка с помощью CSS Grid Layout
23-07-2018Время чтения ~ 8 мин.CSS, HTML, LESS, SASS 9310
Спецификация по 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 использовать не стоит. :-)
Здравствуйте!
Обалденные у Вас статьи. Дар у Вас -доходчиво объяснять.
Пара пожеланий:
- ссылка: куда можно кинуть донат
- сделайти плз уведомление на email комментатору о том, что ему ответили.
Сам текст ответа даже не обязательно присылать (SEO все таки, пусть кликают). А вот сканить все статьи в поисках своих комментов и возможных ответов - это ужас.
https://max-3000.com/page/donation
Зарегистрируйтесь на сайте, будет уведомление. Либо используйте RSS.