CSS

Grid для макетов, Flexbox для компонентов

Spread the love

Перевод статьи: Ahmad Shadeed — Grid for layout, Flexbox for components

Мой брат только что закончил университет по компьютерной специальности, и в настоящее время заканчивает стажировку в области фронтенд разработки. Он узнал как о CSS grid, так и о flexbox, но задал вопрос, который я часто нахожу в Интернете. Ему всегда сложно определиться, когда использовать grid а когда flexbox. Например, он использовал grid для макета заголовка веб-сайта и упомянул, что этот процесс был непростым, поскольку он использовал grid-column и пытался настроить так как было указано в дизайне.

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

Введение

Прежде чем углубляться в концепции и примеры, я хочу убедиться, что вы понимаете основное различие между CSS grid и flexbox. CSS grid — это модуль многомерного макета, что означает, что он имеет столбцы и строки. Flexbox может размещать свои дочерние элементы только в виде столбцов или строк, но не обоих одновременно.

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

Разница между Grid и Flexbox

Позвольте мне прояснить это, нет однозначного способа выбора между CSS grid и flexbox. Кроме того, не существует правильного или неправильного способа их использования. Эта статья представляет собой своего рода руководство, которое рекомендует использовать технику для конкретного случая использования. Я объясню общую концепцию, а затем перейду к примерам, а остальное зависит от вас, чтобы исследовать и экспериментировать.

/* Flexbox wrapper */.wrapper {
    display: flex;
}

/* Grid wrapper */.wrapper {
    display: grid;
    grid-template-columns: 2fr 1fr;
    grid-gap: 16px;
}

Вы что-то заметили? Flexbox представляет собой встроенный список элементов, а grid сделал их сеткой из столбцов и строк. Flexbox выравнивает выравнивание в ряд по горизонтали или вертикали.

/* Flexbox wrapper */.wrapper {
    display: flex;
    flex-direction: column;
}

Как решить, что использовать

Выбор между grid и flexbox может быть немного сложным (иногда), особенно если вы новичок в CSS. Вот несколько начальных вопросов, которые я задаю себе, выбирая между ними:

  • Как отображаются дочерние элементы компонента? В строке или в виде столбцов и строк?
  • Как компонент должен работать на экранах разных размеров?

В большинстве случаев, если у просматриваемого компонента все дочерние элементы отображаются встроенными (inline) в ряд, то, скорее всего, лучшим решением здесь будет flexbox. Рассмотрим следующий пример:

Однако, если вы видите столбцы и строки, тогда сетка CSS — это решение для вашего случая.

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

Случаи использования и примеры

В следующем разделе я подробно расскажу о различных сценариях использования как flexbox, так и grid.

Grid

Main и Sidebar

Когда у вас есть боковая и основная панель, grid — идеальное решение для их создания. Рассмотрим следующий макет:

Вот как я бы сделал это в CSS:

<div class="wrapper">
    <aside>Sidebar</aside>
    <main>Main</main>
</div>
@media (min-width: 800px) {
    .wrapper {
        display: grid;
        grid-template-columns: 200px 1fr;
        grid-gap: 16px;
    }
    
    aside {
        align-self: start;
    }
}

Если для элемента  <aside> не использовалось align-self, высота его будет равна высоте основного элемента, независимо от длины содержимого.

Карточки Grid

Как обсуждалось в начале статьи, CSS grid не требует пояснений из своего названия, поэтому использование ее для создания сетки карточек — идеальное ее применение.

Вот как я бы реализовал макет:

.wrapper {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    grid-gap: 16px;
}

Ширина столбца будет не менее 200 пикселей, и если места недостаточно, карточки будут помещены на новую строку. Стоит отметить, что указанное выше решение может вызвать горизонтальную прокрутку, если ширина области просмотра меньше 200 пикселей.

Простое решение — добавить определение сетки только тогда, когда ширины области просмотра будет достаточно:

@media (min-width: 800px) {
    .wrapper {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
        grid-gap: 16px;
    }
}

Макет раздела

В следующем дизайне мы можем использовать grid дважды, первое использование — разделить область на две области (боковая панель для связи и форма), второе — использовать саму grid формы.

Я не могу сказать, насколько grid идеально подходит для этого. Но вот как это сделать в CSS:

@media (min-width: 800px) {
    .wrapper {
        display: grid;
        grid-template-columns: 200px 1fr;
    }
    
    .form-wrapper {
        display: grid;
        grid-template-columns: 1fr 1fr;
        grid-gap: 16px;
    }
    
    .form-message,
    .form-button {
        grid-column: 1 / 3; /* let them take the full width */    }
}

Этот пример заимствован из моей статьи на Envato о создании макетов веб-форм с помощью CSS grid.

CSS Flexbox

Навигация по сайту

В 90% случаев навигация по сайту должна быть построена с помощью CSS Flexbox. Самый распространенный шаблон — это логотип слева и навигация справа. Это идеально подходит для flexbox.

В приведенном выше примере все, что вам нужно установить, если следующее:

.site-header {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
}

Та же концепция может работать и на следующем дизайне.

Обратите внимание, как структура навигации немного изменилась, но расстояние между элементами по-прежнему задается с помощью свойства justify-content.

Список действий

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

Как видите, элементы отображаются рядом друг с другом и распределяются по горизонтали. Flexbox идеально подходит для этого! Это одно из основных его применений.

.actions-list {
    display: flex;
}

.actions-list__item {
    flex: 1; /* expand the items to take the available space equally between them */}

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

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

Для модального заголовка это выглядит так:

.modal-header {
    display: flex;
    justify-content: space-between;
}

А с нижним колонтитулом все немного иначе. Действие «Отмена» использует auto, чтобы сдвинуть себя вправо. Я написал об этом подробную статью.

.cancel__action {
    margin-left: auto;
}

Именование .cancel__action здесь может быть не идеальным, но я не хочу вдаваться в соглашения об именах CSS в этой статье.

Элементы формы

Комбинация поля ввода и кнопки рядом с ним — идеальный вариант использования Flexbox. Рассмотрим рисунок ниже:

В первой форме ввод занимает все оставшееся пространство, что делает его с динамической шириной. То же самое и со второй формой (мессенджер Facebook), текстовое поле занимает все оставшееся место. Давайте посмотрим поближе.

.input { flex: 1 1 auto; }

Обратите внимание, как без использования flex: 1 1 auto в текстовом поле оно не будет расширяется и не заполнит все оставшееся пространство.

Комментарии

Другой распространенный вариант использования flexbox — поток комментариев. Рассмотрим следующий пример.

У нас есть фото пользователя и сам комментарий. Комментарий занимает оставшееся пространство у своего родительского элемента. Это идеальное применение для flexbox.

Компоненты карточек

Компонент карточек имеет множество вариаций, но наиболее распространенный дизайн похож на макет ниже.

Слева дочерние элементы карточки уложены в стопку, потому что направление flex оболочки — column. А справа все наоборот. Используемое направление — row, и имейте в виду, что row используется по умолчанию для flexbox.

.card {
    display: flex;
    flex-direction: column;
}

@media (min-width: 800px) {
    .card {
        flex-direction: row;
    }
}

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

Обратите внимание, как значок и текстовая метка центрированы по горизонтали и вертикали. Благодаря flexbox это легко сделать.

.card {
    display: flex;
    flex-direction: column;
    align-items: center;
}

Встроенный стиль будет по умолчанию, нам просто нужно удалить столбец flex-direction: column и оставить для него значение по умолчанию (row).

Вкладки (Tabs) / Нижнее меню

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

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

.tabs__item {
    flex-grow: 1;
}

Этот метод используется в среде React Native для создания панели вкладок для мобильных приложений. Вот пример кода, который делает то же самое, что и выше, в React Native. Код заимствован с этого ресурса.

import React from 'react';
import { View } from 'react-native';

export default FlexDirectionBasics = () => {
    return (
      <View style=>
        <View style= />
        <View style= />
        <View style= />
      </View>
    );
};

Список возможностей

Что мне больше всего нравится в flexbox, так это возможность менять направление элементов на противоположное. Направление flexbox по умолчанию — row, но мы можем изменить его, как показано ниже.

.item {
    flex-direction: row-reverse;
}

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

Центрирование содержимого раздела

Предположим, у нас есть раздел и его контент нужно центрировать по горизонтали и вертикали. Горизонтальное центрирование может быть простым, поскольку оно может быть выполнено с выравниванием текста.

.hero {
    text-align: center;
}

Но как использовать flexbox для центрирования элементов по вертикали? Вот что нужно.

.hero {
    display: flex;
    flex-direction: column;
    align-items: center; /* центрирование по горизонтали */    justify-content: center; /* центрирование по вертикали */    text-align: center;
}

Объединение CSS Grid и Flexbox

Не только у каждого модуля макета есть свои варианты использования, но мы можем использовать их оба. Когда я думаю об их объединении, первое, что у меня возникает, — это список карточек. Grid используется для размещения карт, а flexbox используется для самого компонента карточки.

Вот требования к макету:

  • Высота карточек для каждого ряда должна быть одинаковой.
  • Ссылка «read more» должна располагаться в конце карточки независимо от ее высоты.
  • grid должна использовать функцию minmax()
<div class="wrapper">
    <article class="card">
        <img src="sunrise.jpg" alt="">
    <div class="card__content">
      <h2><!-- Title --></h2>
      <p><!-- Desc --></p>
      <p class="card_link"><a href="#">Read more</a></p>
    </div>
    </article>
</div>
@media (min-width: 500px) {
    .wrapper {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
        grid-gap: 16px;
    }
}

.card {
    display: flex; /* [1] */    flex-direction: column; /* [2] */}

.card__content {
    flex-grow: 1; /* [3] */    display: flex; /* [4] */    flex-direction: column;
}

.card__link {
    margin-top: auto; /* [5] */}

Позвольте мне объяснить приведенный выше CSS.

  1. Делаем карточки как обертку flexbox.
  2. direction — column, что означает, что элементы карточек уложены друг на друга.
  3. Позволим содержимому карточек расшириться и заполнить оставшееся пространство.
  4. Делаем содержимое карточек как оболочку flexbox.
  5. Наконец, используйте margin-top: auto, чтобы переместить ссылку вниз. Это сохранит ее положение в конце независимо от высоты карточки.

Как вы видели, объединить CSS grid и flexbox несложно. Эти два инструмента могут дать нам множество способов реализовать макеты в Интернете. Давайте использовать их правильно и комбинировать только при необходимости, как указано выше.

Поддержка старых браузеров

Используйте CSS @supports

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

Да, это мой веб-сайт — веб-сайт интерфейсного разработчика на IE11. Сначала я был сбит с толку, почему это происходит? Я вспомнил, что CSS-сетка поддерживается в IE11, но это его старая версия, выпущенная Microsoft. Решение очень простое: использовать @supports, чтобы использовать CSS-сетку только для новых браузеров.

@supports (grid-area: auto) {
    body {
        display: grid;
    }
}

Позвольте мне это объяснить. Я использовал grid-area, потому что он поддерживается только в новой спецификации CSS grid с марта 2017 года по сегодняшний день. Поскольку IE не поддерживает запросы @supports, все правило будет проигнорировано. В результате новая сетка CSS будет использоваться только для поддержки браузеров.

Использование Flexbox в качестве альтернативы CSS Grid

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

@mixin grid() {
  display: flex;
  flex-wrap: wrap;

  @supports (grid-area: auto) {
    display: grid;
    grid-gap: 16px 16px;
  }
}

@mixin gridAuto() {
  margin-left: -16px;

  > * {
    margin-bottom: 16px;
    margin-left: 16px;
  }

  @media (min-width: 320px) {
    > * {
      width: calc((99% / #{2}) - 16px);
      flex: 0 0 calc((99% / #{2}) - 16px);
    }
  }

  @media (min-width: 768px) {
    > * {
      width: calc((99% / #{3}) - 16px);
      flex: 0 0 calc((99% / #{3}) - 16px);
    }
  }

  @supports (grid-area: auto) {
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    margin-left: 0;

    > * {
      width: auto;
      margin-left: 0;
      margin-bottom: 0;
    }
  }
}

Приведенный выше резервный код работает следующим образом:

  1. Добавляет display: flex и flex-wrap: wrap к обертке элемента.
  2. Проверяет, поддерживается ли grid, если да, то вместо нее будет использоваться display: grid.
  3. Используя selector > *, мы можем выбрать прямые дочерние элементы оболочки. Выбрав их, мы можем добавить каждому из них определенную ширину или размер.
  4. Конечно, необходим margin между ними, и он будет заменен на grid-gap, если поддерживается grid.

Вот пример того, как использовать Sass миксин.

.wrapper {
  @include grid();
  @include gridAuto();
}

Demo

Как не надо использовать Grid и Flexbox

Когда я делал обзор кода для своего брата, я заметил пару неправильных применений CSS grid или flexbox и подумал, что было бы полезно, если бы я выделил некоторые из них.

Использование CSS Grid для заголовка веб-сайта

Одна из причин написания этой статьи — этот пример. Я заметил, что мой брат использует grid для реализации заголовка веб-сайта.

Он упомянул следующие выражения, как «это было сложно, grid сложна и т. д.». В результате использования неправильного метода компоновки он подумал, что grid очень сложна технология. Но это не так, и все его замешательство возникло из-за того, что он использовал его для чего-то неподходящего.

Рассмотрим следующий пример, который я заметил.

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

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

CSS grid использовалась дважды: первый раз для всего заголовка, второй — для навигации. Он использовал grid-column для точной настройки расстояния между элементами и других странных вещей, которые я не могу вспомнить, но вы поняли!

Использование CSS Grid для Tabs

Еще одно неправильное использование CSS grid — ее применение к компоненту вкладок (Tabs). Рассмотрим следующий макет.

Неправильный код CSS выглядит так:

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

Из приведенного выше кода я вижу, что разработчик предположил, что количество вкладок всего три. В результате он использовал 1fr 1fr 1fr для выкладки колонок. Это может легко сломаться, если количество столбцов изменится.

Чрезмерное использование Flexbox или Grid

Помните, что старые методы компоновки так же могут идеально подойти для многих вариантов. Чрезмерное использование flexbox или grid может со временем усложнить ваш CSS. Я не имею в виду, что они сложные, но использовать их правильно и в правильном контексте, как объясняется в примерах в этой статье, намного лучше.

Например, у вас есть следующий раздел с требованием на горизонтальное центрирование всего его содержимого.

Это можно сделать с помощью text-align: center. Зачем использовать flexbox, если есть более простое решение?

Заключение

Уф, я много написал о различиях между использованием grid и flexbox. Эта тема была в голове долгое время, и я рад, что мне представилась возможность написать об этом. Не стесняйтесь оставлять отзывы по электронной почте или в Twitter @shadeed9!

Спасибо за чтение.

Я пишу электронную книгу

Рад сообщить вам, что я пишу электронную книгу об отладке CSS.

Если вам интересно, перейдите на debuggingcss.com и подпишитесь на обновления о книге.

Была ли вам полезна эта статья?
[5 / 4.8]

Spread the love
Editorial Team

Recent Posts

Vue 3.4 Новая механика v-model компонента

Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование​ v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…

12 месяцев ago

Анонс Vue 3.4

Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…

12 месяцев ago

Как принудительно пере-отобразить (re-render) компонент Vue

Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…

2 года ago

Проблемы с установкой сертификата на nginix

Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…

2 года ago

Введение в JavaScript Temporal API

Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…

2 года ago

Когда и как выбирать между медиа запросами и контейнерными запросами

Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…

2 года ago