Большая статья про гриды (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).
  • Ключевым словом min-content — наименьший возможный размер контента. Для текста это ширина самого длинного неразрываемого фрагмента или слова.
  • Ключевым словом max-content — наибольший размер контента. Для текста это длина самой большой строки без переносов.
  • Функцией minmax(<минимум>, <максимум>). Задает минимум, до которого можно ужимать полосу, и максимум, на который она может растянуться, если хватит места (аналог min/max-width или min/max-height в одной записи). Максимум можно задавать всеми вышеперечисленными способами, минимум — всеми, кроме fr. Обычно минимум делают фиксированным, а максимум — гибким, напр. minmax(200px, 30%) или minmax(5em, 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 бы тоже растягивалась.

(Добавлено 13.07.2017): и еще обратите внимание, что полосы с размерами в fr не сжимаются меньше наименьшего размера контента, т.е. фактически ограничены снизу значением min-content. Так что широкий контент (таблица, большая картинка и т.п.) может «распереть» колонку и визуально нарушить структуру грида (автор примера сам было попался:). Если нужно, чтобы колонка сужалась сильнее, указывайте минимум явно, например, minmax(0%, 1fr).

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

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

.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 для этого же свойства тоже можно повторять только конкретные размеры (не *-content, не fr и не auto).
    • grid-template-columns: repeat(2, 2fr) repeat(4, 1fr) — можно (нет auto-fill/auto-fit)
    • grid-template-columns: repeat(4, 10%) repeat(auto-fill, 10em) — можно (в первом repeat повторяется конкретная ширина в процентах)
    • 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 для таблиц. Только бывает еще и в процентах. И добавляется только между полосами, снаружи крайних полос не добавляется.

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

Другой неинтуитивный момент (добавлено 29.06.2017): сокращенное свойство grid сбрасывает значения грид-интервалов (как background сбрасывает background-color), но не может их установить! Поэтому всегда пишите их после свойства grid, ни в коем случае не перед ним.

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

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

Если грид-полосы заполняют грид-контейнер не целиком (т.е. сумма их размеров меньше размера грид-контейнера и нет полос с размерами во 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-row-end: abracadabra — то же самое, что grid-row-end: abracadabra 1, пропущенный номер линии по стандарту интерпретируется как 1).

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

Пары 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 (вместо правильного grid-column: content 1). Firefox и Safari отображают верно. Баг уже оперативно исправили, но пока исправление доходит до релиза, на всякий случай всегда явно указывайте номер конкретной линии, если одноименных линий несколько.

Можно написать еще короче, сократив обе пары сразу: 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] auto [nav-end foot-end main-start] auto [head-end main-end];
      grid-template-rows: [head-start] auto [head-end  nav-start main-start] auto [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. Это тоже может быть интересно:

39 Комментарии
  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 контейнера был ограничен

  6. Luca

    Ребят, чего-то перемудрили. Вроде только начал понимать гриды и после статьи только запутался. Скорее всего это потому, что сразу начинаете мешать всё в кучу. Смотрите, я только начал разбираться, а тут на тебе, и fr и auto, и vh, а для меня все эти понятия новы и получилась, что ничего не получилось. Постепенно надо вводить. Начать с самых простых реализаций — минимальных, затем fr и тд и только потом миксовать это, а вся первая половина статьи сплошной микс, который только рассеивает. Может это субъективно моё ощущение.

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

      Спасибо за честный отзыв!

      Эта статья задумывалась в большей мере как обзорная, «что вообще тут есть». Есть очень много всего, поэтому приходилось искать баланс между краткостью и полнотой (если описывать каждую возможность подробно, никакой статьи не хватит, но и упустить что-то важное — например, auto-fill/auto-fit, упущенные в «полном руководстве по гридам» с CSS-Tricks — тоже не хотелось). Статья посвящена новинкам именно гридов, поэтому тема той же vh действительно не раскрыта (про единицы измерения была старая статья, но признаю, расчет был на то, что читатели с этими единицами уже знакомы). Да, первая половина статьи, возможно, слегка ошарашивает (не говоря уже о спецификации!), но хотелось именно показать безграничность возможностей, а потом уже знакомить с этими возможностями более подробно. Некоторые понятия (те же auto-fill/auto-fit и свойства для выравнивания — justify-*, align-* и новое сокращение для них place-*) подробнее объясняются на примерах в отдельных статьях по ссылкам.

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

      Но критику принимаю! И буду благодарен за указание на самые проблемные места текста — постараюсь переписать яснее или добавить поясняющий пример/иллюстрацию. Попробуем вместе найти оптимальный компромисс между полнотой и понятностью!

  7. Luca

    Правда перемудрили — я реально перестал что-либо поонимать. Хотел статью прочитать с утра в удовольствие, а в результате «подавился». Может статья для каких-то опытных верстальщиков.
    Для начинающих эта статья точно не подходит. Макеева слушал про гриды — всё понял, что он объяснял.

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

      Можно указать самые непонятные/запутывающие места? Постараюсь исправить эти недоработки!

      1. Luca

        Надо разобраться самому сначала, а потом, надеюсь, напишу, когда сам пойму.

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

          Если что, не стесняйтесь спрашивать прямо здесь — попробуем разобраться вместе, а заодно и статью подшлифуем!

          1. Luca

            если возможно, посоветуйте форум по CSS,HTML (желательно на русском)

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

              https://htmlforum.io/ подойдет?

              1. Luca

                Нет, не подойдёт, тк я начинающий, а в разделе для начинающих там два подфорума:
                1. Макеты для вёрстки — не то
                2. Сделайте мне бесплатно (раздел для ленивых, лодырей…)
                ни туда, ни туда себя и свой вопрос не отношу: у меня конкретный вопрос по гридам и к «Макеты для вёрстки» это не относится, но к бездельникам, лодырям и пр. я себя тоже не отношу, а третьего там не дано. Вот.

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

                  Так кроме подфорумов там есть собственно сам корневой раздел «для начинающих», куда не относятся эти две категории)

                  1. Luca

                    грустный форум у Вас (чисто дизайнерски) — тоску навевает. цвет надо поменять — побольше ьцветов стимулирующих моз и интеллект (сиреневый с какими-то цветами из оранжевого имхо).
                    в тонкости вникать некогда просто, тк делаю сайт посвященный математике (моё любимое). Фронтэнд что-то с чем-то — всякие вебпаки, гриды, CSS + ещё всякой шелухи типа React. Я «покалупал» когда чистый JS, то начал писать «свой фреймворк»-просто сокращать, потом понял, что пишу смесь JQuery and React. ДЖКвери молодцы — у меня длиннее получилось — профи )) Реакт порочен в конце концов имхо. В остальном я не берусь судить… пока

                2. Алексей

                  я, прежде чем забраться на форум, сидел на самом htmlbook, сначала читал книги, иногда спрашивал в комментариях(увидите), решал учебные примеры (постепенно освоите песочницы) и только через какое-то время созрел до вышеупомянутого форума — когда появились какие-то вопросы, но это начнётся, по-видимому, не раньше, чем Вы без особых проблем какие-то задачи будете ваять самостоятельно. Тогда Вы можете дать кусок кода и сказать, вот такая-то задача, решил делать так-то потому-то, думал будет эдак, а получилось эвонакак… почему? что я упустил, как можно исправить? и пробуйте решать задачи разными способами, отмечайте для себя, их преимущества и недостатки…

      2. Luca

        В общем, мое мнение, после прочтения статей для начинающих( Вы дали мне пару ссылок), таково: надо сделать пометку в начале статьи, что на неокрепшие умы оказывает негативный эффект и ссылки на вводный курс, те эта статья не для знакомства с grid’ами вот и всё.

  8. Ярослав

    Ох уж эти гриды. То ли с зимы, то ли с весны всё пытаюсь к ним подобраться, и вот, наконец, начало приходить хоть какое-то понимание, теперь пришло время углубляться. Сложно было отвыкнуть от «одномерного мышления»)

    Сейчас кручу-верчу эту статью (как и все остальные по гридам на этом сайте), на глаза попалось два «бага»:
    — В разделе «Выравнивание и центрирование грид-полос в грид-контейнере» самая последняя ссылка битая (которая про уточнение спецификации), прямо в ней слово «auto-fill» внезапно оказалось окружено тегом «code»«/code».
    — В содержании к третьей главе ссылка «По имени» не работает, в статье у самого элемента «h4» пропал id.

    А так за статью большое спасибо! Думаю, буду ещё далеко не раз к ней возвращаться, как когда-то возвращался к флексбоксам

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

      Огромное спасибо за внимательность! Баги исправлены.

      1. Ярослав

        Рад помочь! У меня тут, кстати, ещё кое-что есть. Один раз за что-то зацепился взгляд, но я не понял, за что именно. Во второй раз тоже. И вот только что до меня дошло, что последний пункт списка в песочницах — не хитроумное послание, которое я всё никак не могу понять, а просто случайный кусок текста одного из пунктов «размеров грид-полос»

         Аж вдруг с себя смешно стало, так глупо себя чувствую :D Шпаргалка, визуальный редактор, гриды на грядках, ключевое слово max-content — всё верно, да, так и было задумано…

        И ещё, правда уже не по статье: когда нажимаешь на «ответить», то форма ответа как-то некрасиво наезжает на сообщение, если отвечаешь на комментарий автора записи (заголовок «Оставить комментарий» частично наезжает на сервый фон сообщения). А если нажать «ответить» на сообщение над комментарием автора (на моё изначальное сообщение, например), то форма вообще выпирает слева от серого фона. Попробовал через devtools убрать float у #comments #respond, стало выглядеть намного лучше. И без него всё по-прежнему выглядят хорошо (вроде как), что в хроме, что в файрфоксе. Посмею спросить, зачем там был нужен float? И при скроллинге в момент прилипания менюшки к верхней границе экрана контент страницы каждый раз так неприятно скачет…

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

        1. Ярослав

          Эх, забыл закрыть «code», а исправлять уже поздно.

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

          Большое спасибо еще раз! Сам ума не приложу, как этот пункт туда прискакал (притом в отдельном ul). Какая-то издержка Ctrl+C/Ctrl+V при промежуточных правках, видимо… Fixed.

          А насчет багов в верстке самого сайта — увы, признаю. Постараюсь разобраться. Но вообще текущий дизайн задумывался как временный компромисс, он и так слишком затянулся, и вот как раз сейчас появились шансы исправить это радикально (правда, это пока секрет:). Так что следите за обновлениями!

  9. Алексей

    В разделе «Размещение грид-элемента в грид-области» в примере, в html-коде два раза используется идентификатор grid0 (вместо grid1 для второй иллюстрации).

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

      Спасибо! Исправлено.

  10. Алексей

    Для понимания, в «Выравнивание и центрирование грид-элемента в грид-области» хорошо было бы повторить про свойства justify-content и align-content, в контексте сравнения их с justify-items align-items (насколько я понял, первые определяют расположения грид-ячеек, а вторые — расположение контента в этих ячейках, грубо говоря). Ну а потом уже упомянуть про self’ы (тоже самое что items только для отдельной ячейки, для которой это свойство и назначается).
    Подобное повторение не грузит, а наоборот облегчает восприятие статьи: даже простую логику запомнить с первого раза сложно, а при чтении статьи, нужно постоянно только что прочитанное увязывать с тем что было две строчки назад, и хорошо когда авторы «заботятся» о том, чтоб картинка возникающая в голове читателя совпадала с тем, что они излагают :)

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

      Я боялся, что если начать подробно разжевывать эти свойства еще и здесь, то статья получится вообще неподъемной, поэтому решил вместо этого сослаться на отдельную большую статью про них. К тому же эти свойства — не часть спецификации гридов, они общие для гридов и флексбоксов (а в перспективе — еще и для мультиколонок и даже для блоков), и я решил, что даже ради общей картины лучше рассказать о них отдельно, а не мешать их в общую кучу.

  11. Алексей

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

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

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

      1. Алексей

        Спасибо! И сорри за невнимательность…

      2. Алексей

        На вскидку, по флексбоксам у этих авторов обучалка намного мощнее, последняя задача довольно сложная и, в принципе, лягушки учат флексбоксам относительно творчески.
        Что же касается моркви, то она, скорее неплохой тренажёр для Вашей статьи (даже скорей отдельных её моментов, «вооружают» отдельным моментам синтаксиса, начинаешь понимать как его использовать), но на всеобъемлющую обучалку по свойствам и возможностям гридов явно не претендует. Так что, вопрос, по-видимому, актуален, особенно для рунета.
        Основное в таких обучалках, на мой взгляд, постепенность, чтоб у обучающихся выстраивалась общая картинка, которая обретала всё более чёткие очертания, и лёгкая доступность используемого синтаксиса, чтоб обучающийся, в первую очередь, думал о логике построения, а не о том, какими словами слать авторов тут вообще можно пользоваться :-) А то превратится в игру угадай-ка… А нужно, чтоб обучающийся ощущал синтаксис не как сложнозапутанный квест, а как удобный инструмент с богатыми возможностями и настройками…

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

          Но флексбоксы и объективно проще. Одно измерение (ну в крайнем случае «полтора», для многострочных), положение блоков определяется самими блоками и единственным образом, блоки не накладываются друг на друга и т.д. А в гридах и самих возможностей больше, и переплетаются они друг с другом теснее. Поэтому с любыми наглядными материалами по ним очень трудно избежать одной из крайностей — либо застрять на простых примерах и так и не добраться до целой картины, либо попытаться обрисовать эту общую картину и упустить какую-то конкретику. Как минимум, если пытаться запихнуть все гриды в одну статью/обучалку/руководство. Сам на этом обжегся.

          1. Алексей

            Методология обучения вообще вопрос довольно большой и сложный, хотя, конечно, очень интересный! Иногда читаешь какие-то вводные — всё понятно, переходят к конкретике — что-то вроде «все слова понятны, а вот общий смысл — нет» :-)

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

            Эту общую картину формирует сам читающий (обучающийся) когда, используя предыдущую аналогию, учится строить фразы из слов. Тогда постепенно начинает заполняться «сфера возможного» и формируется общая картина. До этого всё, что бы Вы не рассказали, будет либо «всё понятно, а что конкретно?», либо «как конкретно это сделано, понятно, но как пришить к
            этому перламутровые пуговицы — не совсем» :) То есть, к конкретике, подробностям и особенностям, нужно подвести, из общих принципов, должна вытекать возможная логика, а для её реализации, органично выстраиваться синтаксис. Так, чтоб читатель мог спокойно в голове воспроизвести весь процесс. Иначе ему придётся верить Вам на слово :-)
            Наверное, как-то так…

  12. Алексей

    repeat(auto-fill, 100px), repeat(auto-fit, minmax(100px, 1fr)) — а не могли бы прокомментировать как, в данном случае, будет произведено заполнение?

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

      Это два разных примера (виноват, по оформлению получилось неочевидно, но запятая ведь в любом случае в значениях grid-template-* не используется). Исправил оформление на более очевидное. Никакой тайной хитрости там не предполагалось, первый пример — заполнение контейнера 100-пиксельными полосами, сколько влезет, второй пример — заполнение полосами не меньше 100px без пустых полос (т.е. полос не больше, чем элементов).

      1. Алексей

        Спасибо!

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

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

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

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