Решающая CSS битва: Grid против Flexbox
Узнайте, чем они отличаются и когда их нужно использовать вместе.
Dec 21, 2017 · 5 min read
👉 Мой Твиттер — там много из мира фронтенда, да и вообще поговорим🖖. Подписывайтесь, будет интересно: ) ✈️
CSS Flexbox стал крайне популярным среди Front-end разработчиков за последние несколько лет. И это не удивительно, поскольку теперь стало легче создавать динамические шаблоны и выравнивать контент внутри контейнеров.
Однако, на районе появился новый парниша по имени CSS Grid и у него очень много тех же возможностей, что и у Flexbox. В одних случаях, он даже лучше, чем Flexbox, в то время как в других совершенно нет.
Такой расклад событий вводит разработчиков в смятение. Поэтому, в этой статье мы сравним два модуля, как на микро, так и на макро уровнях.
Одномерное против двумерного
Если вы хотите получить урок из этой статьи, то пусть он пусть он будет таким. Flexbox это одномерные макеты, а Grid это двумерные.
Это означает, что если вы раскладываете объекты в одном направлении, к примеру, кнопку в header, то вам нужно применять Flexbox.
Это даст вам больше гибкости, чем в случе с CSS Grid. Также с этим будет проще работать в дальнейшем, а самое важное вы избежите лишней писанины.
В этом случае с CSS Grid вы получите больше гибкости, да и ваша разметка будет проще, а код станет понятнее для дальнейшей работы.
Упор на контент или на макет?
Ещё одно кардинальное отличие в том, что Flexbox берет за основу контент, в то время как в основе Grid лежит сам макет и его общая разметка. С первых слов это всё довольно абстрактно, поэтому давайте взглянем на конкретный пример, который позволит нам легче понять суть того, что происходит.
Мы будем использовать header из предыдущего параграфа. Вот как выглядит его HTML.
Перед тем как мы зафлексбоксим макет, эти дивы будут располагаться друг над другом. Как тут:
Flexbox header
Итак, когда мы укажем display: flex все элементы аккуратненько встанут в линию.
Для того, чтобы отправить кнопку logout в правый угол, мы просто укажем нужный элемент и зададим ему внешний отступ.
Это даст нам такой результат:
Это основное различие между Flexbox и Grid и сейчас это станет ещё понятнее, после того как мы переделаем header на Grid’ах.
Пусть даже CSS Grid не задуман для создания одномерных header’ов, это всё же хороший пример для проработки в этой статье, так как он научит понимать основные понятия между Flexbox и Grid.
Grid header
Мы можем создать наш header несколькими разными способами с помощью CSS Grid. Тут же мы увидим довольно понятный способ, где у grid есть десять колонок, каждая из которых является частью формирования ширины элемента.
Это будет идентично решению через Flexbox.
Но давайте взглянем поглубже и посмотрим в чем же разница. Зайдем в Chrome inspector, чтобы увидеть границы колонок.
Ключевое различие тут в том, что мы должны сначала выставить определения колонок макета. Начиная с определения ширины колонок и потом выставляя контент в доступные ячейки grid.
Этот подход заставил нас четко определить позицию, на сколько колонок мы хотим разделить header.
Пока мы не изменим сетку, выходит, что мы застряли с этими десятью колонками. Это ограничение, с которым бы мы не столкнулись, имея дело только с Flexbox.
Для того, чтобы кнопку logout поставить в конец секции справа, мы поставим этот элемент DOM в десятую колонку, как тут:
Вот как это будет выглядеть при детальном виде расположения колонок.
Совмещаем два подхода
А теперь давайте посмотрим, как применять два эти подхода вместе, объединяя header со всем нашим макетом. Мы начнем с построения самого макета.
Вот так мы расставим элементы по сетке:
Теперь мы просто добавим header. Его мы зафлексбоксим, хотя он уже является элементом нашего Grid CSS.
Теперь мы можем установить кнопку logout справа.
И теперь, у нас идеальный макет, который использует как Grid, так и Flexbox. Вот как выглядят оба контейнера.
Итак, теперь у вас имеется четкое понимание основ и конкретных различий между Flexbox и Grid, и самое важное — это понимание того, как использовать их вместе.
Поддержка браузеров
Перед тем как мы закончим, также надо упомянуть о поддержке браузерами. На момент написания этой статьи, 77% глобального трафика сайтов поддерживали CSS Grid и этот показатель постоянно растет.
Скорее всего, 2018 будет годом CSS Grid. Это будет его прорывом и он станет необходимым навыком для front-end разработчика. Точно также как это было с CSS Flexbox несколько лет назад.
Выбор CSS макета — Grid или Flexbox?
Удачно оформленный макет удерживает пользователей на сайте, так как делает важные элементы доступными и легко находимыми. Слабые же макеты отпугивают посетителей, которые покидают ресурс, так и не найдя того, за чем пришли.
В веб-дизайне макет – это то, как сайт отображается на экране. В HTML 5 есть довольно много элементов, определяющих внешний вид веб-страницы: заголовок, навигационный блок, абзац, сноска, статья и нижний колонтитул, каждый из которых имеет свое особое значение в создании макета. Вместе же они формируют четыре основных раздела страницы – заголовок/баннер, поисковый блок, содержимое и нижний колонтитул.
Языки программирования помогают сделать сайты «живыми», но в основе каждой страницы по-прежнему лежит старый добрый HTML. При рассмотрении макетов необходимо учитывать факторы, определяющие их качество, а именно отзывчивость, порты просмотра, устройства отображения, браузеры и размеры экранов пользователей. Грамотный макет не только здорово смотрится, но также может сохранять задуманную структуру, вписываясь в экраны с любым возможным соотношением сторон. Как раз за эту подстройку и отвечает CSS. В текущей статье мы в общих чертах рассмотрим два его мощнейших инструмента: Flexbox и Grid.
Что такое макет CSS FLEXBOX?
Flexbox – это общепринятое сокращение для Flexible Box Module (модуль гибкого контейнера), который представляет собой одномерную модель макета. Это значит, что одновременно он может работать только со строкой или столбцом, но не с обоими сразу. Flexbox эффективно справляется с выравниванием, распределением и направлением элементов страницы.
Двумя основными понятиями этой модели макета являются главная ось и поперечная ось. Главная ось flex-контейнера – это основное направление, вдоль которого выстраиваются flex-элементы, поперечная же ось ей перпендикулярна.
Для начала давайте обернем HTML-элементы div во flex-wrapper.
В CSS родительский контейнер “flex-wrapper” преобразуется во flexbox с помощью простой инструкции.
При добавлении элементов и свойств я буду использовать яркие цвета и отступы, чтобы выделить контейнеры и div-элементы.
Вы можете видеть, как удачно элементы div располагаются по горизонтали, но при этом они занимают не всю область контейнера, и в конце остается пустое пространство. Это можно исправить, добавив flex-grow.
Свойство flex-grow отвечает за распределение каждого элемента flex-контейнера. По умолчанию значение этого свойства равно 0, присваивая же разное количество единиц div-элементам, вы увеличиваете их по отношению к остальным. Противоположный эффект дает свойство flex-shrink.
FLEX-DIRECTION
Flex-direction определяет направление размещения элементов контейнера. С его помощью можно заставить их располагаться по направлению вверх, вниз, влево или вправо, а также в обратном порядке. По умолчанию элементы flex-контейнера упорядочены вдоль главной оси слева направо.
Здесь элементы также отображаются слева направо, но в обратном порядке. В итоге четвертый div становится первым, а первый, в свою очередь, последним.
Здесь же упорядочивание происходит уже вертикально – сверху вниз.
Теперь элементы также расположены вертикально, но в обратном порядке, т.е. четвертый оказался вверху, а первый внизу.
FLEX BASIS
Flex basis определяет размер элемента внутри контейнера. При этом значение размера может указываться в em, px или процентах. Это свойство отличается от flex-grow тем, что не распределяет пространство между элементами контейнера равномерно.
Flex – это сокращенное свойство, объединяющее flex-shrink, flex-grow и flex-basis. Его рекомендуется использовать вместо раздельного написания свойств, указывая в нем их значения в следующем порядке: flex-grow, flex-shrink, flex-basis.
JUSTIFY-CONTENT И ALIGN-SELF
Justify-content и align-self – это идеальное решение для размещения div или контейнера в центре окна браузера.
CSS GRID Layout
CSS grid (сетка) представляет собой мощный двухмерный макет, при использовании которого можно одновременно работать со строками и столбцами. В основе CSS Grid лежит неявное разделение экрана на сетку из 12 частей, в которые в итоге и вписываются элементы.
Преимущество этой технологии перед Flexbox и другими видами макетов в ее возможности работать двухмерно. При этом она также упрощает позиционирование, и элементы контейнера могут размещаться, перекрывая друг на друга.
ОПРЕДЕЛЕНИЕ СЕТКИ В CSS GRID
Преобразование HTML-структуры в СSS сетку выполняется одной простой CSS инструкцией.
GRID TEMPLATE-COLUMNS И GRID-TEMPLATE-ROWS
Свойства grid-template-columns и grid-template-row устанавливают величину столбца или строки, определяя размер div-элементов согласно присвоенным значениям, которые указываются в px, fr, процентах или em.
grid-template-columns: 40px 1fr 20%; — эта строка дает браузеру команду присвоить первому div ширину 40px, второй же занимает одну долю отведенного места, а третий 20%. Элементы с 4 по 6 автоматически смещаются под первые 3 и принимают те же значения в том же порядке, т.е. div 4 получает размер 40px, div 5 — одну долю, а div 6 – 20%.
Чтобы поместить все шесть div-элементов в одну строку нужно указать в свойстве grid-template-column шесть значений. При этом не обязательно использовать для столбцов разные единицы измерения, можно задать только проценты, fr или px.
grid-template-rows: 200px; — эта строка присваивает всем div-элементам высоту в 200px.
Присвоив 16,7% для 6 точек, я успешно разделил шесть элементов контейнера по шести равным частям экрана. Значение 16,7% я выбрал, потому что при умножении 16,7 на 6 как раз получится 100% ширины экрана.
Использование процентов и пикселей работает идеально, но им недостает гибкости, и они уступают наиболее эффективному компоненту – долям CSS сетки.
Fr – это дробная единица, которая присваивает каждому элементу одну долю доступного пространства, которое можно увеличивать, выделяя под div необходимую ему область.
Теперь наше свойство grid-template-columns стало:
В результате каждый div-элемент был размещен на экране равномерно.
Изменив второе и четвертое значения, мы сделали соответствующие элементы вдвое больше остальных. Самое же главное, что они по-прежнему распределяются в браузере равномерно и имеют высокую отзывчивость.
ФУНКЦИЯ REPEAT
Вместо того, чтобы повторно переписывать значения, можно задействовать функцию repeat, которая позволит сделать это всего один раз.
Синтаксис этой функции относительно прост. Сначала пишем слово “repeat”, после которого определяем, сколько раз нужно повторить размер, в данном случае 6, а затем указываем величину единицы измерения. Эта функция аналогичным образом работает со свойством template-row и позволяет использовать как fr, em, px, так и проценты.
Gap – это отступ, представляющий свойство CSS сетки, которое позволяет указывать расстояние между div-элементами контейнера. Работает оно точно также, как свойство margin и измеряется обычно в px.
GRID-COLUMN-START/GRID-COLUMN-END И GRID-ROW-START/GRID-ROW-END
Свойства grid-column-start и grid-column-end помещают элемент сетки в конкретное место столбца относительно определенных строк сетки. Свойства же grid-row-start и grid-row-end делают то же самое, но в отношении строки. Присваивая этим свойствам значения, можно удобно управлять начальной и конечной точкой элемента сетки, выделяя ему нужную область.
Если вы присвоите указанные значения первому div, то заметите, что он смещает второй div на одну единицу и занимает первые две позиции, смещая третий div вниз. В отношении же строк теперь он занимает три позиции и становится выше.
В программировании индексация производится по особому правилу, согласно которому мы обычно начинаем отсчет с 0. В этом случае последнее значение, как правило, упоминается, но не учитывается. Например, значение свойства grid-column-end равно 3, но по факту оканчивается оно на 2-х также, как и grid-row-end оканчивается на 3-х, а не на 4-х.
GRID-COLUMNS И GRID-ROW
Это сокращенный вариант для свойств grid-column-start/grid-column-end и grid-row-start/grid-row-end. В качестве значений в этом случае через слэш указываются начальные и конечные позиции элемента:
СОЗДАНИЕ ГАЛЕРЕЙ
CSS сетка идеально подходит для создания галерей. С помощью небольшого количества кода и манипуляций вы можете создать их прекрасные отзывчивые макеты.
Мозаичный макет галереи
Такой макет создает равные плитки изображений, равномерно распределенные по странице/контейнеру.
Этот код создаст прекрасный макет плиточной галереи изображений.
Макет Masonry-галереи
Этот макет уже неравномерен, так как не имеет фиксированной высоты строк. Однако при помощи grid-columns и grid-rows мы можем подстраивать изображения, чтобы они вписывались в назначенные дробные единицы и перемещались по ним нужным нам образом.
GRID TEMPLATE AREAS
Свойство Grid-template-areas присваивает элементам имена, чтобы свойство grid-area могло на них ссылаться. Работает оно аналогично grid-column и grid-row, позволяя легко отображать и размещать конкретные области в структуре сетки.
GRID AREAS
Ссылаться на именованные области необходимо в порядке их вызова. Например, область сетки для #one не может быть нижним колонтитулом, поскольку эта область сетки именуется последней. Нарушение же правильного порядка приведет к ошибке в дизайне.
Что же лучше — Flexbox или Grid?
В своей сути Grid является макетом на основе контейнеров, а Flexbox на основе содержимого. И тот, и другой по-своему эффективен, хотя CSS Grid включает больше возможностей и позволяет легче манипулировать строками и столбцами сетки. Прежде чем решать, какой использовать, следует проанализировать сложность, структуру и содержимое создаваемого вами сайта. Приведу еще одно несколько углубленное сравнение: в макете flexbox размер ячейки (flex-элемента) определяется в самом flex-элементе, а в макете Grid размер элемента определяется уже в его контейнере.
Лично я могу посоветовать использовать CSS Grid для общего макета сайта, а затем уже Flexbox для элементов контейнера. Однако CSS Grid также отлично работает с отдельными элементами и учитывает нюансы реальной структуры сетки лучше, чем Flexbox. Например, инструкция grid-template-areas отобразит структуру сайта буквально за несколько секунд, после чего вы сможете сосредоточится на выравнивании контента по своему усмотрению.
Grid или Flexbox?
Мишель Баркер, автор материала, перевод которого мы сегодня публикуем, говорит, что недавнее обсуждение в Twitter, начатое Крисом Койером, заставило её задуматься о том, как веб-разработчики делают выбор между технологиями CSS Grid Layout и CSS Flexbox Layout при разработке макетов.
Крис Койер в своём твите задал аудитории вопрос о том, как те, кто знает о том, что такое Grid и Flexbox, предпочитают объяснять разницу между этими технологиями.
Среди ответов на этот вопрос, что, по словам Мишель, вполне ожидаемо, можно было отметить ценные идеи Рэйчел Эндрю и Джен Симмонс.
Рэйчел сказала, что технология Flexbox предназначена для разработки одномерных макетов, представляющих собой описание расположения элементов в строке или в столбце. А технология Grid предназначена для разработки двумерных макетов, в которые входят и строки, и столбцы.
Джен говорит, что, технология Grid используется для описания строк и столбцов макетов. При этом содержимое будет располагаться в ячейках макета именно так, как это нужно разработчику. При использовании Flexbox это не так, причём, речь идёт не только о размещении данных во втором измерении (это и так понятно), но и о размещении их в одном измерении. Технология Flexbox не подходит для большинства случаев, в которых её используют.
Мишель отмечает, что одно лишь чтение твитов не раскрывает особенностей использования технологий Grid и Flexbox. В этом материале она хочет рассказать о том, когда и где стоит использовать эти технологии, а также о том, по каким причинам можно предпочесть одну технологию другой.
Читая ответы на вопрос Криса, Мишель была удивлена тем количеством людей, которые говорили о том, что они использовали бы Grid лишь для макетов уровня страницы, и Flexbox — для всего остального. Если вы тоже придерживаетесь подобного правила — это значит, что вы серьёзно ограничиваете себя в том, что касается использования мощных возможностей Grid в различных ситуациях. Главное, что автору материала хотелось бы порекомендовать веб-разработчикам, заключается в том, что каждый макет стоит воспринимать как нечто особенное, анализировать доступные возможности, и не делать предположений о том, какие технологии понадобятся для его создания. Вот некоторые вопросы, которые можно задать себе при выборе технологии, подходящей для разработки макета.
Много ли вычислений приходится выполнять?
Одно измерение или два?
Серьёзное различие технологий Grid и Flexbox заключается в том, что первая позволяет управлять расположением элементов в двух измерениях (в строках и столбцах), а вторая этого не позволяет. Опять же, это не означает, что никогда не следует использовать Grid для одномерных макетов. Я часто выбираю именно Grid — в тех случаях, когда мне нужна высокая точность в управлении размерами и положением элементов, расположенных в одном измерении. Данный подход продемонстрирован в этом примере на CodePen, и в этой сопутствующей ему статье.
Пример использования Grid
Как должны вести себя элементы?
Технологию Grid часто имеет смысл использовать в тех случаях, когда разработчику нужен контроль над поведением макета в двух измерениях. Однако это не говорит о том, что Grid всегда лучше Flexbox. При использовании Grid в распоряжении разработчика имеются строки и столбцы, ячейки, и так называемые грид-области (grid area), представляющие собой одну ячейку или группу из нескольких ячеек. При использовании Grid элементы должны быть расположены в этих ячейках или областях.
Предположим, у нас имеется макет, основанный на Grid, отличающийся следующими особенностями: есть девять элементов, расположенных слева направо в трёх строках по три элемента, между элементами имеются промежутки (gap) размером в 20 пикселей. Такой макет можно создать как с использованием Grid, так и с использованием Flexbox. Код описания такого макета, основанного на Grid, оказывается гораздо проще и чище:
Пример использования Grid
Подробнее об этой технике, а также о некоторых других полезных вещах, можно узнать, посмотрев это видео.
Если бы мы создавали подобный макет с помощью Flexbox, то, в отличие от только что описанного примера, нам понадобилось бы стилизовать и элементы, и контейнер:
Тут, в контейнере, понадобится указывать отрицательное значение для свойства margin — для того чтобы нейтрализовать тот факт, что общая ширина элементов больше, чем сам контейнер, и таким образом осуществить перенос данных на следующую строку. Кроме того, этот пример не может продемонстрировать то же самое отзывчивое поведение без дополнительных усилий с нашей стороны. Далее, надо отметить, что здесь, вероятно, может потребоваться использование медиа-запросов.
Вот пример на CodePen, который иллюстрирует вышесказанное.
Пример использования Flexbox
Существует несколько способов создать такой же макет с использованием Flexbox, но все они требуют применения неких «хаков», и происходит это по той причине, что такова их природа. Фактически, речь идёт о том, что, мы пытаемся использовать технологию Flexbox для того, для чего она, на самом деле, не предназначена. Но это не значит, что Flexbox — это всегда неудачный выбор основы для макета.
Многие современные CSS-фреймворки используют некие вариации этого метода для представления макетов. И, кстати, если вы хотите пойти именно таким путём, то могу порекомендовать Susy, набор инструментов, который берёт на себя все сложности по созданию подобных макетов.
Итак, что же лучше выбрать в этой ситуации? Grid или Flexbox? Возникает такое ощущение, что у Grid тут имеются некоторые неоспоримые преимущества, но для того чтобы ответить на этот вопрос, нам надо подумать о том, что должно произойти в том случае, если у нас имеется более девяти, но менее 12 элементов (если их будет, например, 12, то это позволит им полностью заполнить новую строку). Нужно ли нам, чтобы новые элементы просто находились бы в начале следующей строки, как было в тех примерах, что мы уже видели? Или нам надо, чтобы они вели бы себя как-нибудь иначе? Возможно, если в очередной строке будет находиться лишь один элемент, то нам нужно, чтобы он занял бы всё пространство этой строки, как в варианте A следующего примера? Или, может быть, если в новой строке будет всего два элемента, нам нужно, чтобы они были бы выровнены по центру, как в примере B?
Разные варианты размещения элементов в последней строке
При использовании макета, основанного на Grid, с применением автоматического размещения элементов, в нашем распоряжении оказывается лишь один вариант — размещение нового элемента в доступной ячейке, расположенной слева. Подобное размещение элементов можно встретить в предыдущих примерах. Тут мы исходим из предположения о том, что свойство direction не установлено в значение rtl (в таком случае элементы располагались бы справа налево, и единственный элемент в последней строке располагался бы в правой ячейке). В результате новые элементы при использовании Grid размещаются в следующих доступных ячейках сетки. Технология Flexbox позволяет гибко управлять расположением элементов. Это означает, что мы можем управлять поведением элементов, используя комбинацию свойств, управляющих размещением элементов и их выравниванием.
Вот пример, в котором продемонстрированы такие макеты, при использовании которых один или два элемента, приходящиеся на строку, рассчитанную на три элемента, занимают всю эту строку.
Элемент занимает всё доступное пространство строки
В результате оказывается, что независимо от технологии, используемой для формирования макета, всё сводится к тому, какое именно поведение элементов, расположенных в макете, интересует разработчика. И в разных ситуациях на один и тот же вопрос могут быть даны различные ответы.
Пытаетесь ли вы заменить Flexbox на Grid?
Когда я выступаю на различных мероприятиях, меня нередко спрашивают о том, когда я использовала бы Flexbox вместо Grid, и о том, нужна ли нам вообще такая технология, как Flexbox. Как мы уже видели в предыдущем примере, Grid — это не замена Flexbox. Обе технологии довольно-таки мирно сосуществуют, и знание о том, в каких ситуациях каждая из них лучше всего показывает себя, расширяет возможности по проектированию макетов.
На этом рисунке показан компонент, в ходе работы с которым нужно управлять размещением текста, изображения и заголовка, и с учётом столбцов, и с учётом строк. Так же тут нужно управлять тем, как они, в определённой степени, друг с другом взаимодействуют. Единственный способ удовлетворительного решения этой задачи заключается в использовании технологии Grid.
Но я без колебания воспользуюсь технологией Flexbox для создания навигационного меню, такого, которое показано в данном примере.
Меню, созданное средствами Flexbox
Здесь нужно управлять расположением элементов в единственном измерении, и надо, чтобы элементы вели бы себя гибко. С этой задачей технология Flexbox справляется на отлично. Благодаря использованию Flexbox можно указать, нужно ли переносить эти элементы на новые строки, или нет, что позволяет аккуратно отображать их в том случае, если имеющееся на странице свободное пространство не позволяет вывести все элементы в одной строке.
Как макет должен выглядеть в браузерах, которые не поддерживают технологию Grid?
Если мы пользуемся технологией Grid, то одной из возможных проблем, которую нам нужно принимать во внимание, является поддержка этой технологии браузерами. Тут же нам нужно продумать и то, что будет происходить в том случае, если наша страница будет выводиться в одном из браузеров, не поддерживающих Grid (например — в IE 11 и ниже). Мой подход к решению этой проблемы заключается в использовании правил @supports и в подготовке кода, предназначенного для разных браузеров. Часто (но не всегда) я, в качестве замены макета, основанного на Grid, использую макет, основанный на Flexbox, предназначенный для достаточно старых браузеров.
Правда, тут надо отметить, что если вы ловите себя на том, что тратите многие часы на попытку воссоздать, без использования Grid, то, что было сделано с помощью этой технологии, тогда, возможно, у вас с самого начала было не так уж и много причин использовать именно Grid. Ведь эта технология особенно хороша тем, что она способна на то, что средствами исключительно Flexbox сделать нельзя.
Итоги
Мы обсудили несколько очень простых и широко распространённых примеров разработки макетов, рассмотрели особенности использования при их построении технологий Grid и Flexbox. Надеемся, нам удалось дать пищу для размышлений тем, кто занят выбором подходящей технологии для своего очередного макета.
Уважаемые читатели! В каких ситуациях вы пользуетесь технологией Grid, а в каких — Flexbox?

















