Сетки

Сетки нужны для того, чтобы правильно расположить содержимое на странице. Обычно, системы сеток состоят из контейнеров (container), рядов (row) и колонок (col). Распространённой практикой являются 12-колоночные сетки. Наиболее известная система сеток среди верстальщиков - это Bootstrap Grid layout

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

Float

Когда-то давно существовал лишь один более или менее хороший подход к проектированию сеток — сетки на флоатах.

<div class="container">
  <div class="row">
    <div class="col w8">
      <span>Ячейка w8</span>
    </div>
    <div class="col w4">
      <span>Ячейка w4</span>
    </div>
  </div>
  <div class="row">
    <div class="col w4">
      <span>Ячейка w4</span>
    </div>
    <div class="col w4">
      <span>Ячейка w4</span>
    </div>
    <div class="col w4">
      <span>Ячейка w4</span>
    </div>
  </div>
  <div class="row">
    <div class="col w3">
      <span>Ячейка w3</span>
    </div>
    <div class="col w3">
      <span>Ячейка <br> w3</span>
    </div>
    <div class="col w3">
      <span>Ячейка w3</span>
    </div>
    <div class="col w3">
      <span>Ячейка w3</span>
    </div>
  </div>
  <div class="row">
    <div class="col w6">
      <span>Ячейка w6</span>
    </div>
    <div class="col w6">
      <span>Ячейка w6</span>
    </div>
  </div>
</div>
    
* {
  box-sizing: border-box;
}
 {
  max-width: 800px;
  margin: 0 auto;
  padding: 0 5px;
}
.row {
  margin: 0 -5px 10px;
}
.row::after {
  content: '';
  display: block;
  clear: both;
}
.col {
  width: calc(100% / 12);
  float: left;
  padding: 0 5px;
}

.col.w1  { width: calc(100% / 12); }
.col.w2  { width: calc(100% * 2 / 12); }
.col.w3  { width: 25%; }
.col.w4  { width: calc(100% * 4 / 12); }
.col.w5  { width: calc(100% * 5 / 12); }
.col.w6  { width: 50%; }
.col.w7  { width: calc(100% * 7 / 12); }
.col.w8  { width: calc(100% * 8 / 12); }
.col.w9  { width: 75%; }
.col.w10 { width: calc(100% * 10 / 12); }
.col.w11 { width: calc(100% * 11 / 12); }
.col.w12 { width: 100%; }

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

Flex

Попробуем исправить предыдущий пример.

<div class="container">
  <div class="row">
    <div class="col w8">
      <span>Ячейка w8</span>
    </div>
    <div class="col w4">
      <span>Ячейка w4</span>
    </div>
  </div>
  <div class="row">
    <div class="col">
      <span>Ячейка</span>
    </div>
    <div class="col">
      <span>Ячейка</span>
    </div>
    <div class="col">
      <span>Ячейка</span>
    </div>
  </div>
  <div class="row">
    <div class="col">
      <span>Ячейка</span>
    </div>
    <div class="col">
      <span>Ячейка <br> вторая строка</span>
    </div>
    <div class="col">
      <span>Ячейка</span>
    </div>
    <div class="col">
      <span>Ячейка</span>
    </div>
  </div>
  <div class="row">
    <div class="col">
      <span>Ячейка</span>
    </div>
    <div class="col">
      <span>Ячейка</span>
    </div>
  </div>
</div>
    
* {
  box-sizing: border-box;
}
 {
  max-width: 800px;
  margin: 0 auto;
  padding: 0 5px;
}
.row {
  display: flex;
  flex-wrap: wrap;
  margin: 0 -5px 10px;
}
.col {
  width: auto;
  max-width: 100%;
  flex-shrink: 0;
  flex-grow: 1;
  flex-basis: 0;
  padding: 0 5px;
}

.col.w1  { min-width: calc(100% / 12); flex-basis: calc(100% / 12)}
.col.w2  { min-width: calc(100% * 2 / 12); flex-basis:calc(100% * 2 / 12); }
.col.w3  { min-width: 25%; flex-basis: 25%; }
.col.w4  { min-width: calc(100% * 4 / 12); flex-basis: calc(100% * 4 / 12); }
.col.w5  { min-width: calc(100% * 5 / 12); flex-basis: calc(100% * 5 / 12); }
.col.w6  { min-width: 50%; flex-basis: 50%; }
.col.w7  { min-width: calc(100% * 7 / 12); flex-basis: calc(100% * 7 / 12); }
.col.w8  { min-width: calc(100% * 8 / 12); flex-basis: calc(100% * 8 / 12); }
.col.w9  { min-width: 75%; flex-basis: 75%; }
.col.w10 { min-width: calc(100% * 10 / 12); flex-basis: calc(100% * 10 / 12); }
.col.w11 { min-width: calc(100% * 11 / 12); flex-basis: calc(100% * 11 / 12); }
.col.w12 { min-width: 100%; flex-basis: 100%; }
    

Как видите, у этого метода есть свои плюсы. Когда нам нужны одинаковые колонки в ряду, нам не нужно указывать ширину этих колонок. И, хоть мы и избавились от хака с clear: both, кода меньше не стало. И снова подстраивать расстояния между блоками приходится не без фокусов, хотя и высоты блоков теперь можно сделать зависимыми друг от друга. Однако, этот способ действительно гораздо лучше предыдущего.

Grid

Уже из названия этого способа понятно, что он придуман как раз для решения этой проблемы.

Для начала, избавимся от строк. Они нам больше не нужны.

<div class="container">
  <div class="grid g-2-1">
    <div class="cell">
      Ячейка
    </div>
    <div class="cell">
      Ячейка
    </div>
  </div>
  <div class="grid g-1-1-1">
    <div class="cell">
      Ячейка
    </div>
    <div class="cell">
      Ячейка
    </div>
    <div class="cell">
      Ячейка
    </div>
  </div>
  <div class="grid g-1-1-1-1">
    <div class="cell">
      Ячейка
    </div>
    <div class="cell">
      Ячейка <br> вторая строка
    </div>
    <div class="cell">
      Ячейка
    </div>
    <div class="cell">
      Ячейка
    </div>
  </div>
  <div class="grid g-1-1">
    <div class="cell">
      Ячейка
    </div>
    <div class="cell">
      Ячейка
    </div>
  </div>
</div>
    
.container {
  max-width: 800px;
  margin: 0 auto;
}        
.cell {
  padding: 0 10px;
}
.grid {
  display: grid;
  gap: 10px;
  margin-bottom: 10px;
}

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

Это совершенно иной подход к организации сеток. Как видите, здесь уже нет проблем с расстояниями между колонками, благодаря свойству gap, кроме того, если вам нужна ровная сетка, кода станет гораздо меньше:

<div class="container">
  <div class="cell">
    Ячейка
  </div>
  <div class="cell">
    Ячейка
  </div>
  <div class="cell">
    Ячейка <br> вторая строка
  </div>
  <div class="cell">
    Ячейка
  </div>
  <div class="cell">
    Ячейка
  </div>
  <div class="cell">
    Ячейка
  </div>
  <div class="cell">
    Ячейка
  </div>
  <div class="cell">
    Ячейка
  </div>
  <div class="cell">
    Ячейка
  </div>
</div>
.container {
  max-width: 800px;
  margin: 0 auto;
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(3, 1fr);
}
.cell {
  padding: 0 10px;
}
  

Теперь нам не обязательно иметь строки, а сам грид может быть совмещён с контейнером.

Поэкспериментировать с этим примером можно здесь:

Запустить пример

Кроме того, с помощью CSS Grid можно создавать вот такие необычные сетки:

Запустить пример