Знакомство с CSS Grid Layout
Перевод статьи Getting to know CSS Grid Layout с сайта cm.engineering для CSS-live.ru, автор — Крис Райт
Фотографии из 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 определяет колонки, возьмём эту раскладку:
Двухколоночная раскладка с интервалами с использованием 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
, и раскладка в итоге будет с горизонтальным скроллбаром.
Горизонтальный скроллбар от использования грид-интервала с единицами измерения относительно вьюпорта
Для исправления этого переполнения места нужно немного другое решение. Вводим единицу доли (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, в отличие от других, растянет элемент от начала и до конца его полосы.
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
, что позволяет создать негативное пространство внутри грида.
Негативное пространство с использованием grid-template-columns
и grid-column-start
Один из способов создать негативное пространство — задать грид-элементу номер колонки больше его собственного порядкового номера, оставив изначально предназначенное ему место пустым и сдвинув элемент по горизонтали в новую колонку.
Перемещение первого элемента с помощью 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;
, то алгоритм постарается найти следующую свободную ячейку во второй колонке на следующих рядах.
Мертвая зона для контента создана при помощи grid-template-columns
и grid-column-start
Грид-полоса будет пропускать колонки, пока не найдёт следующую пустую вторую колонку. Это даёт возможность создать «мёртвую зону» внутри грида, где не будет назначено никаких грид-полос с контентом.
Демо «мёртвой зоны» для контента
Создание рядов
Что, если вы захотите разбить макет на четыре части? Всё, что мы рассмотрели до сих пор про колонки, применимо и к рядам.
.grid { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 250px 250px; }
Создание грид-раскладки при помощи grid-template-columns
и grid-template-rows
Проблема в этом примере — это идеальный сценарий. Контент каждого грид-элемента достаточно мал, чтобы никогда не превысить указанный размер ряда. Когда дело касается рядов, контент меняет всё. Вот вам пример того, что случается, когда ваш контент переполнит указанный размер ряда:
Контент переполняет указанные размеры ряда
Мы создали два ряда по 250px, если контент внутри ряда переполнит его, он прорвется через границу своего ряда и начнёт перекрывать контент ряда под ним. Не совсем желаемый результат.
Установка минимальных размеров с сохранением гибкости
В этом сценарии нам нужна возможность установить минимальный размер, но чтобы он мог подстраиваться по контенту, этого можно добиться с помощью ключевого слова minmax
, которое мы использовали в примере с устаревшим синтаксисом.
.grid { grid-template-rows: minmax(250px, auto) minmax(250px, auto); }
Теперь, после знакомства с основами, нужно создать ряды с контентом, можно начать выстраивать более сложные гриды, горизонтальные и вертикальные.
Демо создания гибких рядов с помощью минимальных размеров
Использование 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
Можно планировать раскладки множественных полос, разбивая раскладку до наименьшей единицы в раскладке грида. В этом примере наименьшая единица выделена:
Наименьший грид-элемент используется для грид-колонок, поэтому можно выстраивать более крупные элементы с помощью span
Выстраивая всё вокруг наименьшей единицы, можно гибко применять классы со span для создания интересных раскладок, а поскольку значения span суммируются, можно объединять ячейки и по рядам, и по колонкам, для создания в гриде иерархии.
Гибкие гриды без медиавыражений
Хотя некоторые из предыдущих примеров могли реагировать на изменения доступного пространства, ни один из них не предназначался специально для этих целей. У грида есть две крайне мощные фичи для управления свободным местом. Эти фичи называются ‘auto-fit’
и ‘auto-fill’
, и используются внутри функции repeat
, обычно с функцией minmax
, как здесь:
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
Они заменяют собой числа в repeat, и вычисляют максимально возможное число колонок в контейнере. Основное различие между ними – это то, как они справляются с лишним пространством в строке.
Auto-fill
пытается поместить наибольшее количество повторяющихся элементов в колонку, сколько их может уместиться без переполнения. Когда места для добавления другого элемента не хватает, следующий элемент будет размещён на следующей строке, а это место, которое он не смог заполнить, останется пустым.
Пример: После auto-fill
могут оставаться пустые места, тогда как auto-fit
будет схлопывать пустые места до 0px
.
Auto-fit
ведёт себя почти как auto-fill
, за исключением того, что любая пустая область будет схлопываться и растягивать элементы в этой строке – напоминая поведение флексбоксов, когда по мере уменьшения доступного пространства колонки схлопываются.
Пример с grid-auto-fit
Раскладка, основанная на медиавыражениях, привязана к области просмотра, это не подходит для изолированных модулей – компоненты должны адаптироваться к тому пространству, которое им доступно. Поэтому как это будет выглядеть на практике?
Практический пример grid auto-fit
Это только цветочки
Мы пережили почти пятнадцать лет безраздельного господства флоатов в раскладках, успели изучить их до мелочей, a CSS Grid — еще совсем новичок, и еще так много предстоит экспериментировать и изучать.
Самый важный шаг на сегодня – просто использовать Grid по максимуму, знакомясь с ним и создавая более продвинутые раскладки. Grid – это практически терра инкогнита веба, и как только мы лучше познаем его возможности и начнём сочетать его с другими фичами, мы сможем создавать более интересные и гибкие раскладки без лишних стилей, и сможем забыть про отдельные фреймворки.
Если стало интересно и появилось желание продолжить знакомство с CSS Grid, поиграйтесь с GridByExample Рэйчел Эндрю, где исследуется каждый аспект CSS Grid в демо-примерах с объяснениями.
P.S. Это тоже может быть интересно:
Есть идеи как сделать что-то похожее 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 По высоте картинки приблизительно одинаковые, ширина по возможности пропорционально подстраивается
Верно ли я понял, что в каждой строке картинки выстраиваются по-своему, вертикальных связей между ними нет? Если да, то это задача скорее для флексбоксов, чем для гридов. Возможно, в качестве отправной точки подойдет этот пример Дадли Стори? По-моему, при большом количестве маленьких картинок получается достаточно похоже.
Тут ширина одинаковая, а там они более менее пропорциональные. По-вертикали, по-видимому, есть максимальное значение, чтобы в ширину укладывались.
У того же Дадли есть развитие идеи, где элементам задаются значения flex, пропорциональные отношению ширины к высоте картинок. В примере он делает это на JS, но пишет, что можно делать это и на сервере, на PHP или чем-то вроде. Немножко хак, конечно… но пока ничего лучше не придумывается(
Такая галерея не реализуется с помощью Grid Layout, делается либо через inline-block, либо через flexbox, в обоих случаях скорее всего будут проблемы с правым краем (будет «лес»)
Выглядит не очень просто в освоении.
А не в курсе, есть ли в разработке что-то вроде масонри раскладке без js? (колонки не устраивают)
Просто много всего непривычного:).
Насчет масонри на чистом CSS — насколько я в курсе, пока, к сожалению, нет. Есть хак на гридах с очень маленькой высотой ряда и
auto-flow dense
, но для него нужно заранее знать высоту элементов и руками/препроцессором проставлять им соответствующийspan
для рядов, к тому же он быстро упирается в браузерные лимиты. Возможно, в Grid Layout Level 2 это исправят и такой вариант станет рабочим решением, но раньше вряд ли. Но такой фичереквест в репозитории CSS-спецификаций есть.Интересно когда у этого дела процент поддерживающих браузеров за 60% хотя бы перевалит. Сейчас все ринулись восхищаться этой штукой, но до реальной возможности применения ещё ждать и ждать
За 60% должно перевалить где-то в середине лета. У Фокса по caniuse уже сейчас 52-я версия отхватила половину, у Хрома основная масса пока 56-я, но 55-й (вышла в начале декабря) уже меньше процента, так что старые версии уходят в историю за 4-5 месяцев. У IE вместе с Edge от силы процентов 5, погоды они не делают, на самый крайний случай и их старая реализация на что-нибудь сгодится.
Можно уже сейчас добавлять штуку в порядке прогрессивного улучшения через @supports, для лучшей надежности, адаптивности управляемости и т.п. существующих дизайнов (как делал Эрик Мейер со своим блогом). А еще использовать для быстрого прототипирования и экспериментального определения оптимального расположения компонентов на странице (а для продакшна прибить их к этим местам дедовскими «железобетонными» методами:).
Неплохая статья для начинающих, хорошо иллюстрированная. Если б я прочитал сначала её, то, наверное, Ваша бы большая обзорная статья воспринималась бы легче…
А, да, хотел сказать Максиму, переводившему статью — негативное пространство, возможно и известное словосочетание в CSS, но лично я, например, слышал про него лишь краем уха и о его значении приходится всё же догадываться, да и вообще как-то режет ухо… Может заменить на просто пустое пространство?…
Я тоже, признаюсь, впервые увидел это словосочетание в этой статье, но беглый поиск показал, что это вполне устоявшийся термин в дизайне (в т.ч. веб-). Насколько я понимаю, не всякое пустое пространство — негативное, так что менять так «в лоб» не рискнул бы. Но надо бы у дизайнеров поспрашивать…
Ну вот и я не припомню, где я это слышал, но вроде, где-то слышал :-) Если это устоявшийся термин (пусть и в узких кругах), то, наверное, лучше, сразу после его употребления в статье, дать ему определение на чистом русском %) Чтоб читали могли понимать, а не додумывать…
читатели, сорри
Топ гайд. Спасибо, всё по полочкам и понятно! Моё время сэкономлено. :)