Найти тему

Верстаем правильно: знакомство с Flexbox и Grid

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

Что вы узнаете из этой статьи:

  • как раньше работали с CSS-разметкой;
  • разницу между устаревшими подходами и современными стандартами;
  • как начать работу с новыми стандартами (Flexbox и Grid);
  • почему вас должны волновать эти современные стандарты.

Как раньше работали с CSS-разметкой

Задача

Давайте смоделируем весьма стандартную задачу: как создать страницу с двумя секциями — боковой панелью и зоной с основным контентом, у которых одинаковая высота, независимо от размера контента?

Вот пример того, к чему мы стремимся:

Боковая панель и зона с основным контентом одинаковой высоты, независимо от размера контента
Боковая панель и зона с основным контентом одинаковой высоты, независимо от размера контента

Для начала я покажу, как решить эту задачу с помощью устаревших подходов.

1. Создаём div с двумя элементами

Например, <aside> и <main>:

<body>
<aside>
Lorem ipsum dolor sit amet.
</aside>

<main>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim.
</main>
</body>

Очевидно, что в main больше текста.

Выделим aside цветом, чтобы его проще было отличить:

aside {
color: #fff;
background-color: #8cacea;
}

2. Размещаем обе секции рядом

Для этого напишем следующее:

aside {
width: 25%;
}
main {
width: 75%;
}
aside,
main{
float: left;
}

Этот стиль разделяет доступное пространство в необходимых пропорциях и устанавливает float для aside и main.

Результат:

Два блока, расположенные рядом
Два блока, расположенные рядом

Для тех, кто не знаком с float: это относительно старый способ перемещения элементов влево или вправо.

Как видно на изображении выше, задача всё ещё не выполнена — высота боковой панели не совпадает с высотой основной зоны. Исправим это.

3. Используем трюк с display: table

Чтобы решить эту проблему, надо использовать display: table.

Если вы с ним не знакомы, то вот что надо делать:

  • Делаем родительский контейнер (в нашем случае элемент body) таблицей:

body { display: table; }

2. Убираем float и делаем дочерние элементы aside и main ячейками таблицы:

aside, main{ display: table-cell; }

Как только мы сделали это, задачу можно считать решенной. По крайней мере, так её решали раньше.

Оба блока теперь одинаковой высоты.
Оба блока теперь одинаковой высоты.

Разница между устаревшими подходами и современными стандартами

Теперь, когда у вас есть представление о том, как проблему решали раньше, давайте взглянем, на что способны Flexbox и Grid.

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

Решение задачи с помощью Flexbox

Контекст форматирования Flexbox инициализируется путем создания flex-контейнера.

Родительским элементом является body. Он содержит боковую панель и основную зону. Создаём контейнер:

body {
display: flex;
}

И получаем:

Flexbox в действии
Flexbox в действии

Не забудем о пропорциях:

aside {
width: 25%;
}
main {
width: 75%;
}

Вуаля! Проблему можно считать решенной:

Задача решена
Задача решена

С Flexbox можно делать много разных вещей:

  • Отцентрировать боковую панель и основную зону по вертикальной оси:

html, body {
height: 100%;
}
body {
align-items: center;
}

Боковая панель и основной контент отцентрированы по вертикальной оси
Боковая панель и основной контент отцентрированы по вертикальной оси
  • Изменить положение одного из дочерних элементов:

aside {
align-self: center;
}

Боковая панель отцентрирована по вертикальной оси
Боковая панель отцентрирована по вертикальной оси
  • Менять порядок дочерних элементов без изменения HTML-кода:

aside {
order: 2
}

Боковая панель теперь размещена после блока с основным контентом
Боковая панель теперь размещена после блока с основным контентом

И я затронул лишь верхушку айсберга Flexbox.

Flexbox доступен в большинстве поддерживаемых браузеров. Им можно полноценно пользоваться в Firefox с 28 версии, Chrome с 29, Safari с 6.1 и Edge с 12.

Прим. перев. Разобраться с Flexbox поможет наше наглядное введение.

Решение проблемы с помощью Grid

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

Начинается всё так же, как и в случае с Flexbox. Создаём контейнер:

body {
display: grid;
}

Вот весь CSS:

body {
display: grid;
background-color: #eeeeee;
}
aside {
color: #fff;
background-color: #8cacea;
}

И вот что мы получим:

Первичный вариант
Первичный вариант

Grid доступен в большинстве поддерживаемых браузеров, хотя и в меньшем количестве. Им можно полноценно пользоваться в Firefox с 52 версии, Chrome с 57, Safari с 10.1 и Edge с 16.

Наше последнее изображение пока никак не отличается от предыдущих. Так в чём же магия?

Что, если мы разделим пропорции ширины, как раньше:

aside {
width: 25%;
}
main {
width: 75%;
}

Пропорциональное распределение ширины для дочерних элементов
Пропорциональное распределение ширины для дочерних элементов

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

Вот мы и подошли к сути Grid-разметки. После инициализации Grid-контейнера при помощи display: grid необходимо определить ряды и строки внутри него.

Вот как это делается:

body {
grid-template-columns: 30% 70%;
}

Решение в одну строку — красиво, не правда ли? grid-template-columnsопределяет пропорции столбцов в сетке.

Задача решена
Задача решена

Но с помощью Grid можно сделать гораздо больше.

Сначала добавим немного цвета главному блоку, чтобы примеры были более наглядными:

main {
background-color: rgba(39,174,96 ,1);
color: #fff;
}

Вот что мы должны получить:

Заливка цветом зоны основного контента
Заливка цветом зоны основного контента

Посмотрим, что хорошего может предложить Grid:

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

body {
grid-column-gap: 15px;
}

Вот результат:

С разрывом между колонками выглядит гораздо опрятней.
С разрывом между колонками выглядит гораздо опрятней.

Нет необходимости в добавлении отступов к блокам aside и main: это делает grid-column-gap.

  • Можно сделать столько столбцов, сколько вам нужно. Примеры выше использовали только по одному элементу aside и main. Добавим ещё два:

<body>
<aside>
Lorem ipsum dolor sit amet.
</aside>

<main>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim.
</main>

<aside>
Lorem ipsum dolor sit amet.
</aside>

<main>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim.
</main>

<aside>
Lorem ipsum dolor sit amet.
</aside>

<main>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim.
</main>

</body>

Две колонки все еще соответствуют пропорциям 30% / 70%
Две колонки все еще соответствуют пропорциям 30% / 70%

Grid сам понял, что нам надо — не пришлось даже трогать CSS.

  • Можно определить пробел между строками:

body {
grid-row-gap: 15px;
}

Добавлен разрыв между строками
Добавлен разрыв между строками

Для упрощения можно использовать сокращение: grid-gap: 15 px вместо grid-row-gap и grid-column-gap.

  • Можно определять размеры строк:

body {
grid-template-rows: 200px 300px 400px;
}

Разная высота строк
Разная высота строк

Теперь высота первой, второй и третьей строк равна 200, 300 и 400 пикселей соответственно.

Для начала хватит и этого — но это далеко не всё.

Как начать работу с новыми стандартами?

Вы увидели пример того, как Flexbox и Grid предоставляют более удобные решения для разметки. Так как начать?

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

Почему вас должны волновать эти стандарты?

Если вы до сих пор не поняли, почему стоит использовать Flexbox и Grid, то вот несколько проблем, с которыми вы можете столкнуться при использовании предыдущих решений:

  • если вы используете «плавающие» блоки и clearfix, то знаете, что с ними могут возникать проблемы;
  • при абсолютном позиционировании элементы могут накладываться друг на друга;
  • при использовании display: table остается много ненужной разметки;
  • при использовании inline-block возникнут проблемы с пустыми местами.