HTML и CSS / CSS Grid Layout

Заметка создана: 30 января 2024 г.
CSS Grid Layout представляет двумерную сетку для CSS. Grid (здесь и далее подразумевается CSS Grid Layout) можно использовать для размещения основных областей страницы или небольших элементов пользовательского интерфейса. В этой статье описывается компоновка сетки CSS и новая терминология, которая является частью спецификации CSS Grid Layout Level 1. Функции, показанные в этом обзоре, будут более подробно описаны в остальной части данного руководства.
.grid { 
   display: grid; 
   grid-template-columns: 200px 200px 200px; // задаём количество и ширину столбцов в px
   grid-template-columns: 1fr 1fr 1fr;  // задаём количество и ширину столбцов в fr
   grid-column-gap: 10px;  // задаём интервалы между столбцами
   grid-template-rows: 50px 1fr 30px;  // задаём количество и размеры строк
   grid-row-gap: 1em;  // задаём интервалы между строками
   grid-gap: 3%;  // задаём интервалы между строками и столбцами
}

Что такое Grid?


Grid представляет собой пересекающийся набор горизонтальных и вертикальных линий - один набор определяет столбцы, а другой строки. Элементы могут быть помещены в сетку, соответственно строкам и столбцам.  Grid имеет следующие функции:

Фиксированные и гибкие размеры полос

Вы можете создать сетку с фиксированными размерами полос — например, используя пиксели. Вы также можете создать сетку с гибкими размерами, используя проценты или новую единицу измерения - fr, предназначенную для этой цели.

Расположение элемента

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

Создание дополнительных полос для хранения контента

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

Управление выравниванием

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

Управление перекрывающимся контентом

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

Grid контейнер

Мы создаёмgrid контейнер, объявляяdisplay: grid или display: inline-grid на элементе. Как только мы это сделаем, все прямые детиэтого элемента станут элементами сетки.
В этом примере есть div, содержащий класс wrapper с пятью потомками
<div class="wrapper">
   <div>One</div>
   <div>Two</div>
 <div>Three</div>
   <div>Four</div>
 <div>Five</div>
</div>

Сделаем wrapper grid контейнером

.wrapper {
  display: grid;
}

Все прямые потомки теперь являются grid элементами. В веб-браузере вы не увидите никакой разницы в отображении элементов, поскольку Grid создал единую сетку столбцов для элементов. На данный момент вам может оказаться удобным работать в Firefox Developer Edition, в котором есть Grid Inspector, доступный как часть инструментов разработчика. Если вы просмотрите этот пример в Firefox и проверите Grid, вы увидите маленький значок рядом с display: grid. Нажмите этот значок, и сетка на этом элементе будет наложена в окне браузера.

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

Если мы хотим, чтобы это стало более похожим на сетку, нам нужно добавить полосы.

Grid Tracks


Мы определяем ряды и столбцы в нашей сетке при помощи свойств grid-template-columnsи grid-template-rows. Это определяет полосы сетки. Полоса сетки — это место между любыми двумя линиями сетки. На изображении ниже вы можете увидеть подсветку полосы — первого трека ряда в нашей сетке.
Можно дополнить пример выше, добавив свойство grid-template-columns и  задав размеры полос колонок.
В примере ниже мы создаём сетку с шириной колонки 200px. Каждый дочерний элемент сетки будет располагаться в отдельной ячейке сетки.

<div class="wrapper">
   <div>One</div>
   <div>Two</div>
   <div>Three</div>
   <div>Four</div>
   <div>Five</div>
</div> 

.wrapper {
  display: grid;
  grid-template-columns: 200px 200px 200px;
}

Единица измерения fr


Размер треков (полос) может быть задан с помощью любой единицы длины. Спецификация также вводит дополнительную единицу длины, позволяющую создавать эластичные (flexible) грид-треки. Новая единица длины fr представляет собой долю (fraction) доступного пространства в грид-контейнере. Определение грида в коде ниже создаст три трека равной длины, которые будут увеличиваться и уменьшаться в размерах в соответствии с доступным пространством.

<div class="wrapper">
   <div>One</div>
   <div>Two</div>
   <div>Three</div>
   <div>Four</div>
   <div>Five</div>
</div> 

.wrapper {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}

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

.wrapper {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
}

В последнем примере смешаем треки с абсолютной длиной и треки с длиной во fr. Размер первого трека 500 пикселей, и эта фиксированная ширина убирается из доступного пространства. Оставшееся пространство разбивается на три части и пропорционально разделяется между двумя эластичными треками.

.wrapper {
  display: grid;
  grid-template-columns: 500px 1fr 2fr;
}

Задание треков с помощью нотации repeat()
В огромных гридах с большим количеством треков можно использовать нотацию repeat() , чтобы повторить структуру треков или её часть. Например, такое задание грида:

.wrapper {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}

можно записать вот так:

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

Repeat-нотацию можно использовать как часть списка треков. В следующем примере создаётся грид с начальным треком шириной в 20 пикселей, шестью треками шириной в 1fr и последним треком шириной в 20 пикселей.
```
.wrapper {
  display: grid;
  grid-template-columns: 20px repeat(6, 1fr) 20px;
}
Repeat-нотация в качестве аргумента принимает список треков, поэтому с её помощью можно создавать структуру из повторяющихся треков. В следующем примере грид состоит из 10 треков: за треком шириной 1fr следует трек шириной 2fr, и все это дело повторяется пять раз.

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

Явный и неявный грид

Во всех примерах выше мы создавали наши колоночные (столбцовые) треки с помощью свойства grid-template-columns, в то время как грид самостоятельно создавал строки (ряды, полосы) для любого контента там, где это требовалось. Эти строки создавались в неявном гриде. Явный грид состоит из строк и колонок, которые мы определяем с помощью grid-template-columnsи grid-template-rows. Если вы размещаете что-нибудь вне рамок определённого данными свойствами грида или в зависимости от контента требуется большее количество грид-треков, грид создаёт строки и колонки в виде неявного грида. Размер подобных треков по умолчанию задаётся автоматически в зависимости от находящегося в них контента.
Вы также можете задать размер треков, создаваемых в виде неявного грида с помощью свойств grid-auto-rows(en-US)и grid-auto-columns(en-US).
В примере ниже мы задаём grid-auto-rows , чтобы треки, создаваемые в неявном гриде были высотой 200 пикселей.

<div class="wrapper">
   <div>One</div>
   <div>Two</div>
   <div>Three</div>
   <div>Four</div>
   <div>Five</div>
</div>

 .wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 200px;
}

Масштабирование треков и minmax()

При задании размеров явного грида или при определении размеров автоматически создаваемых колонок или строк может возникнуть следующая ситуация: мы хотим определить для треков минимальный размер, но при этом быть уверенными, что при необходимости треки растянутся, чтобы вместить весь добавленный в них контент. Например, нам нужно, чтобы строки никогда не становились меньше 100 пикселей, но если контент занимает, скажем, 300 пикселей в высоту, мы хотим, чтобы  строка тоже стала 300 пикселей.
Для подобных ситуаций в Grid  предусмотрено решение с помощью функции minmax(). В следующем примере  minmax() используется, как значение свойства grid-auto-rows(en-US). Автоматически создаваемые строки будут как минимум 100 пикселей в высоту, а как максимум примут значение auto. Использование auto означает, что размер строки посмотрит на размер контента и растянется таким образом, чтобы вместить самый высокий элемент ячейки в этой строке. 

.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: minmax(100px, auto);
} 

<div class="wrapper">
   <div>One</div>
   <div>Two
   <p>I have some more content in.</p>
   <p>This makes me taller than 100 pixels.</p>
</div>
   <div>Three</div>
   <div>Four</div>
   <div>Five</div>
</div>

Grid-линии

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

Линии нумеруются в соответствии с режимом написания (writing mode) документа. В языках с написанием слева-направо, линия 1 - самая левая линия в гриде. В языках с написанием справа-налево, линия 1 - самая правая линия в гриде. Линиям также можно давать имена, и - не переключайтесь, дальше мы узнаем, как это делать. 

Размещение элементов по линиям

В дальнейшем мы детально рассмотрим размещение элементов с помощью линий, а пока остановимся на простом способе. При размещении элемента мы ссылаемся именно на линию, а не на трек. 

В следующем примере мы размещаем первые два элемента в нашем гриде из трёх колоночных треков с помощью свойств grid-column-start(en-US), grid-column-end(en-US), grid-row-startи grid-row-end(en-US). Поскольку режим написания слева направо, первый элемент размещается, начиная с колоночной линии 1, и занимает пространство до колоночной линии 4, которая в нашем случае - самая правая линия грида. Наш элемент начинается со строчной линии 1 и заканчивается на строчной линии 3, таким образом занимая два строчных трека.

Второй элемент начинается с колоночной линии 1 и занимает один трек. Это поведение по умолчанию, поэтому не нужно задавать конечную линию. Элемент также занимает два строчных трека - со строчной линии 3 до строчной линии 5. Остальные элементы самостоятельно размещаются в пустых пространствах грида. 

<div class="wrapper">
   <div class="box1">One</div>
   <div class="box2">Two</div>
   <div class="box3">Three</div>
   <div class="box4">Four</div>
   <div class="box5">Five</div>
</div>

 .wrapper {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-auto-rows: 100px;
}
.box1 {
    grid-column-start: 1;
    grid-column-end: 4;
    grid-row-start: 1;
    grid-row-end: 3;
}
.box2 {
    grid-column-start: 1;
    grid-row-start: 3;
    grid-row-end: 5;
}

Не забывайте, что вы можете использовать Grid Inspector в Firefox Developer Tools, чтобы посмотреть, как элементы размещаются по линиям грида.

Grid-ячейки

Грид-ячейка (grid cell) - наименьшая единица измерения грида, концептуально похожая на ячейку таблицы. Как мы видели в предыдущих примерах, едва грид определён для родительского элемента, дочерние элементы автоматически размещаются в каждой ячейке нашего заданного грида. На рисунке ниже первая ячейка грида выделена цветом.

Grid-области

Элементы могут занимать одну или несколько ячеек внутри строки или колонки, и подобное поведение создаёт грид-область (grid area). Грид-области должны быть перпендикулярными, - невозможно создать область, например, в форме буквы L. Выделенная цветом грид-область на рисунке ниже занимает два строчных трека и два колоночных. 
grid-template-areas
Свойство CSS определяет именованные области сетки, устанавливая ячейки в сетке и присваивая им имена.
Эти области не связаны с каким-либо конкретным элементом сетки, но на них можно ссылаться из свойств размещения сетки grid-row-start, grid-row-end, grid-column-start, grid-column-end grid-row и их сокращений grid-column, grid-area

/* Keyword value */
grid-template-areas: none; /* <string> values */
grid-template-areas: "a b";
grid-template-areas:
  "a b b"
  "a c d"; /* Global values */
grid-template-areas: inherit;
grid-template-areas: initial;
grid-template-areas: revert;
grid-template-areas: revert-layer;
grid-template-areas: unset;
```

Пример

<section id="page">
  <header>Header</header>
  <nav>Navigation</nav>
  <main>Main area</main>
  <footer>Footer</footer>
</section>
```

CSS

#page {
  display: grid;
  width: 100%;
  height: 250px;
  grid-template-areas:
    "head head"
    "nav  main"
    "nav  foot";
  grid-template-rows: 50px 1fr 30px;
  grid-template-columns: 150px 1fr;
}
#page > header {
  grid-area: head;
  background-color: #8ca0ff;
}
#page > nav {
  grid-area: nav;
  background-color: #ffa08c;
}
#page > main {
  grid-area: main;
  background-color: #ffff64;
}
#page > footer {
  grid-area: foot;
  background-color: #8cffa0;
}
```

Зазоры (Gutters)

Зазоры (Gutters) или аллеи (alleys) между грид-ячейками можно создать с помощью свойств grid-column-gap(en-US)и grid-row-gap(en-US), или с помощью сокращённого свойства grid-gap(en-US). В примере ниже мы создаём зазор в 10 пикселей между колонками и в 1em между строками.

.wrapper {
   display: grid;
   grid-template-columns: repeat(3, 1fr);
   grid-column-gap: 10px;
   grid-row-gap: 1em;
} 

<div class="wrapper">
   <div>One</div>
   <div>Two</div>
   <div>Three</div>
   <div>Four</div>
   <div>Five</div>
</div>

Любое пространство, которое занимают зазоры, добавляется в начало эластичных треков, задаваемых с помощью fr, поэтому зазоры используются для регулирования размеров и действуют как регулярные грид-треки, хотя что-то разместить в них нельзя. В терминах расположения элементов по грид-линиям (line-based positioning) зазоры ведут себя так, как если бы самой грид-линии была добавлена толщина.

Вложенные гриды

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

<div class="wrapper">
   <div class="box box1">
       <div class="nested">a</div>
       <div class="nested">b</div>
       <div class="nested">c</div>
    </div>
    <div class="box box2">Two</div>
    <div class="box box3">Three</div>
    <div class="box box4">Four</div>
    <div class="box box5">Five</div>
</div>

Если мы задаём для box1 значение display: grid , то можем написать для него структуру треков, и он тоже станет гридом, а его дочерние элементы будут размещены внутри этого нового грида.

.box1 {
   grid-column-start: 1;
   grid-column-end: 4;
   grid-row-start: 1;
   grid-row-end: 3;
   display: grid;
   grid-template-columns: repeat(3, 1fr);
}

В данном случае вложенный грид не связан с родительским. Как вы можете видеть, он не наследует значение свойства grid-gap(en-US)родительского элемента и линии вложенного грида не выравниваются по линиям родительского грида.

Подгрид (Subgrid)

В спецификации гридов уровня 2 есть функциональность, называемая подгридом (subgrid) , которая позволит нам создавать вложенные гриды, использующие структуру треков родительского грида.
Примечание. Эта функция поставляется в браузере Firefox 71, который в настоящее время является единственным браузером для реализации subgrid.
В приведённом выше примере мы можем отредактировать вложенный грид, изменив grid-template-columns: repeat(3, 1fr), на grid-template-columns: subgrid. Вложенный грид будет использовать родительскую структуру треков, чтобы разместить свои дочерние элементы.

.box1 {
   grid-column-start: 1;
   grid-column-end: 4;
   grid-row-start: 1;
   grid-row-end: 3;
   display: grid;
   grid-template-columns: subgrid;
}

Размещение элементов с помощью z-index

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

<div class="wrapper">
   <div class="box box1">One</div>
   <div class="box box2">Two</div>
   <div class="box box3">Three</div>
   <div class="box box4">Four</div>
   <div class="box box5">Five</div>
</div> Copy to Clipboard
```
.wrapper {
   display: grid;
   grid-template-columns: repeat(3, 1fr);
   grid-auto-rows: 100px;
}
.box1 {
   grid-column-start: 1;
   grid-column-end: 4;
   grid-row-start: 1;
   grid-row-end: 3;
}
.box2 {
   grid-column-start: 1;
   grid-row-start: 2;
   grid-row-end: 4;
}

Элемент box2 теперь перекрывает box1, и отображается сверху, поскольку в исходном коде находится ниже.
Управление порядком отображения
Порядком, в котором элементы накладываются друг на друга, можно управлять с помощью свойства z-index- точно так же, как в случае с позиционированными элементами. Если задать box2 значение z-index , меньшее, чем у box1 , в стеке он отобразится под элементом box1.

.wrapper {
   display: grid;
   grid-template-columns: repeat(3, 1fr);
   grid-auto-rows: 100px;
}
.box1 {
   grid-column-start: 1;
   grid-column-end: 4;
   grid-row-start: 1;
   grid-row-end: 3;
   z-index: 2;
}
.box2 {
   grid-column-start: 1;
   grid-row-start: 2;
   grid-row-end: 4;
   z-index: 1;
}