Большая статья про гриды (CSS Grid Layout)

Мы давно изучали CSS-гриды, сами и вместе с зарубежными авторами. Тогда же возникла мысль оформить результат в виде подробного руководства по ним, вроде этого по флексбоксам. Это оказалось не так-то просто: стандарт большой, вводит множество новых понятий, к тому же эти понятия переплетены друг с другом, совсем как полосы самих гридов (как показать грид-области без привязанных к ним грид-элементов, и наоборот?). Поэтому работа над статьей, скажем прямо, несколько затянулась:) Но теперь, когда грид-раскладка уже поддерживается почти повсеместно (Firefox 52+, Chrome 57+, Opera 44+, Safari 10.1+/iOS 10.3+ Safari, Яндекс-Браузер 17+, а также в Android WebView), мы рады представить вам результат трудов. Надеемся, он поможет разобраться в горах новых возможностей. Это не «полное руководство» (полностью описать все возможности CSS Grid в одной статье просто нереально!), но мы постарались упомянуть некоторые важные моменты, упущенные многими из «полных руководств». Любые дополнения и уточнения приветствуются!

Краткое содержание:

  1. Основа и терминология
  2. Грид-контейнер и его свойства
  3. Грид-элементы и их свойства
  4. Песочницы

Основа и терминология

Грид — это двумерная (в отличие от от одномерных флексбоксов) сетка. Как табличная, только виртуальная, не связанная с разметкой. Состоит из следующих элементов:

  • Грид-контейнер — элемент, в котором строится сетка.
  • Грид-элементы — элементы, размещаемые по сетке. Важно: они должны быть непосредственными потомками грид-контейнера (как и во флексбоксах флекс-элементы должны быть непосредственными потомками флекс-контейнера).
  • Грид-линии — невидимые вертикальные и горизонтальные линии, разделяющие грид на ячейки и формирующие его структуру. Грид-линии автоматически нумеруются, а также им можно задавать имена. К грид-линиям можно привязывать грид-элементы — и по номерам, и по именам, как удобнее.
  • Грид-полосы — то, что ограничено парой соседних грид-линий. Вертикальные грид-полосы — это колонки грида (аналог столбцов таблицы), горизонтальные — ряды (аналог строк).
  • Грид-ячейки — то, что получается на пересечении двух грид-полос (колонки и ряда). Аналог ячейки таблицы.
  • Грид-области — прямоугольники из M×N смежных грид-ячеек (1×1 и больше). Каждая грид-область ограничена двумя парами грид-линий (парой вертикальных и парой горизонтальных). В них и размещаются грид-элементы. Грид-областям тоже можно задавать имена.
  • Грид-интервалы — пустые пространства (отступы) между соседними грид-полосами. Аналог border-spacing в таблице.

See the Pen LypJVK by Ilya Streltsyn (@SelenIT) on CodePen.

Ограничение, что грид-элементы должны быть непосредственными потомками грид-контейнера, в будущем снимут подсетки (subgrids). Пока их нет, его можно частично обойти с помощью display:contents или эмулировать CSS-переменными.

Визуализировать грид-линии умеет отладчик Firefox (иконка в виде решетки, указанная стрелкой):

скриншот отладчика Firefox с включенным грид-инспектором

Примечание: простой текст (всё, кроме пробелов, табов и переводов строк), оказавшийся непосредственно в грид-контейнере (между тегами), оборачивается в анонимные грид-элементы. Подобный эффект нам уже знаком по флексбоксам.

Грид-контейнер и его свойства

Создание грид-контейнера

Задаем ему display:grid. Или display: inline-grid, разница с обычным grid такая же, как у inline-block с block. Ниже наглядный пример:

See the Pen Kzvrrw by Ilya Streltsyn (@SelenIT) on CodePen.

Разметка колонок и рядов

Используем свойства grid-template-rows и grid-template-columns.

Значения этих свойств состоят из перечисления размеров грид-полос (через пробел). До и после размера полосы можно указывать имена грид-линий, в квадратных скобках. Чтобы не писать одно и то же по нескольку раз, можно сократить запись функцией repeat(). Подробности ниже.

Размеры грид-полос

Размер каждой грид-полосы (ширину колонки/высоту ряда) можно задавать:

  • В любых CSS-единицах длины, абсолютных (pt, mm, px…) или относительных (em, rem, vw, vh…).
  • В процентах (от доступной ширины или указанной высоты грид-контейнера — как для блоков).
  • В единицах fr (от fraction — часть). Свободное место распределяется между такими полосами пропорционально количеству fr. Как на flex-grow у флексбоксов (при нулевом flex-basis).
  • Ключевым словом max-content — наибольший размер контента. Для текста это длина самой большой строки без переносов.
  • Ключевым словом min-content — наименьший возможный размер контента. Для текста это ширина самого длинного неразрываемого фрагмента или слова.
  • Функцией minmax(<минимум>, <максимум>). Задает минимум, до которого можно ужимать полосу, и максимум, на который она может растянуться, если хватит места (аналог min/max-width или min/max-height в одной записи). Минимум и максимум можно задавать всеми вышеперечисленными способами. Обычно минимум делают фиксированным, а максимум — гибким, напр. minmax(200px, 30%) или minmax(min-content, 2fr). Подробнее о ней здесь.
  • Ключевым словом auto — размер грид-полосы подстраивается под размеры ее грид-элементов, так, чтобы самый большой из них уместился впритык. Не дает грид-полосе ужиматься меньше min-width самого широкого грид-элемента (для колонки) или min-height самого высокого (для ряда) и растягиваться больше, чем max-content. Но есть важный нюанс: грид-полосы с размером auto могут растягиваться при *-content: stretch (и отсутствии других полос с размерами во fr).
  • Функцией fit-content() с максимальным размером в качестве параметра. Если контент не больше этого размера, ведет себя как auto, если больше — этот параметр становится размером полосы. Что делать, если указан размер меньше самого длинного слова (т.е. min-content), браузеры пока не определились.

Примечание: на момент публикации статьи min-content и max-content в Safari требуют префикса -webkit-. Именно для значения, не для свойства. А вот в Firefox они работают без префикса (хотя MDN и caniuse опять это скрывают!).

Пример действия разных значений:

.grid {
    display: grid;
    grid-template-columns: 50px 20% min-content max-content 1fr 2fr auto;
    grid-template-rows: auto minmax(50px, 50vh) 4em;
    /* другие свойства... */
}

See the Pen ZWJmzg by Ilya Streltsyn (@SelenIT) on CodePen.

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

Также обратите внимание, что при увеличении размеров контейнера ряд с размером auto начинает растягиваться по высоте. А колонка с размером auto не растягивается, потому что есть другие колонки с гибким размером (fr). Если бы их не было, колонка с auto бы тоже растягивалась.

Имена грид-линий

Удобны для привязки грид-элементов к ним. Пишутся в квадратных скобках перед или после размера соотв. полосы. У одной грид-линии может быть много имен. Имена грид-линий могут быть практически любыми — как имена классов. Допустимы русские буквы и др. символы юникода, даже эмодзи (но чувствуйте меру:).

.grid {
    /* другие свойства... */
    grid-template-rows: [header-top] auto [header-bottom  main-top] 1fr [main-bottom];
}

У каждой грид-линии, именованной или нет, есть также два номера: с начала грида, положительное число (1, 2, 3, …), и с конца грида, отрицательное число (-1, −2, −3, …). Привязывать грид-элементы к ним можно как по именам, так и по любому из этих номеров.

Больше примеров и подробностей — в отдельной статье.

У имен грид-линий, оканчивающихся на -start и -end, есть своя «особая магия»: они косвенно создают именованные грид-области (см. подробности в разделе о них).

Функция repeat()

Общий синтаксис: repeat(<сколько раз повторять>, <что повторять>). У нее два основных варианта:

  • Повторение любой последовательности грид-полос указанное число раз.

  • Повторение одной грид-полосы до заполнения грид-контейнера по соответствующей оси. Количество повторов задается ключевым словом auto-fill либо auto-fit:

    • auto-fill повторяет грид-полосу столько раз, сколько вместится в размер грид-контейнера. Если у грид-контейнера задан максимальный размер, грид-полоса повторяется столько раз, сколько вместится без переполнения (если без переполнения никак не вмещается — то один раз). Если у грид-контейнера задан только минимальный размер, грид-полоса повторяется столько раз, сколько достаточно для превышения этого минимума. Хотя бы одно повторение будет в любом случае.
    • auto-fit — то же самое, но после размещения грид-элементов оставшиеся пустыми грид-полосы сжимаются до нуля, а интервалы между ними объединяются в один интервал. Т.е. пустые полосы как будто выбрасываются. Если полос вмещается пять, но элемента только три — в итоге и полос будет только три.

Есть несколько важных ограничений:

  1. Нельзя вкладывать repeat в другой repeat.
  2. С auto-fill и auto-fit можно повторять только конкретные размеры. Явно заданные (в единицах длины или процентах) или хотя бы явно ограниченные с одной стороны, но не *-content, не fr и не auto.
    • repeat(auto-fill, 100px), repeat(auto-fit, minmax(100px, 1fr)) — можно
    • repeat(auto-fill, auto), repeat(auto-fit, 1fr) — нельзя
  3. repeat c auto-fill или auto-fit может быть только один на одно измерение грида (grid-template-rows или grid-template-columns).
    • grid-template-columns: repeat(3, 50px 5%) repeat(auto-fill, 100px) repeat(4, 80px) — можно
    • grid-template-columns: repeat(auto-fill, 50px) repeat(2, 100px) repeat(auto-fit, 80px) — нельзя (2 repeat с неизвестным количеством повторений)
  4. Если есть repeat c auto-fill или auto-fit, то в соседних с ним repeat тоже можно повторять только конкретные размеры.
    • grid-template-columns: repeat(2, 2fr) repeat(4, 1fr) — можно (нет auto-fill/auto-fit)
    • grid-template-columns: repeat(auto-fill, 100px) repeat(4, 1fr) — нельзя (в одном repeat есть auto-fill, а в другом repeat повторяется заранее неизвестная ширина).

С auto-fill легко решается старая задача выравнивания одинаковых блоков по резиновой сетке.

Разметка грид-областей

Используем свойство grid-template-areas (известное как «разметка страницы ASCII-графикой»). Каждая строка значения задает имена ячейкам соответствующего ряда, повторение одного и того же имени указывает, что грид-область с таким именем охватывает несколько ячеек. Имена грид-областей, как и грид-линий, могут быть любыми (хоть эмодзи), кроме ключевых слов CSS. Неиспользуемые (пропускаемые) ячейки обозначаются точкой:

#grid {
    display: grid;
    grid-template-areas: "head head"
                         "nav  main"
                         "foot .   ";
}

В эти области можно напрямую помещать грид-элементы.

Несколько пробелов между именами считаются за один, поэтому можно добавлять их сколько угодно для красоты и наглядности. А можно не добавлять: grid-template-areas: "head head" "nav main" "foot ."; — то же самое, что пример выше.

При создании грид-области с именем что-то ограничивающие ее грид-линии получают имена что-то-start и что-то-end. И наоборот: пара параллельных грид-линий с именами что-то-start и что-то-end автоматически создает между собой именованную грид-область с именем что-то.

Можно указывать одновременно и размеры, и grid-template-areas:

.grid {
    display: grid;
    /* другие свойства: размеры и т.п. */
  
    grid-template-columns: 2fr 1fr;
    grid-template-rows: [header-top] auto [header-bottom  main-top] 1fr [main-bottom];

    grid-template-areas: "banner    banner"
                         "container menu";
}

See the Pen GmJVPO by Ilya Streltsyn (@SelenIT) on CodePen.

Сокращенная запись для колонок, рядов и областей: grid-template

Более короткий (но менее понятный) способ указывать грид-области и размеры грид-полос одновременно: свойство grid-template.

Вот предыдущий пример, переписанный на grid-template и отформатированный для максимальной наглядности (посмотреть вживую):

.grid {
    display: grid;
    /* другие свойства: размеры и т.п. */
  
    grid-template:
    [header-top]                              /* верхняя горизонтальная грид-линия */
                "banner     banner"     auto  /* структура первого ряда и его высота */
    [header-bottom main-top]                  /* средняя горизонтальная грид-линия */
                "container  menu"       1fr   /* структура второго ряда и его высота */
    [main-bottom]                             /* нижняя горизонтальная грид-линия */
              /                               /* конец описания рядов */
                 2fr        1fr;              /* ширины грид-колонок */
  }
}

Важно: в такой записи (сочетание «ASCII-графики» с размерами) нельзя использовать repeat(), потому что перечисления рядов/колонок должны визуально соответствовать именам областей в «ASCII-графике».

Неявный грид (автоматические ряды и колонки)

При попытке разместить грид-элемент за пределами явных грид-полос автоматически генерируются неявные полосы. Их размерами можно управлять с помощью grid-auto-rows и grid-auto-columns. По умолчанию они auto (грубо говоря, по контенту, см. «Размеры грид-полос»).

Неявные полосы могут генерироваться как перед явными, так и после них. Соответствующие грид-линии продолжают нумерацию: после грида — положительную, перед гридом — отрицательную. Чем-то похоже на то, как добавляются дополнительные линейки для нот, оказавшихся выше или ниже основных пяти линеек. Вот пример грида с 5 явными линиями для рядов (т.е. 4 рядами) и несколькими «нотами», привязанными (с помощью grid-row-start, о нем чуть ниже) к линиям как в пределах явного грида, так и за его пределами:

See the Pen OpKzxK by Ilya Streltsyn (@SelenIT) on CodePen.

Важный момент: грид-линия № 1 не всегда совпадает с началом грид-контейнера! Браузер пытается уместить в грид-контейнер весь грид, не только явные полосы. Поскольку по умолчанию грид-полосы выравниваются по началу грид-контейнера, неявные грид-полосы будут выталкивать явные вниз (для рядов) или вправо (для колонок, для текста слева направо). В этом примере, благодаря тому, что общая ширина неявных полос сверху и снизу одинакова, можно подогнать явные ряды к границам грид-контейнера, отцентрировав весь грид по вертикали (с помощью align-content: center). Можете поменять align-content у грид-контейнера и увидеть эту разницу (контейнер при наведении подсвечивается). Но такое везение бывает не всегда!

Для привычного нам размещения «текст слева направо, строчки сверху вниз», если элемент оказывается за пределами колонок грида — чаще всего это ошибка (хотя может быть и дизайнерским приемом). А вот создавать ряды автоматически по мере необходимости, продолжая грид вниз, бывает нужно сплошь и рядом.

Алгоритм авторазмещения: направление и «плотность упаковки» элементов

Еще одна аналогия с флексбоксами: у флекс-контейнера есть свойство flex-flow, указывающее, как пойдут элементы в нем — по вертикали или по горизонтали. У грид-контейнера есть очень похожее: grid-auto-flow. И первая часть значения та же самая: row либо column. Т.е. обходить ячейки по строкам (по умолчанию слева направо) либо по столбцам (сверху вниз).

У второй, необязательной, части значения аналога нет. Ключевое слово dense указывает, что надо «запихивать» элементы в грид как можно плотнее, по возможности заполняя каждую ячейку. По умолчанию, без dense, алгоритм авторазмещения «высматривает» подходящее для очередного элемента место только «впереди», не оглядываясь на уже пройденные строки/столбцы.

Примеры различия «с dense и без» есть в одной из первых статей о CSS-гридах в Рунете на css-live, а также в недавней статье. Еще немного подробностей будет ниже, в разделе про сами грид-элементы. Ну и совсем простенький наглядный пример всех 4 вариантов значений:

See the Pen LLxMjX by Ilya Streltsyn (@SelenIT) on CodePen.

Одно свойство, чтоб править всеми: grid

Способ указывать и грид области, и размеры всех грид-полос — явных и неявных, и алгоритм авторазмещения, всё сразу. Поэтому еще более запутанный, чем grid-template. И может принимать те же значения, что и grid-template (тогда неявные полосы и алгоритм авторазмещения будут по умолчанию, auto и row соответственно). Но очень удобен в простых случаях. Например, просто и быстро поделить контейнер на 4 колонки и 3 ряда:

grid: repeat(4, 1fr) / repeat(3, 1fr); /* ...и готово! */

Но вообще это свойство заслуживает отдельной статьи. Мы постараемся разобрать его в ближайшее время.

Промежутки между ячейками (грид-интервалы)

Делаются специальными свойствами grid-row-gap и grid-column-gap, либо сокращенным свойством grid-gap:

    grid-row-gap: 5px;
    grid-column-gap: 10%;
    /* или, короче */
    grid-gap: 5px 10%;

Если задать grid-gap одно значение, отступы между рядами и колонками будут равными:

    grid-gap: 5px; /* то же, что и grid-gap: 5px 5px; */

В общем, почти как border-spacing для таблиц. Только бывает еще и в процентах. И добавляется только между полосами, снаружи крайних полос не добавляется.

Неинтуитивный момент: начало и конец грид-интервала считаются одной и той же грид-линией (этакая толстая линия, во весь интервал толщиной:). Можете еще раз посмотреть на это в первом примере (про терминологию).

Выравнивание и центрирование грид-полос в грид-контейнере

Если грид-полосы заполняют грид-контейнер не целиком (т.е. сумма их размеров меньше размера грид-контейнера и нет полос с размерами во fr), оставшееся свободное место может быть перед ними, после них, вокруг них и между ними. Делается свойствами justify-content/align-content. Общий принцип тот же, что у выравнивания строк в многострочном флекс-контейнере. Подробнее об этих свойствах — в отдельной статье.

Можно посмотреть это на живом примере:

See the Pen dWYjKr by Ilya Streltsyn (@SelenIT) on CodePen.

При space-between, space-around и новом значении space-evenly фактически растягиваются грид-интервалы (это уточнение появилось в спецификации благодаря статье на css-live.ru:).

Грид-элементы и их свойства

О способах размещения грид-элементов — есть отдельная подробная статья одного из авторов реализации гридов в Chrome и Safari, с прекрасными иллюстрациями. Добавить к ней что-то новое сложно. Так что просто кратко перечислим, какие возможности есть.

Привязка грид-элемента к грид-линиям

Используем 4 свойства:

  • grid-row-start
  • grid-row-end
  • grid-column-start
  • grid-column-end

По умолчанию у них значение auto (находить место для элементов автоматически, об этом ниже). Можно привязывать элементы к грид-линиям по номеру (любому из двух — положительному, с начала, или отрицательному, с конца), по имени, по имени и номеру (если одноименных линий несколько, например, при repeat). Бегло рассмотрим все три способа.

По номеру

Например, grid-row-start: 3; grid-row-end: 5 — поставить элемент между 3-й и 5-й линиями рядов (т.е. он будет занимать два ряда, 3-й и 4-й). То же самое — grid-row-start: 3; grid-row-end: span 2 (от третьей линии до второй по счету линии после начальной). Или grid-row-start: span 2; grid-row-end: 5 (от второй по счету линии перед конечной до пятой линии).

Еще пример: grid-column-start: -5; grid-column-end: -2 — поставить элемент между 5-й и 2-й линиями колонок с конца (т.е. он займет 3 колонки, 4-ю от конца явного грида, 3-ю от конца и предпоследнюю). Это то же самое, что grid-column-start: -2; grid-column-end: -5 (если начало позже конца, они меняются местами). А вот grid-column-start: -2; grid-column-end: span -3 сделать нельзя: span может быть только положительным. Записать «от третьей линии перед второй с конца до второй с конца» можно только так: grid-column-start: span 3; grid-column-end: -2. А растянуть элемент на всю ширину грида, от начала до конца, можно так: grid-column-start: 1; grid-column-end: -1.

Это работает и с линиями неявного грида, только номер у них лишь один (у добавочных линий перед гридом — только отрицательный, у добавочных после — только положительный).

Примечание: во многих руководствах (и даже в нескольких местах спецификации!) говорится, что span указывает, сколько грид-полос занимает элемент. Для привязки по номерам линий это верно (и может быть даже нагляднее), но с именованными линиями, как вы увидите чуть ниже, это уже не работает. На мой взгляд, надежнее всегда считать именно линии, с ними точно не запутаетесь.

По имени

Например, grid-row-start: header; grid-row-end: abracadabra. И даже grid-row-start: 👸; grid-row-end: 👠 (кому удобнее обозначать предметы «современными иероглифами», идея из статьи Юны Кравец). Лично меня больше запутывают не эмодзи, а названия, совпадающие с ключевыми словами CSS (когда я после долгого перерыва стал заново разбирать статью Мануэля, до меня не сразу дошло, что grid-row-start: top и grid-column-end: right — не какие-то специальные режимы, а просто названия линий:). Но по стандарту называть линии можно как угодно, так что делайте, как удобнее вам и вашим коллегам!

Запись grid-row-end: span sidebar означает «охватить ряды вплоть до линии с именем sidebar» (если таких линий несколько — то до ближайшей из них, см. ниже).

По имени и номеру

При повторяющейся структуре грида может быть несколько линий с одинаковым именем (пример этого тоже был в раннем цикле статей про CSS Grid). Чтобы привязаться к одной конкретной из них, указываем и имя, и номер: grid-column-start: content 3 — началом элемента будет 3-я по счету линия с именем content. Чуть ниже вы можете увидеть это в деле в сокращенной записи.

Сокращенные свойства

Пары grid-*-start и grid-*-end можно писать сокращенно — как grid-row и grid-column соответственно. Значение записывается через слеш (до слеша *-start, после него *-end):

grid-row: 2 / 4; // от 2-й до 4-й линий, т.е. 2-й и 3-й ряды
grid-column: span 3 / -2; // 3 колонки до предпоследней включительно
grid-column: menu-end / span item-column 2; // от конца области menu до 2-й линии с именем "item-column"

Если указано только одно значение, оно считается начальным, а конечное обычно подставляется по умолчанию (span 1 — до следующей линии после указанной, т.е. занять 1 полосу). Но если в структуре грида есть линии что-то-start и что-то-end (или, что то же самое, есть грид-область что-то), то включается «магия» этих имен: grid-row: что-то превращается в grid-row: что-то-start / что-то-end (для grid-column аналогично). Не очень очевидно, но очень удобно! В примере ниже banner и menu — «волшебные» имена, а content (их 3 шт.) — обычные (хотя геометрически первая из них совпадает с banner-start):

See the Pen jwVNMQ by Ilya Streltsyn (@SelenIT) on CodePen.

Примечание: на данный момент в Chrome баг, и grid-column: content интерпретируется там как grid-column: content 3, a не grid-column: content 1, как должно быть по спецификации. Firefox отображает верно. Пока баг не исправят, всегда указывайте номер конкретной линии явно!

Можно написать еще короче, сократив обе пары сразу: grid-area. У него может быть от 1 до 4 значений, тоже через слеш.

Если есть все 4 значения, их порядок такой: grid-row-start / grid-column-start / grid-row-end / grid-column-end. Т.е., для текста слева направа — против часовой стрелки (в отличие от сокращенных записей для margin, paddingborder-* и большинства прочих свойств с 4 сторонами)! Пожалуй, чтобы не запутаться, лучше запоминать порядок не «верх/лево/низ/право», а именно как начала и концы ряда и колонки соответственно.

Если части grid-row-end/grid-column-end пропущены, для них работает та же логика, что для grid-row и grid-column: если значение для соотв. начальной линии — «волшебное» имя, оно разворачивается в пару что-то-start и что-то-end, если нет — для конечной линии подставляется auto. Если же указано всего одно значение что-то, то если грид-область с таким именем есть — оно разворачивается в четверку свойств со значениями что-то-start и что-то-end, привязывающих элемент к грид-области с таким именем. А если нет — все 3 недостающие части становятся auto.

Размещение грид-элемента в грид-области

Здесь и пригодится grid-area с одним значением — именем грид-области. Неважно, присвоено ей это имя прямо (в свойстве grid-template-areas для грид-контейнера)…

  #grid0 {
      display: grid;
      grid-template-areas: "head head"
                           "nav  main"
                           "foot .   ";
  }
  #grid0 > header { grid-area: head; }
  #grid0 > nav    { grid-area: nav; }
  #grid0 > main   { grid-area: main; }
  #grid0 > footer { grid-area: foot; }

…или косвенно (парой вертикальных и парой горизонтальных «волшебных» грид-линий с окончаниями -start/-end):

  #grid1 {
      display: grid;
      grid-template-columns: [head-start nav-start foot-start] 2fr [nav-end foot-end main-start] 1fr [head-end main-end];
      grid-template-rows: [head-start] auto [head-end  nav-start main-start] 1fr [nav-end main-end foot-start] auto [foot-end];
  }
  #grid1 > header { grid-area: head; }
  #grid1 > nav    { grid-area: nav; }
  #grid1 > main   { grid-area: main; }
  #grid1 > footer { grid-area: foot; }

Результат от способа задания имени грид области (слева — прямое, справа — косвенное), как видно в примере ниже, не зависит:

See the Pen JNpXom by Ilya Streltsyn (@SelenIT) on CodePen.

Автоматическое размещение грид-элементов

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

При знакомстве с автоматическим размещением с плотной упаковкой (dense), наверное, у каждого верстальщика возникает мысль: «Что, теперь не нужны скрипты типа Masonry, и раскладку а-ля Pinterest можно делать чистым CSSом?». Увы: совсем заменить Masonry гриды пока не могут. Грид-элементы пока не умеют автоматически охватывать столько полос, сколько нужно, чтобы вместить их контент: ведь размеры полос сами могут зависеть от размеров элементов, и получается бич CSS — циклическая зависимость (хотя редакторов спеки об этом настойчиво просят, в т.ч. сама Рэйчел Эндрю, так что есть шанс, что в Grid Layout 2-го уровня для фиксированных размеров полос такая возможность появится). Но мы можем расставить их динамически! Хотя бы простейшим скриптом, как в примере ниже (форке одного из примеров к самому Masonry):

See the Pen Masonry (fluid columnWidth) with CSS Grid by Ilya Streltsyn (@SelenIT) on CodePen.

Откройте его в отдельной вкладке и посмотрите, что происходит при ресайзе окна. Вся логика скрипта заняла немногим больше строчек, чем одно лишь подключение Masonry в оригинале!

Важное замечание: но всё же не стоит слишком увлекаться таким приемом для очень длинных страниц, особенно с «бесконечным скроллингом». Максимальное количество рядов в гридах в браузерах ограничено, если их станет больше 1000 — могут быть проблемы.

Порядок грид-элементов

При явной привязке грид-элементов к линиям и/или областям их порядок значения не имеет. Куда что поставите, там то и будет. Порядок влияет только на наложение грид-элементов, если их грид-области пересекаются (см. ниже).

При автоматическом размещении элементы идут в том порядке, как они идут в разметке. Это можно изменить тем же свойством order, что во флексбоксах. Работает оно тут практически так же. Но не злоупотребляйте им: разный порядок на экране и при клавиатурной навигации считается проблемой доступности.

Выравнивание и центрирование грид-элемента в грид-области

Грид-элементы можно выравнивать (в т.ч. центрировать) в своих грид-ячейках или грид-областях всеми свойствами для выравнивания (из модуля CSS Box Alignment). Используются свойства justify-items/align-items для контейнера (выравнивают все элементы сразу) или justify-self/align-self для самого элемента (выравнивает конкретно его), во многом аналогично выравниванию флекс-элементов во флекс-контейнере. Подробнее о них — в отдельной статье. Можно поиграть с ними и в живом примере:

See the Pen GmKMyp by Ilya Streltsyn (@SelenIT) on CodePen.

По умолчанию, если ничего не делать, грид-элементы растягиваются (stretch) на всю область по обеим осям. Наверное, чаще всего именно это и нужно.

Наложение грид-элементов

Если несколько грид-элементов размещены в одной грид-области/ячейке, они могут накладываться друг на друга. Порядком наложения можно управлять с помощью z-index — совсем как для позиционированных элементов.

Вы могли заметить это в самом первом примере в статье, при наведении на термины вверху (можно вернуться и посмотреть еще раз:).

Песочницы

Любую новую технологию проще осваивать «методом тыка», на удобном тренажере. Но сделать свою «песочницу» для гридов по образцу «песочницы» для флексбоксов из визуального руководства по ним оказалось не так-то просто: в гридах, в отличие от флексбоксов, грид-области существуют независимо от грид-элементов, так что их нужно визуализировать отдельно. Возможно, то, что получилось, тоже окажется для вас чем-то полезным (особенно в сочетании с грид-инспектором из отладчика Firefox), но хочется большего (напр. наглядного визуального редактора структуры грида). Мы работаем над этим, так что следите за обновлениями сайта!:)

А пока, кроме вышеприведенной ссылки, «потыкать» гриды можно с помощью следующих ресурсов:

  • Песочница по гридам Мирзы Джолдика. Простой, но наглядный инструмент с текстовым интерфейсом: есть поле для ввода CSS-кода грид-контейнера, поле для общего CSS-кода всех грид-элементов, а прямо в каждый из самих элементов можно вводить его «персональный» CSS-код. Элементы можно добавлять и удалять, а также скрывать/показывать их порядковый номер и примененные стили. Благодаря тому, что стили задаются напрямую CSS-кодом, тут нет типичных для подобных песочниц ограничений (напр., можно вовсю использовать автоматические полосы и repeat), но нужно знать, что вводить (совсем начинающим может быть сложновато). У автора песочницы есть также неплохая статья по гридам с примерами ее использования. И эту песочницу рекомендовала сама Джен Симмонс:)
  • Шпаргалка по гридам Али Алаа. Тут, наоборот, яркий (даже очень:) и наглядный GUI, так что добавить/удалить ряд/колонку грида или изменить их размер — и тут же посмотреть, что получится — можно буквально в один клик. Грид-элементы тоже можно динамически добавлять, а по клику на элемент выезжает дополнительная панель инструментов, где можно изменить его свойства (перепривязать к другим грид-линиям и изменить выранивание). Но оборотная сторона наглядности интерфейса — некоторые продвинутые функции (repeat с auto-fill/auto-fit, именованные области и т.д.) недоступны.
  • Визуальный редактор grid-template Энтони Дюгуа. Удачный «гибрид» визуального и текстового интерфейсов: управлять струтурой грид-областей можно как редактированием CSS-кода, так и перетягиванием прямоугольников по нарисованной сетке, когда что-то одно из этого меняется, второе автоматически подхватывает изменения. Но, как видно из названия, инструмент служит лишь для одной частной задачи и не претендует ни на что большее (поиграть с отдельными грид-элементами в нем не получится). Может быть хорошей «затравкой» для начала самостоятельных экспериментов.
  • Любая из универсальных песочниц типа CodePen, jsFiddle, dabblet и т.п. Кроме шуток: когда уже знаешь основы, зачастую бывает проще набросать нужный пример с нуля. Можно брать за основу любой готовый пример из интернета, в т.ч. из этой статьи. А с грид-инспектором из Firefox это еще проще (кстати, на mozilla.com есть прекрасная страница с полезными примерами гридов, наглядной инструкцией к инспектору и кучей полезных ссылок).
  • Ну и как не упомянуть гриды на грядках — чудесный вводный курс в Grid Layout в форме забавной игры (нужно «поливать морковки» и «опрыскивать сорняки», управляя соотв. областями с помощью CSS-свойств) тех же авторов, кто раньше выпустили не менее увлекательную «обучалку» по флексбоксам на лягушатах.

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

8 Комментарии
  1. Valerii Sydorov

    Спасибо! Очень крутая статья для тех, кто хочет быть на «гребне волны». А как поделиться? Где расшаривание в соцсетях?

  2. SelenIT (Автор записи)

    Спасибо за отзыв! Стараемся для вас). А кнопки расшаривания должны быть сразу над комментариями (может, не догрузились или попались под горячую руку слишком усердной баннерорезке?).

  3. Петр

    Также обратите внимание, что при увеличении размеров контейнера ряд с размером auto начинает растягиваться по высоте.
    Растягивается же только второй (средний) ряд, а у него высота вовсе не auto же:
    grid-template-rows: auto minmax(50px, 50vh) 5em;

    1. SelenIT (Автор записи)

      Ой! Действительно, перемудрил с редактированием примеров (сначала контейнер должен был растягиваться вручную по высоте окна, потом решил для наглядности заменить анимацией, а зависимость от высоты убрать забыл). Спасибо за внимательность! Обновил пример, посмотрите теперь — после того, как второй ряд растянется до максимума (120px), должен начать растягиваться первый.

      1. Петр

        Ага, работает! :) Спасибо! И за мануал, за труд и за ответ :)

  4. Pogranecz

    < Cпасибо за статью.

  5. Сергей

    Спасибо! Очень понятно. Кроме одного момента. Может слишком чайниковский вопрос, но перерыл всю статью, а ответа на нашёл.

    Надо чтобы один row был нужного размера (хоть в px, не важно), а другой — высотой до конца экрана (по вертикали, конечно), но без прокрутки. Все примеры и песочницы из статьи так или иначе задают его высоту. А мне бы автоматически…

    1. Сергей

      уже нашёл причину: height контейнера был ограничен

Оставить комментарий

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

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

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