CSS-live.ru

Лакомые кускочки Grid-раскладки, часть 3: размеры грид-полос

Перевод статьи Grid Tidbits part 3: grid track sizing с сайта thatemil.com, опубликовано на css-live.ru с разрешения автора — Эмиля Бьёрклунда (твиттер — @ThatEmil).

В этой заметке исследуются некоторые тонкости задания размеров грид-полос (иначе — рядов и колонок) в CSS Grid Layout. Гибкие размеры, функция повторения, функция minmax — вот это да!

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

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

Вспомним пройденное

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

<div class="grid-container">
  <div class="grid-item-a">A</div>
  <div class="grid-item-b">B</div>
  <div class="grid-item-c">C</div>
</div>

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

.grid-container {
  display: grid;
  grid-template-columns: 50% 50%;
  grid-template-rows: auto auto;
}

Эта запись означает, что мы создали шаблон сетки 2 ✕ 2, в котором две колонки занимают по 50% каждая, а два ряда автоматически подстраивают высоту, чтоб вместить самое высокое содержимое. Если мы доверим расположение элементов им самим, т.е. алгоритму автоматического размещения, то A и B окажутся в первом ряду, а C — в левом нижнем углу.

Сетка «два на два» с тремя элементами (подписаны A,B,C), два в первом ряду и один во втором.

Сетка 2 ✕ 2 из второй части (ссылка на JSBin для рис.1)

Чтобы понять грид-раскладку, нужно перестроить своё мышление на то, что основной механизм задания размеров грида заключен в определении грид-полос, а не в самих элементах. Задавать размеры полосам можно во многих единицах измерения — процентах, em-ах, пикселях, единицах области просмотра и т.п. Но в спецификации грид-раскладки есть куда более впечатляющие возможности — поехали!

Придание гибкости — единица fr

Спецификация Grid Layout вводит новую единицу для гибкого задания размеров. Единица fr расшифровывается как доля (англ. fraction) оставшегося пространства. Она распределяет место, оставшееся после вычисления размеров всех полос, заданных как auto, в процентах, em-ах, пикселях и т.п. Если вы знакомы с флексбоксами, это по сути то же самое, что коэффициент flex-grow, при нулевом flex-basis.

Если мы поменяем ширину первой колонки на 5em, а второй — на 1fr, то вторая колонка займет всё место, оставшееся сверх 5em.

.grid-container {
    display: grid;
    grid-template-columns: 5em 1fr;
    grid-template-rows: auto auto;
}

Сетка два на два, где левая колонка уже правой

Обновленный грид, где правая колонка занимает всё место, оставшееся сверх 5em левой колонки (ссылка на JSBin для рис.2)

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

Например, что случится, если правой колонке задать ширину 2fr? Она станет вдвое шире оставшегося места и вызовет переполнение? Нет. Математически «доля доступного места» означает, что вторая колонка получит (значение доли * доступное место)/сумму всех долей. Это значит, что при 100 пикселях доступного места правая колонка будет шириной (2 * 100)/2 пикселей, т.е. всё те же 100 пикселей. Это как смешивать напитки: никаких конкретных единиц, а просто «2 части текилы, 1 часть виски, 1 часть горьких слёз» (это, наверное, получился бы ужасный коктейль, но ведь и я далеко не дипломированный бармен-профи).

Если мы вздумаем добавить еще одну колонку, тоже шириной 1fr, средняя и правая колонки будут одной ширины — каждая по 1 доле доступного места, т.е. по 1/2.

.grid-container {
    display: grid;
    grid-template-columns: 5em 1fr 1fr;
    grid-template-rows: auto auto;
}

Сетка три на два, где вторая и третья колонки одинаковой ширины. Второй ряд пуст и невидим.

Колонки B и C одной ширины. Обратите внимание, что второй ряд теперь пуст и схлопывается до нулевой высоты (ссылка на JSBin для рис.3)

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

.grid-container {
    display: grid;
    grid-template-columns: 5em 2fr 1fr;
    grid-template-rows: auto auto;
}

Сетка три на два, где вторая колонка вдвое шире третьей. Второй ряд пуст и невидим.

Колонка B стала вдвое шире колонки C (ссылка на JSBin для рис.4)

На свободное место претендуют в сумме три единицы (2fr + 1fr), так что две трети оставшегося места (после задания размера первой колонки) достанутся второй колонке, и одна треть — третьей колонке.

Повторение грид-полос

Если вы имеете дело с сеткой сложнее горстки колонок, раз за разом повторять колонки одинакового размера порядком надоедает. К счастью, спецификация гридов разобралась с этим: можно воспользоваться функциональной нотацией repeat(). Если у нас сетка из 24 колонок одинаковой ширины (например), можно просто повторить полосу в 1fr 24 раза.

<div class="grid-container">
  <div class="grid-item-a">A</div>
  <div class="grid-item-b">B</div>
  <div class="grid-item-c">C</div>
  <div class="grid-item-a">A</div>
  <div class="grid-item-b">B</div>
  <div class="grid-item-c">C</div>
  <!-- ...и т.д., 24 шт. -->
</div>
.grid-container {
  display: grid;
  grid-template-columns: repeat(24, 1fr);
  grid-template-rows: auto auto;
}

24 элемента в 24 колонках одинаковой ширины

24 элемента в 24 колонках одинаковой ширины (ссылка на JSBin для рис.5)

Можно сочетать и чередовать повторяющиеся полосы с полосами, объявленными обычным способом, если часть полос отличается. Если первая и последняя колонки задаются в других единицах, список полос для колонок может выглядеть так:

.grid-container {
  display: grid;
  grid-template-columns: 5em repeat(22, 1fr) 5em;
  grid-template-rows: auto auto;
}

Минимальный и максимальный размеры

Покольку мы управляем размерами грид-полос, а не элементов в DOM, мы не можем задать им размеры с помощью свойств min-width, max-width, min-height и max-height. Вместо этого в спецификации Grid Layout для этого предусмотрена функциональная нотация, которая называется соответственно — minmax().

Например, нам понадобилось, чтобы крайняя левая колонка занимала 20% ширины, но не сужалась меньше 5em.

.grid-container {
  display: grid;
  grid-template-columns: minmax(5em, 20%) 1fr 1fr;
  grid-template-rows: auto auto;
}

Стоит отметить, что внутри minmax() можно использовать единицу fr, но смысл в этом есть лишь тогда, когда она указывает максимальный размер. По сути, можно сказать «эта полоса должна быть не меньше 5em, но если места хватит, пусть она занимает такую-то часть свободного места», но не наоборот.

Я не жуткий спец по части объяснений, но подозреваю, что это из-за того, в каком порядке действует алгоритм задания размеров грид-полосам. Если взять единицу fr как минимальный размер, она будет воспринята как 0 или min-content (см. следующий раздел о внутренних размерах), в зависимости от того, как задан размер грид-контейнеру.

Ключевые слова для внутренних размеров и автоматические размеры

Пока что мы объявили, что высота горизонтальных полос (рядов) у нас автоматическая. Что это значит? Ну, мы уже выяснили, что полоса схлопывается до нулевой высоты, если ряд пуст. Если в ряду есть элементы, он растянется, чтобы вместить их. Проще говоря, такое поведение означает, что высота ряда будет равна величине самого высокого элемента — смотря как заданы размеры самих элементов.

Можно добиться еще более прицельного управления размерами полос, если воспользоваться ключевыми словами из модуля внутренних и внешних размеров. Если нам попалась колонка с кратким текстом, мы можем сделать так, чтобы ее максимальный размер соответствовал ширине max-content

<div class="grid-container">
  <div class="grid-item-a">Привет, мир</div>
  <div class="grid-item-b">B</div>
  <div class="grid-item-c">C</div>
</div>
.grid-container {
  background-color: #E6CAD6;
  display: grid;
  grid-template-columns: minmax(5em, max-content) 1fr 1fr;
  grid-template-rows: auto auto;
}

Трехколоночная сетка, первая колонка которой содержит слова «привет, мир»

Пока есть место, первая колонка растягивается, чтобы вместить слова «привет, мир» (ссылка на JSBin для рис. 6)

Если мы добавим к гриду четвертый элемент, он окажется на втором ряду (благодаря правилам автоматического размещения — не переживайте, мы к этому вернемся в следующих лакомых кусочках). Если содержимое этого элемента будет еще шире, размер min-content всей полосы станет больше. Таким образом, max-content означает «элемент с наибольшим max-content в этой полосе».

<div class="grid-container">
  <div class="grid-item-a">Привет, мир!</div>
  <div class="grid-item-b">B</div>
  <div class="grid-item-c">C</div>
  <div class="grid-item-d">Привет, большой мир!</div>
</div>;
.grid-item-d {
  background-color: #274461;
}

Трехколоночная сетка, первая колонка которой содержит слова «привет, мир»

Элемент «D» увеличивает размер max-content первой колонки (ссылка на JSBin для рис. 7)

Лично для меня задание размеров в модуле Grid-раскладки — одно из тех мест, где я сразу вижу непосредственную пользу от ключевых слов для внутренних размеров в CSS (хотя с другой стороны, подозреваю, что польза от них будет везде, просто я еще об этом не думал). Эти ключевые слова появились достаточно давно, но поддерживаются пока лишь местами, в основном с префиксом.

Итого

Для первого раза про размеры грид-полос хватит! Многое еще впереди — мы еще даже не затрагивали интервалы между полосами, именованные линии или области шаблона… Эти первые заметки получились несколько длиннее, чем ожидалось, но, разобравшись с основами, далее мы сможем обсуждать другие понятия покороче. Так что ждите еще более лакомых кусочков!

Текущие лакомые кусочки:

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

5 комментариев

  1. Доброго времени суток.
    Ситуация: динамическое число блоков от 1 до 5-ти в 1 ряд, и нужно что бы ширина каждого блока была на 50px шире текстового содержимого, которое так же разное.
    Как это реализовать? Пробежался по тексту — нигде нет адаптации по содержимому..

    1. Если я правильно понял задачу, реализовать ее можно с помощью неявных грид-колонок (что-то типа такого). Но вообще для неизвестного количества неизвестных размеров, возможно, гриды — не оптимальный выбор. Тем более для одного ряда. Для этой задачи скорее напрашиваются флексбоксы.

  2. Добрый день. Очень классный гайд, прям многое стало понятнее. Но я уже сколько ищу никак не могу найти как сделать правильно адаптивный грид когда в первом ряду у меня два объекта (2 колонки), а в дальнейших 3. Никак не могу сформулировать запрос, чтобы найти инфу, может тут мне кто подскажет?

    1. Добрый день! Как вариант, вы можете сделать грид из 6 колонок и первым двум элементам поставить grid-column: span 3, a последующим — span 2.

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

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

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