Знакомство с CSS Grid Layout

Перевод статьи Getting to know CSS Grid Layout с сайта cm.engineering для CSS-live.ru, автор — Крис Райт

ciu-grid

Фотографии из  Unsplash

CSS Grid — важнейшее событие для веб-раскладки, что случалось в браузерах со времен флексбоксов. Он позволяет избежать всяких магических чисел, хаков и обходных путей, к которым мы привыкли за последние 15 лет. С ним стало намного проще описывать раскладки, что здорово урежет нишу большинства ведущих CSS-фреймворков и позволит писать меньше стилей.

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

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

Необходимый минимум

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

Браузерная совместимость

CSS-гриды уже есть в Safari 10.1, Firefox 52, Opera 44 и Chrome 57.

Есть более старая реализация устаревшей спецификации со своими ограничениями, которая доступна в браузерах Microsoft, но мы лишь кратко её коснёмся, чтобы понять некоторые различия между новыми и старыми реализациями, и как обойти их.

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

@supports (display: grid) {
    .grid {
        display: grid;
    }
}

Браузеры, не поддерживающие @supports или гриды, не получат эту фичу.

Чтобы запускать примеры из статьи, вам потребуются браузеры с поддержкой Grid.

Создание двухколоночного грида с интервалами

Чтобы увидеть, как CSS Grid определяет колонки, возьмём эту раскладку:

ciu-grid

Двухколоночная раскладка с интервалами с использованием grid-template-columns и grid-gap

Этот грид можно создать с помощью grid-template-columns и grid-gap.

Grid-template-columns отвечает за то, как выкладываются колонки грида, оно принимает ряд значений через пробел, определяющих размер каждой колонки; сколько значений указано, столько и будет колонок.

Например, четырёхколоночный грид из колонок шириной по 250px можно описать так:

grid-template-columns: 250px 250px 250px 250px;

Ту же самую раскладку можно выразить с помощью удобного ключевого слова repeat.

grid-template-columns: repeat(4, 250px);

Определение интервалов

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

В нашем примере раскладки, разбитой на две колонки можно объявить наш грид так:

.grid {
  display: grid;
  grid-template-columns: 50vw 50vw;
  grid-gap: 1rem;
}

К сожалению, интервал добавится к общей ширине контейнера, которая будет рассчитываться как 100vw + 1rem, и раскладка в итоге будет с горизонтальным скроллбаром.

ciu-grid

Горизонтальный скроллбар от использования грид-интервала с единицами измерения относительно вьюпорта

Для исправления этого переполнения места нужно немного другое решение. Вводим единицу доли (FR, от англ. fraction).

Единица fr

Единица fr занимает долю доступного места; если бы доступное место составляло 900px, и при этом первому элементу досталась бы одна доля, а второму — две, то первый получил бы 1/3, а второй – 2/3 от этих 900px.

Переделаем наш новый код, заменив единицы вьюпорта на доли:

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

Выравнивание контента

Для выравнивания контента в нашем примере мы объявляем грид в дочерних элементах и размещаем их на соответствующих полосах с помощью свойств для выравнивания; полоса – это просто собирательное название для грид-колонок и рядов. У гридов, как и у флексбоксов, есть ряд свойств выравнивания – четыре значения – start, center, end и stretch, которые указывают дочерним элементам, где им находиться на отведённой для них полосе. Stretch, в отличие от других, растянет элемент от начала и до конца его полосы.

ciu-grid

align-items и justify-content

В нашем примере, чтобы пригнать контент к центру по вертикали и горизонтали, можно применить эти свойства к контейнеру:

.center-content {
    display: grid;
    align-items: center;
    justify-content: center;
}

демо двух колонок

Воссоздание двухколоночной раскладки с помощью старых гридов.

Чтобы воспроизвести эту раскладку с помощью старого грида, придётся учитывать много ограничений в реализации. Мало того, что в старом гриде нет grid-gap, так ещё и в каждом грид-элементе нужно объявить, где это будет начинаться, иначе по умолчанию он будет 1, что заставит все дочерние элементы складываться друг под дружку в первой колонке.

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

.grid-legacy {
   display: -ms-grid;
   -ms-grid-columns: 1fr 1rem 1fr; // gap replacement
}
.grid-legacy:first-child {
   -ms-grid-column: 1;
}
.grid-legacy:last-child {
    -ms-grid-column: 3;
}

Подход к выравниванию и растягиваиние старого грида на всю высоту

У старого грида есть та же проблема, что у флекбоксов в IE11: установка контейнеру min-height не всегда будет учтена. В гридах обойти эту проблему гораздо легче.

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

-ms-grid-rows: minmax(100vh, 1fr);

В самих дочерних элементах можно создать грид из единственной колонки и единственного ряда по 1fr.

.ms-cell {
   -ms-grid-columns: 1fr;
   -ms-grid-rows: 1fr;
}

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

.ms-align-center {
    -ms-grid-column: 1;
    -ms-grid-column-align: center; // как align-self в современном гриде
    -ms-grid-row-align: center; // как justify-self в современном гриде
}

Демо двух колонок на старых гридах

Если хотите посодействовать тому, чтобы Microsoft обновил Grid в MS Edge, посетите их страницу на сайте «статус платформы», посвященную обновлению CSS Grid и проголосуйте за неё, чтобы как можно больше повысить ее приоритет.

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

Создание негативного пространства с помощью CSS Grid

Одна возможность, которую дают вам гриды – объявить то, где начинаются колонки в грид-элементе с помощью свойства grid-column-start, что позволяет создать негативное пространство внутри грида.

ciu-grid

Негативное пространство с использованием grid-template-columns и grid-column-start

Один из способов создать негативное пространство — задать грид-элементу номер колонки больше его собственного порядкового номера, оставив изначально предназначенное ему место пустым и сдвинув элемент по горизонтали в новую колонку.

ciu-grid

Перемещение первого элемента с помощью grid-column-start

В примере выше с негативным пространством, разметка состоит из div-а, обёрнутого в другой div.

<div class="grid">
    <div class="child"><!-- содержимое --></div>
</div>

Грид представлен так:

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

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

.child {
    grid-column-start: 2;
}

Примечание: несоответствие в Firefox 52 приводит к некоторым проблемам с вертикальным выравниванием, где единица FR для высоты рядов не растягивается на всю высоту окна браузера, и для решения этой проблемы мы делаем дочерние элементы грид-элементами, и добавляем единственный ряд нужной нам высоты.

.l-grid--full-height {
    grid-template-rows: minmax(100vh, 1fr);
}

Демо создания негативного пространства

Создание «мёртвых зон» для контента

Если грид-элементу, который естественным порядком попал бы в третью колонку (поскольку вторая колонка перед ним занята), явно объявить grid-column-start:2;, то алгоритм постарается найти следующую свободную ячейку во второй колонке на следующих рядах.

ciu-grid

Мертвая зона для контента создана при помощи grid-template-columns и grid-column-start

Грид-полоса будет пропускать колонки, пока не найдёт следующую пустую вторую колонку. Это даёт возможность создать «мёртвую зону» внутри грида, где не будет назначено никаких грид-полос с контентом.

Демо «мёртвой зоны» для контента

Создание рядов

Что, если вы захотите разбить макет на четыре части? Всё, что мы рассмотрели до сих пор про колонки, применимо и к рядам.

.grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-template-rows: 250px 250px;
}

ciu-grid

Создание грид-раскладки при помощи grid-template-columns и grid-template-rows

Проблема в этом примере — это идеальный сценарий. Контент каждого грид-элемента достаточно мал, чтобы никогда не превысить указанный размер ряда. Когда дело касается рядов, контент меняет всё. Вот вам пример того, что случается, когда ваш контент переполнит указанный размер ряда:

ciu-grid

Контент переполняет указанные размеры ряда

Мы создали два ряда по 250px, если контент внутри ряда переполнит его, он прорвется через границу своего ряда и начнёт перекрывать контент ряда под ним. Не совсем желаемый результат.

Установка минимальных размеров с сохранением гибкости

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

.grid {
    grid-template-rows: minmax(250px, auto) minmax(250px, auto);
}

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

Демо создания гибких рядов с помощью минимальных размеров

ciu-grid

Использование grid-column-start и ключевого слова span для создания сложных гридов. Фото из Unsplash

Создание более сложных гридов

Мы можем перейти к созданию более сложных гридов, заставляя грид-элементы занимать несколько полос в гриде. В колонке этого можно добиться с помощью grid-column-start и grid-column-end, или выразить это в этой сокращённой записи:

grid-column: 1 / 3;

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

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

.span-column-3 {
    grid-column-start: span 3;
}

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

Демо сложных гридов при помощи span

Планирование раскладки с помощью span

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

ciu-grid

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

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

Гибкие гриды без медиавыражений

Хотя некоторые из предыдущих примеров могли реагировать на изменения доступного пространства, ни один из них не предназначался специально для этих целей. У грида есть две крайне мощные фичи для управления свободным местом. Эти фичи называются ‘auto-fit’ и ‘auto-fill’, и используются внутри функции repeat, обычно с функцией minmax, как здесь:

grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));

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

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

ciu-grid

Пример: После auto-fill могут оставаться пустые места, тогда как auto-fit будет схлопывать пустые места до 0px.

Auto-fit ведёт себя почти как auto-fill, за исключением того, что любая пустая область будет схлопываться и растягивать элементы в этой строке – напоминая поведение флексбоксов, когда по мере уменьшения доступного пространства колонки схлопываются.

ciu-grid

Пример с grid-auto-fit

Раскладка, основанная на медиавыражениях, привязана к области просмотра, это не подходит для изолированных модулей – компоненты должны адаптироваться к тому пространству, которое им доступно. Поэтому как это будет выглядеть на практике?

ciu-grid

Практический пример grid auto-fit

Демо с Grid Auto-fit

Это только цветочки

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

Самый важный шаг на сегодня – просто использовать Grid по максимуму, знакомясь с ним и создавая более продвинутые раскладки. Grid – это практически терра инкогнита веба, и как только мы лучше познаем его возможности и начнём сочетать его с другими фичами, мы сможем создавать более интересные и гибкие раскладки без лишних стилей, и сможем забыть про отдельные фреймворки.

Если стало интересно и появилось желание продолжить знакомство с CSS Grid, поиграйтесь с GridByExample Рэйчел Эндрю, где исследуется каждый аспект CSS Grid в демо-примерах с объяснениями.

P.S. Это тоже может быть интересно:

9 Комментарии
  1. NMitra

    Есть идеи как сделать что-то похожее https://yandex.ru/images/search?text=%D1%80%D0%B5%D0%B4%D0%BA%D0%B8%D0%B5%20%D0%BF%D1%82%D0%B8%D1%86%D1%8B&nl=1 По высоте картинки приблизительно одинаковые, ширина по возможности пропорционально подстраивается

    1. SelenIT

      Верно ли я понял, что в каждой строке картинки выстраиваются по-своему, вертикальных связей между ними нет? Если да, то это задача скорее для флексбоксов, чем для гридов. Возможно, в качестве отправной точки подойдет этот пример Дадли Стори? По-моему, при большом количестве маленьких картинок получается достаточно похоже.

      1. NMitra

        Тут ширина одинаковая, а там они более менее пропорциональные. По-вертикали, по-видимому, есть максимальное значение, чтобы в ширину укладывались.

        1. SelenIT

          У того же Дадли есть развитие идеи, где элементам задаются значения flex, пропорциональные отношению ширины к высоте картинок. В примере он делает это на JS, но пишет, что можно делать это и на сервере, на PHP или чем-то вроде. Немножко хак, конечно… но пока ничего лучше не придумывается(

    2. Cox

      Такая галерея не реализуется с помощью Grid Layout, делается либо через inline-block, либо через flexbox, в обоих случаях скорее всего будут проблемы с правым краем (будет «лес»)

  2. Eugene

    Выглядит не очень просто в освоении.
    А не в курсе, есть ли в разработке что-то вроде масонри раскладке без js? (колонки не устраивают)

    1. SelenIT

      Просто много всего непривычного:).

      Насчет масонри на чистом CSS — насколько я в курсе, пока, к сожалению, нет. Есть хак на гридах с очень маленькой высотой ряда и auto-flow dense, но для него нужно заранее знать высоту элементов и руками/препроцессором проставлять им соответствующий span для рядов, к тому же он быстро упирается в браузерные лимиты. Возможно, в Grid Layout Level 2 это исправят и такой вариант станет рабочим решением, но раньше вряд ли. Но такой фичереквест в репозитории CSS-спецификаций есть.

  3. Denai

    Интересно когда у этого дела процент поддерживающих браузеров за 60% хотя бы перевалит. Сейчас все ринулись восхищаться этой штукой, но до реальной возможности применения ещё ждать и ждать

    1. SelenIT

      За 60% должно перевалить где-то в середине лета. У Фокса по caniuse уже сейчас 52-я версия отхватила половину, у Хрома основная масса пока 56-я, но 55-й (вышла в начале декабря) уже меньше процента, так что старые версии уходят в историю за 4-5 месяцев. У IE вместе с Edge от силы процентов 5, погоды они не делают, на самый крайний случай и их старая реализация на что-нибудь сгодится.

      Можно уже сейчас добавлять штуку в порядке прогрессивного улучшения через @supports, для лучшей надежности, адаптивности управляемости и т.п. существующих дизайнов (как делал Эрик Мейер со своим блогом). А еще использовать для быстрого прототипирования и экспериментального определения оптимального расположения компонентов на странице (а для продакшна прибить их к этим местам дедовскими «железобетонными» методами:).

Добавить комментарий для Eugene Отменить ответ

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

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