Каждый, кто хотя бы немного занимался созданием веб-сайтов, знает, что теги <div>
— являются важным строительным блоком для контроля над макетом.
HTML5 представил новые семантические элементы, чтобы помочь в этом. И хотя они являются фантастическим дополнением к языку, они немного похожи на украшение к нашему супу из <div>
элементов.
С приходом CSS Grid, нам больше не нужно полагаться на элементы <div>
для создания структуры страницы или даже более сложного компонента. Структура буквально определяется родительским элементом, а не тем, как расположено содержимое внутри него.
Это значит, что мы можем получить хороший простой макет, который структурирует содержимое, не обращая внимание на то, как оно изначально организовано с помощью элементов <div>
.
CSS Grid может быть сложным, но и Flexbox тоже
Я слышал о жалобах множества людей, что Grid слишком сложны и что Flexbox отлично справляется с теми же задачами. Я бы сказал, что им просто комфортно использовать Flexbox и поэтому нет желания дополнительно изучать CSS Grid.
Технология CSS Grid действительно вводит множество новых свойств и значение, так что да, есть кривая обучения. Но и Flexbox также довольно сложен.
Можете ли вы рассказать о преимуществах использования свойства flex-basis
вместо width
? Или как Flexbox рассчитывает ширину flex-элементов, если мы её явно не задали?
Например, если вы покажете приведённый ниже пример тому, кто никогда не использовал Flexbox, как вы объясните тот факт, что в нём заданы одинаковая разметка и одинаковые стили для обоих наборов столбцов? Что ещё хуже, второй столбец в обоих случаях имеет ширину 50%. Очевидно, что ширина со значением 50% на самом деле не устанавливает размер элемента в 50%.
«Что ж, всё начинается с того, что элементы сжимаются, если в контейнере недостаточно места, поэтому, даже если мы установили элементу ширину = 50%, места ему не хватает, поэтому он начинает сжиматься, чтобы втиснуться в контейнер, так как другой <div>
требует больше места. 50% — это скорее идеальный размер для блока, а не размер фактический.»
«Таким образом, в примере выше содержимое первого блока настолько большое, что создаёт проблему, потому что, как flex-элемент, по умолчанию он стремится сжаться, чтобы вместить содержимое. В этом примере данный элемент имеет много содержимого, так что…
Так что да, flexbox великолепен и отлично справляется с созданием макетов, но, пожалуйста, не говорите мне, что он прост. Как только вы переходите от идеальных примеров к рабочим задачам, подобное поведение довольно часто далеко от интуитивного понимания, а порой может быть откровенно странным.
Grid сложен тем, что влечёт за собой много новых свойств и значений, но они дают нам гораздо больше контроля, чем flexbox.
В этой статье мне бы хотелось рассмотреть, как этот дополнительный уровень контроля помогает упростить нашу разметку и позволяет писать меньше кода, и всё это даже без необходимости изучения того, как использовать целый ряд его причудливых функций.
Ограничения Flexbox
Даже если мы возьмём простой компонент и создадим его с помощью flexbox, из-за того, что он действует только в 1 измерении (flex-элементы являются либо строками, либо столбцами, они не могут быть и тем и другим), у нас оказывается большое количеством элементов, используемых для создания строк, которые потом можно будет разбить на столбцы.
Например, если мы работает над карточкой, как эта:
Это не сложный макет, но нам всё ещё нужно организовать наш контент довольно специфичным образом, чтобы заставить работать.
Желтый и оранжевый блоки в этой ситуации нужны, чтобы при добавлении свойства display: flex для элемента .card (красный блок), создались две колонки. Таким образом, чтобы структурировать всё содержимое, мы получаем разметку, которая выглядит примерно так:
<div class="card">
<div class="profile-sidebar">
<!-- Изображение профиля и список иконок соцсетей -->
</div>
<div class="profile-body">
<!-- Имя, должность, описание -->
</div>
</div>
Как только вы поймёте, как работает Flexbox, понять такую структуру станет просто.
Когда мы добавим свойство display: flex
для элемента .card
, получим две колонки, после чего нужно будет стилизовать каждую из них отдельно.
Вот рабочий пример со всеми стилями:
Дело в том, что при создании столбцов содержимого, мы получаем немного более сложную разметку, и мы также ограничиваем себя, так как вынуждаем разные части содержимого группироваться вместе.
Упрощение всего с помощью CSS Grid
Поскольку CSS Grid двухмерный, он позволяет нам одновременно создавать строки и столбцы, а это значит, что grid-контейнер (которому мы задали свойство display: grid
) имеет полный контроль над макетом внутри себя.
Раньше для этого требовались дополнительные элементы, как в приведенном выше примере с Flexbox. Используя Grid, мы можем полностью избавиться от них.
<div class="card"> <img src="https://i.pravatar.cc/125?image=3" alt="" class="profile-img">
<ul class="social-list"> ... </ul>
<h2 class="profile-name">Ramsey Harper</h2>
<p class="profile-position">Graphic Designer</p>
<p class="profile-info">Lorem ipsum ...</p>
</div>
С точки зрения разметки, разве не имеет ли это больше смысла?
Есть элемент с классом .card
, в который мы помещаем его непосредственное содержимое. Нам не нужно переживать о структуре и компоновке элементов, мы просто помещаем контент, который нам нужен, и идём дальше.
Структурирование макета
Так же, как при использовании Flexbox, нам все еще нужно структурировать макет, хотя из-за особенностей работы Grid, это выглядит немного иначе.
Это одна из ситуаций, в которой люди могу утверждать, что Grid сложнее, но на самом деле, я просто рисую блоки вокруг каждой части содержимого.
Используя Flexbox, мы создали два блока, которые выступали столбцами. При использовании Grid, вместо этого мы настраиваем всю сетку для родительского элемента, после чего указываем дочерним элементам, где расположиться на этой сетке.
Чтобы настроить сетку, мы можем сделать что-то вроде этого:
.card {
display: grid;
grid-template-columns: 1fr 3fr;
}
Единица измерения fr уникальная для Grid, и обозначает долю доступного пространства. Такое использование очень похоже на установку двух колонок во Flexbox и определение им ширин 25% и 75% соответственно.
Размещение элементов на сетке
Возможно, из-за того, что в течение многих лет для создания разметки я использовал float, теперь ситуации, в которых элементы просто располагаются именно там, где это нужно, кажутся похожими на небольшую магию.
Можно было использовать grid-row
и grid-column
для каждого элемента, чтобы разместить их именно там, где мы хотим, но чем больше я использую Grid, тем больше я влюбляюсь в свойство grid-template-areas
и размещаю элементы с помощью определения областей.
Такой подход занимает немного больше времени, но оно стоит того, особенно когда мы создаём адаптивный дизайн (скоро мы дойдём до этого).
Сперва мы должны определить grid-template-areas
для элемента .card
, после чего мы можем назначить все дочерние элементы в эти области:
.card {
...
display: grid;
grid-template-columns: 1fr;
grid-column-gap: 2em;
grid-template-areas:
"image name"
"image position"
"social description";
}
.profile-name { grid-area: name; }
.profile-position { grid-area: position; }
.profile-info { grid-area: description; }
.profile-img { grid-area: image; }
.social-list { grid-area: social; }
В примере ниже можно увидеть это всё в действии:
Это так просто
Одна из причин, по которой я люблю использовать grid-template-areas
, заключается в том, что если кто-то еще посмотрит на код, он сразу поймёт, что происходит…
Если кто-то показывает вам код, в котором заданы grid-row
и grid-column
с использованием чисел и span
, высчитать и понять, где и как они будут расположены элементы, достаточно просто. Для простых макетов или для использования span в некоторых местах, их использование считаю уместным, но гораздо приятнее, просто посмотрев только на код родительского элемента, сразу понять, как будет выглядеть весь макет.
При использовании Grid легче узнать фактический размер элемента
В самом первом нашем примере, где мы установили ширину одного из flex-элементов = 50%, на самом деле она не была равна 50%. Если вы понимаете, почему так произошло, отлично, но порой это всё равно может раздражать. Это достаточно просто обойти, но когда используется Grid, это становится гораздо меньшей проблемой.
Поскольку мы определяем целый макет, мы также точно задаём, сколько места должны занимать элементы.
И конечно же, мы получаем в распоряжение функцию minmax()
и единицы измерения fr
, которые немного мутят воду, так как позволяют более гибко определять размеры (как те, что мы используем в примере выше), но даже тогда мы всё ещё имеем полный контроль над их гибкостью, и всё это контролируется родителем, без необходимости задавать часть свойств для родителя, а часть — для дочерних элементов.
Ограниченные изменения
Если рассмотреть пример с Flexbox, мы не можем сделать его похожим на макет ниже без изменения HTML-разметки:
Мы ограничили сами себя тем, как группировали элементы вместе с помощью <div>
. Нам пришлось использовать эти <div>
, чтобы заставить макет работать, но теперь это стало для нас преградой.
С дочерними элементами нашего grid-контейнера, расположенными на одном уровне, можно делать всё. И в качестве дополнительного бонуса, поскольку мы настроили всё используя grid-template-areas
, вносить эти изменения очень легко.
.card {
/* Старая разметка
grid-template-areas:
"image name"
"image position"
"social description"; */
/* Новая разметка */
grid-template-areas:
"image name"
"image position"
"image social"
". description";
}
Играя с grid-template-areas
подобным образом, быстро и легко можно сместить иконки социальных сетей туда, где мы хотим их видеть (точка в последней части указывает на пустую ячейку).
Это облегчает жизнь при работе с медиа-запросами
Как я упоминал несколько раз, это тот случай, когда оправдано использование grid-template-areas
. Мы можем полностью контролировать наш макет только с помощью свойств родителя:
.card {
/* настройки для небольших экранов */
display: grid;
grid-template-columns: 1fr;
grid-column-gap: 2em;
grid-template-areas:
"name"
"image"
"social"
"position"
"description";
}
.profile-name { grid-area: name;}
.profile-position { grid-area: position; }
.profile-info { grid-area: description; }
.profile-img { grid-area: image; }
.social-list { grid-area: social; }
/* Перестраивание макета для больших экранов */
@media (min-width: 600px) {
.card {
text-align: left;
grid-template-columns: 1fr 3fr;
grid-template-areas:
"image name"
"image position"
"social description";
}
.profile-name::after {
margin-left: 0;
}
}
CodePen ниже содержит полностью стилизованный пример. Можете изучить его, поиграть с grid-областями и увидеть, насколько просто полностью перестраивать макет.
Flexbox всё еще имеет свою область применения
Я всё чаще и чаще использую Grid, но думаю, что Flexbox всё еще имеет свою область применения. Если у меня есть логотип и навигация, расположенные рядом друг с другом, хорошо бы иметь простой способ сделать что-то подобное и знать, что они окажутся там, где я хочу чтобы они были:
.header {
display: flex;
justify-content: space-between;
}
То же касается и <ul>
, который мы используем для навигации, чтобы просто получить элементы, следующие друг за другом, или, как вы могли заметить в примере с карточкой, который мы рассматривали, он идеально подходит для .social-list
.
Для простых компонентов, где нам не нужен сложный макет, это действительно хорошо работает. Но всё больше и больше я замечаю за собой движение в сторону Grid, иногда из-за явной потребности в них, иногда потому что хочу использовать функцию minmax()
или единицы измерения fr
.
Но в конце концов, я думаю, что самое лучшее в Grid — это возможность существенно упростить нашу разметку.
Мы всё ещё вынуждены использовать <div>
, но благодаря Grid, мы всё меньше можем их использовать.
В завершение
Как бы ни был хорош Flexbox, он не проще, чем Grid. Он действительно отлично подходит в определенных ситуациях, но при работе с более сложными макетами, Grid позволяет нам иметь намного больше контроля. Этот контроль усиливается во время работы с адаптивным дизайном при внесении изменений в медиа-запросы.
При использовании Flexbox, наибольшее, что мы можем изменить, это направление flex-direction
. Используя Grid, мы можем быстро и просто полностью изменить дизайн компонента.
И Flexbox и Grid имеют гораздо больше возможностей. Каждый имеет своё предназначение, но если вы чувствуете, что не знаете, какой подход выбрать, или застряли при попытке понять адаптивный дизайн в общем, недавно на Scrimba я анонсировал курс, который углубляется в вопросы адаптивного дизайна, который называется The Responsive Web Design Bootcamp.
Автор: hisbvdis