Pull to refresh

Основы и практика CSS Grid Layout:  как использовать двумерную раскладку для повседневных задач

Reading time11 min
Views56K

Наш фронтенд-разработчик Данила Абрамов @DanilAbr подготовил материал для новичков и практикующих разработчиков, которые еще не успели разобраться с Grid. В первой части статьи — основные CSS-свойства и принципы раскладки, без которых невозможно понять Grid. Если вы уже знакомы с основами, переходите ко второй части — там примеры решения реальных задач.

Сейчас есть множество статей про Grid. И если вам действительно интересно его освоить и хорошо с ним разобраться, изучите несколько источников. Только так картина в голове станет абсолютно ясной, и вы с лёгкостью станете использовать раскладки на Grid и все их возможности. Самым дотошным и терпеливым рекомендуем прочитать спецификацию. И если вы легко можете понять её, то наш материал не для вас.

CSS Grid Layout — что это?

CSS Grid Layout (далее просто Grid) — это способ двумерной раскладки. Именно ДВУмерной, в отличии от Flexbox. Flexbox позволяет полноценно управлять элементами только по одной оси.

Grid чем-то похож на display: table (далее таблицы). Но есть важное отличие:

таблицы созданы для отображения табличных данных, а HE для раскладки элементов на страницах. Их стали использовать для создания сеток страниц, потому что на тот момент в CSS не было других (адекватных) вариантов сделать это. Grid же изначально разрабатывался для создания современных, интересных, часто нестандартных двумерных раскладок.

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

Давайте на примерах рассмотрим основные возможности Grid.

В HTML создадим следующую разметку и в CSS добавим ячейкам декоративные стили.

HTML:

<div class="container">
   <div class="el el-1">1</div>
   <div class="el el-2">2</div>
   <div class="el el-3">3</div>
   <div class="el el-4">4</div>
   <div class="el el-5">5</div>
   <div class="el el-6">6</div>
</div>

CSS:

.el {
   padding: 15px 35px;
   font-size: 21px;
   color: #fff;
   background: lightblue;
}

Добавим контейнеру свойство display: grid.

.container {
   display: grid;
}
display: grid автоматически создаёт сетку из ячеек, расположенных друг под другом, в один столбец. Дочерние элементы грид-контейнера по очереди размещаются внутри этих ячеек
display: grid автоматически создаёт сетку из ячеек, расположенных друг под другом, в один столбец. Дочерние элементы грид-контейнера по очереди размещаются внутри этих ячеек

Часть 1. Основные Grid-свойства

grid-template-columns / grid-template-rows

Добавим элементам с классом .el рамку и зададим контейнеру свойство grid-template-columns: https://codepen.io/danilabr/pen/jOayKYN

.el {
   ...
   border: 2px dashed #aaa;
}
.container {
   display: grid;
   grid-template-columns: 150px 20vw auto 1fr;
}
grid-template-columns определяет количество колонок и может задавать ширину каждой из них
grid-template-columns определяет количество колонок и может задавать ширину каждой из них

К привычным нам единицам измерения в CSS спецификация Grid добавляет ещё одну — 1fr (fraction). Она похожа на единицу гибкости во Flexbox, flex-grow.  В примере выше ширина первой и второй колонки 150px и 20vw. Третья колонка ужимается под контент (свойство auto). А 1fr здесь используется, чтоб занять всё оставшееся доступное место.

fr (fractional unit) всегда занимает свободное пространство. Когда несколько столбцов с ширинами в fr, цифрами мы указываем, какую часть свободного пространства должны делить между собой строки / колонки.

Эту единицу измерения можно использовать даже с дробными значениями:

Давайте посчитаем, чтоб разобраться. Общая доля свободного пространства (100%) будет равна сумме всех fr:

  • ширина контейнера: 0.5fr + 1fr + 2.5fr = 4fr или 100%

  • ширина первой колонки: 0.5fr / 4fr = 1/8 или 12.5%

  • ширина второй колонки: 1fr / 4fr = 1/4 или 25%

  • ширина третей колонки: 2.5fr / 4fr = 5/8 или 62,5%

Что если у нас есть несколько колонок, и все они должны быть равной ширины? Можно использовать функцию repeat(), которая автоматически создаст нужное количество столбцов, например:

.container {
   display: grid;
   grid-template-columns: repeat(3, 1fr);
}
grid создал три колонки, ширина каждой равна ⅓ ширины контейнера
grid создал три колонки, ширина каждой равна ⅓ ширины контейнера

Первым параметром функция repeat() принимает количество, а вторым — ширину (или список ширин). Это значит, что если написать

.container {
   display: grid;
   grid-template-columns: repeat(3, 1fr 2fr);
}

то мы получим шесть колонок со следующими ширинами: 1fr 2fr 1fr 2fr 1fr 2fr.

Чтобы описать количество и ширину строк, в Grid используется свойство grid-template-rows. Оно может принимать те же значения, что и grid-template-columns.

grid-auto-rows / grid-auto-columns

Есть такие понятия как «явный» и «неявный» Grid. «Явный» создаётся при помощи свойств grid-template-columns и grid-template-rows, когда мы явно указываем количество строк и столбцов. Но что если количество элементов больше, чем ячеек в «явном» гриде? В таком случае грид создаст «неявный» грид. Размеры колонок и строк будут рассчитаны автоматически, в зависимости от контента внутри них. Например:

.container {
   display: grid;
   grid-template-columns: repeat(2, 1fr);
   grid-template-rows: repeat(2, 100px);
}
Описав две строки и два столбца, мы размещаем первые четыре элемента, но остаются ещё два. Размеры следующих строк мы не указали, и высота третьей строки будет равна высоте контента (текст + отступы)
Описав две строки и два столбца, мы размещаем первые четыре элемента, но остаются ещё два. Размеры следующих строк мы не указали, и высота третьей строки будет равна высоте контента (текст + отступы)

Чтоб контролировать размеры строк и столбцов, в «неявном» гриде есть свойства grid-auto-rows / grid-auto-columns.

.container {
   display: grid;
   grid-template-columns: repeat(2, 1fr);
   grid-template-rows: repeat(2, 100px);
   grid-auto-rows: 30px;
}
Высота третьей строки указана в свойстве grid-auto-rows: 30px;
Высота третьей строки указана в свойстве grid-auto-rows: 30px;

grid-auto-rows: minmax();

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

.container {
   display: grid;
   grid-template-columns: repeat(2, 1fr);
   grid-auto-rows: minmax(100px, auto);
}
Здесь минимальная высота строк 100px, максимальная — auto
Здесь минимальная высота строк 100px, максимальная — auto

repeat() - auto-fill / auto-fit

Создание адаптивной сетки — неотъемлемая часть вёрстки. Grid предоставляет нам возможности создавать простые адаптивные раскладки без применения медиа выражений. Функция repeat() первым аргументом может принимать не только количество, но и ключевые слова — auto-fill / auto-fit.

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

Делается это в ОДНУ строчку:

grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));

Ключевое слово auto-fill автоматически заполнит нашу сетку колонками, ширина которых будет минимум 300px. Если есть свободное место, колонки будут растягиваться в ширину до тех пор, пока нет места для ещё одной колонки в 300px. Попробуйте плавно изменить ширину окна и увидите, что происходит с сеткой: https://codepen.io/danilabr/pen/dyREbqv 

Далее измените auto-fill на auto-fit, и вы увидите, что ничего не изменилось. Разница в их поведении станет видна только если уменьшить количество элементов (или их минимальную ширину). Если ширины и количества элементов не хватает, чтоб заполнить весь экран, начинают работать свойства auto-fill / auto-fit.

grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
Обратите внимание, элемента всего два, но у нас достаточно места для трех колонок, и grid автоматически создаёт нам пустую третью колонку по размерам, которые указаны внутри функции minmax
Обратите внимание, элемента всего два, но у нас достаточно места для трех колонок, и grid автоматически создаёт нам пустую третью колонку по размерам, которые указаны внутри функции minmax
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
При использовании auto-fit grid подстраивается под количество элементов и растягивает их на всю доступную ширину. Попробуйте это на практике, и вам станет понятно
При использовании auto-fit grid подстраивается под количество элементов и растягивает их на всю доступную ширину. Попробуйте это на практике, и вам станет понятно

grid-lines

Неотъемлемой частью спецификации Grid являются grid-lines (линии). Если колонки и строки мы можем создать руками (grid-template-columns / grid-template-rows), то grid-lines всегда создаются автоматически. Мы не можем никак повлиять на их создание, но можем их использовать. Если открыть инспектор гридов в devtools, то видно, что grid создаёт линии и нумерует их:

В сетке три строки. Были созданы четыре горизонтальных линии и пронумерованы сверху вниз (от 1 до 4). То же касается и вертикальных линий. На этом примере два столбца. Grid создал три вертикальных линии и пронумеровал их слева направо (от 1 до 3)
В сетке три строки. Были созданы четыре горизонтальных линии и пронумерованы сверху вниз (от 1 до 4). То же касается и вертикальных линий. На этом примере два столбца. Grid создал три вертикальных линии и пронумеровал их слева направо (от 1 до 3)

Можно легко размещать элементы в Grid-сетке относительно нумерованных линий. Для этого существуют следующие свойства:

grid-column-start, grid-column-end / grid-row-start, grid-row-endgrid-column / grid-row

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

.el-6 {
   grid-column-start: 1;
   grid-column-end: 2;
   grid-row-start: 1;
   grid-row-end: 2;
}

можно сократить:

.el-6 {
   grid-column: 1 / 2;
   grid-row: 1 / 2;	
}

или (так как элемент по умолчанию занимает одну ячейку):

.el-6 {
   grid-column: 1;
   grid-row: 1;
}

Есть ещё одно более сумасшедшее сокращение, но о нём мы намеренно не будем рассказывать, поскольку считаем плохой практикой использовать его в рабочем коде (с точки зрения понимания и поддержки в будущем).

Развивая тему размещения от нумерованных линий, нужно добавить ещё некоторые особенности. Ключевое слово span позволит растянуть элемент на нужное количество ячеек:

.el-6 {
   grid-column: 1 / span 2;
   // то же самое, что и grid-column: 1 / 3
   grid-row: 1;
}

Нумерация со знаком минус позволит считать линии с конца столбцов или строк:

.el-6 {
   grid-column: 1 / -1;
   grid-row: 1;
}

Результат будет тот же, что и на скриншоте выше, потому, что третья вертикальная линия, она же последняя, по номеру равна -1 (минус первой).

Auto-placement

Далее затронем важнейшую тему для понимания принципов раскладки Grid — алгоритм автоматического размещения элементов внутри Grid-сетки. Ознакомьтесь с CSS в следующем примере и закомментируйте строчку 26 (grid-row: 1) https://codepen.io/danilabr/pen/KKyaPYM

.el-2 {
   grid-column: 1;
   //grid-row: 1;
}
первый вариант
первый вариант
.el-2 {
   grid-column: 1;
   grid-row: 1;
}
второй вариант
второй вариант

Когда Данила увидел подобное, он очень сильно удивился: почему в одном случае остаются свободные места, а в другом — нет. Ответ здесь гораздо проще чем кажется.

У Grid-раскладки есть специальный алгоритм размещения элементов:

  1. В начале располагаются те элементы, которые были вырваны из обычного потока размещения. Чтобы вырвать элемент из этого потока, достаточно явно указать линию, от которой должен быть расположен элемент. Например, во втором варианте .el-2 вырван из потока авто-размещения с помощью grid-row: 1

  1. Далее все оставшиеся элементы ищут свободное место, и заполняют его слева направо, сверху вниз, что и происходит во втором варианте. .el-1 видит свободную ячейку на второй колонке и первой строке, и встаёт туда. Остальные элементы располагаются по очереди за ним.

А так работает алгоритм в первом варианте: 

У нас нет элементов, «вырванных» из обычного потока размещения Grid, поэтому работает правило размещения по порядку, друг за другом.

  • сначала .el-1 встаёт на своё место (первая линия по вертикали и первая по горизонтали):

  • элементу .el-2 мы указали grid-column: 1. Ему нужно встать на первую линию по вертикали, а первая свободная ячейка на этой линии — это ячейка, которая находится на первой линии по вертикали и второй по горизонтали:

  • далее по порядку в DOM располагаются остальные элементы, но уже ПОСЛЕ второго элемента (следуя обычному потоку размещения в Grid: слева направо, сверху вниз):

grid-area

Используя Grid, можно размещать элементы не только относительно конкретных линий. Также есть возможность создавать области, и размещать элементы внутри конкретной области.

Для примера оставим четыре элемента (.el-1 .el-2 .el-3 .el-4), и каждому элементу с помощью grid-area дадим псевдоним, по которому будем к нему обращаться, выстраивая сетку в свойстве grid-template у родителя:

.el-1 {
   grid-area: header;
}
.el-2 {
   grid-area: aside;
}
.el-3 {
   grid-area: main;
}
.el-4 {
   grid-area: footer;
}	

С помощью свойства gap добавим отступы между ячейками сетки, и в ОДНОМ свойстве родителя grid-template мы можем создать сетку, задать ей размеры, и наглядно описать раскладку наших элементов на странице:

Это может выглядеть проще. Размеры строк и колонок можно задавать отдельно любыми другими способами. Результат такой: https://codepen.io/danilabr/pen/BampVbg

Не будем описывать все особенности данного способа создания сетки, его синтаксические правила (кавычки, пробелы и прочее). Всё это легко можно найти во множестве статей, и разобраться в этом довольно просто. Главное — теперь вы знаете, что в Grid есть возможность сделать так, чтоб сетка была видна наглядно и понятно, даже внутри CSS-кода.

Это далеко не все возможности Grid. Мы рассказали лишь малую часть того, что есть в спецификаци. Но даже этого достаточно, чтоб легко и просто начать делать сетки с помощью Grid.

Теперь перейдём к практике.

Часть 2. Применение CSS Grid Layout. Использование для повседневных реальных задач

Ключевой момент в описании стилей, который отличает использование Grid от других технологий:

стили сетки часто описываются в стилях родителя. Это очень удобно для разработки и поддержки — всё, что касается сетки в одном месте, точнее в одном селекторе.

Адаптивный список карточек с помощью auto-fit

Первым примером будет адаптивный список карточек с минимальной шириной 240px, в котором карточки растягиваются на всю доступную ширину родителя. Нам не понадобится перестраивать сетку на разных ширинах экрана, — Grid сделает это сам. Попробуйте изменить ширину экрана и увидите результат: https://codepen.io/danilabr/pen/mdqRjQy

&__list {
    display: grid;
    gap: 20px;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    margin: 20px;
}

Форма с помощью grid-template

Следующий пример демонстрирует возможности применения свойств grid-area и grid-template. Сделаем форму, и на четырех разных разрешениях у этой формы будет разная сетка. Выделим два ключевых момента использования Grid в этом примере:

1) Мы можем задавать размеры только некоторых столбцов и строк, остальные будут иметь размеры auto.

2) При использовании Flexbox, для выстраивания в ряд полей name и email мы создали бы дополнительную обёртку над ними в html. Grid позволяет избежать этого: https://codepen.io/danilabr/pen/XWzqQRx

.form__container {
   grid-template:
       "text text"
       "name email"
       "message message" minmax(120px, auto)
       "button button"
       / 4fr    3fr;
}

12-колоночная сетка с помощью Grid. Расположение блоков по этой сетке

Третий пример располагает на странице два крупных блока. С помощью грида можно создать сетку, в том числе и стандартную 12-колоночную. И на разных разрешениях можно располагать блоки от разных линий. Для наглядности добавим декоративные стили сетки, чтоб было понятно, по каким линиям располагаются блоки. Попробуйте в примере изменять размеры экрана: https://codepen.io/danilabr/pen/JjOvqaW

Часть 3. Итоги

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

Как начать использовать

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

Чтобы начать использовать Grid, достаточно выбрать один способ из тех, что вы видели. Тот, который понравился и показался интересным. Со временем, попробовав разные подходы, вы будете знать, в какой момент лучше подходит тот или иной. Главное — начать.

Почему не все разработчики хотят изучить grid

Часто, когда много работаешь, выбираешь те или иные технологии, которые нравятся и подходят по всем требованиям для решения задач. Привыкая к определённым паттернам и используя только их, очень легко упустить из вида что-то новое, особенно если новое кажется непонятным. Важно иногда посмотреть по сторонам и подумать, нет ли чего-то более интересного и более подходяшего, чем то, к чему привык. И когда речь идёт о создании адаптивных сеток, особенно двумерных, то Grid — это и есть то более интересное и подходящее. Главное — попробовать.

Если ты знаешь и правильно используешь Grid, то ты:

  • Более востребован на рынке, чем тот, кто не знает Grid.

  • Пишешь меньше кода (меньше HTML-элементов (обёрток), меньше строк в CSS).

  • При построении простой сетки можешь писать все стили в одном месте (в grid-container).

  • Можешь делать те раскладки, которые нереально сделать без Grid.

  • Делаешь раскладки проще и быстрее.

  • Экономишь время, своё и коллег на поддержку проекта.

  • Можешь потратить это свободное время на более качественную вёрстку макета (делать интересную анимацию, уделить время доступности, улучшить performance и т.п.).

  • Grid — это будущее

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

В заключении хотим сказать, что данная статья написана для знакомства с Grid. И ни в коем случае не призывает забыть обо всех других способах раскладок и микрораскладок блоков на странице, будь то flex, inline-flex или inline-block. CSS Grid Layout — это технология, и каждую технологию нужно использовать с умом и для тех задач, для которых она подходит лучше всего.

Tags:
Hubs:
Total votes 5: ↑4 and ↓1+3
Comments3

Articles