Лакомые кусочки Grid-раскладки, часть 2: основы и терминология

Перевод статьи Grid Tidbits part 2: terminology and basics с сайта thatemil.com, автор — Эмиль Бьёрклунд (твиттер — @ThatEmil).

В этой статье мы познакомимся с терминологией «CSS Grid Layout», основами определения grid-шаблонов и размещения в них элементов.

Это вторая из цикла относительно небольших статей про «Grid Layout». В первой части мы узнали о назначении grid-ов и о текущей ситуации в браузерах.

Для этого «лакомого кусочка» мы сделаем следующее:

  • Возьмём элемент и превратим его в grid.
  • Увидим, как элементы сами размещаются в grid’е
  • Поупражняемся в том, как управлять этим размещением

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

Терминология Grid

Grid layout работает за счёт «разбивки» элемента — называемого grid-контейнером — на ряды и колонки. Grid-элементы — непосредственные потомки grid-контейнера могут затем разместиться в этом grid-е. Grid-элементы могут занимать одну grid-ячейку, либо охватывать несколько рядов или колонок. Любые прямоугольные части grid’а собирательно называются «grid-область». Когда вы создаёте ряды и колонки (собирательно называемые «grid-полосы»), вы также создаёте grid-линии, образованные краями полос.

Мы начнём с создания простой сетки, а затем по ходу дела обозначим эти части. Рассмотрим разметку с обычным контейнером div и тремя дочерними элементами.

<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 {
  background-color: #E6CAD6;
}

[class^="grid-item"] {
  border: 1px solid #fff;
  font-size: 4em;
  min-height: 2.5em;
  line-height: 2.5em;
  text-align: center;
  color: #fff;
}

.grid-item-a {
  background-color: #3D74C7;
}

.grid-item-b {
  background-color: #85CAAA;
}

.grid-item-c {
  background-color: #DAB97D;
}

А что, если теперь мы прикажем элементу .grid-container отображаться как grid, и просто оставим всё как есть?

.grid-container {
  display: grid;
}

grid-notemplate

«Голый» grid-контейнер (ссылка на JSBin для рисунка 1)

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

Заметьте, что у display бывает также значение inline-grid — совсем как inline-block или inline-flex. Как видно из его названия, работает как grid-контейнер, но располагается в строчном потоке.

Grid-шаблон

Чтобы двигаться дальше, нужно понять, как работает grid. Скажем, нам нужно две колонки по 50% каждая, и две строки с height: auto — по высоте самого высокого содержимого. Для этой задачи нам потребуется помощь grid-шаблона. Он задаёт полосы (колонки и ряды), и простейшая форма их описания — перечисления размеров через пробел, в порядке отображения.

Заметьте, что эти размеры определяют полоски в порядке направления текста, так что для языков, в которых пишут слева направо, первая колонка — крайняя слева, это меняется при смене значения direction.

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

grid-auto

Посмотрите-ка, получился полноценный Grid! (ссылка на JSbin для рисунка 2)

Вот так вот. Это самая что ни на есть настоящая Grid-овая сетка. Grid-элементы аккурат размещаются в трех из наших четырех ячеек, а grid занимает всю ширину. Чудесно. Но… мы же еще ничего даже не начинали размещать, а элементы уже выстроились колонка к колонке, ряд к ряду — как это так? Ну, у grid-раскладки есть нечто, называемое «автоматическим размещением», и по умолчанию оно разместит каждый элемент, по порядку в исходном коде, в первую же пустую ячейку в первой же строке, где такая найдется. Так что наши три дочерних элемента сами собой займут три из доступных пустых ячеек. То что надо.

Нумерованные Grid-линии

Создав две grid-полосы в каждом измерении, мы автоматически создали три grid-линии в каждом измерении. У двух колонок есть левая, средняя и правая линии. Аналогично у рядов есть верхняя, средняя и нижняя. Grid-линии нумеруются, начиная с 1. (Но не с 0. Вы слишком много читаете про JavaScript, друг)

У нашего grid’a (с направлением текста слева направо) линия 1 — это левая линяя колонки (первая), а линия 3 — правая (последняя)

row-and-column

Номера grid-линий. Вижу в них схожесть с линиями линейки в Illustrator, Photoshop, Sketch и т.д.

Размещение элементов

А теперь самая мякотка: приказать элементам занять конкретную часть grid’а. Например, можно приказать элементу .grid-item-a занять обе колонки в первом ряду. Для этого надо указать те линии, где начинается и заканчивается элемент.

.grid-item-a {
  grid-row-start: 1;
  grid-row-end: 2;
  grid-column-start: 1;
  grid-column-end: 3;
}

grid-span

Элемент А теперь охватывает весь первый ряд. (Ссылка на JSbin для рисунка 3)

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

.grid-item-a {
  grid-row: 1/2;
  grid-column: 1/3;
}

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

.grid-item-a {
  grid-area: 1/1/2/3;
}

Не знаю, как вы, но я нахожу это трудным для чтения. Порядок здесь такой: row-start /column-start / row-end / column-end — т.е., по сравнению с сокращенными записями margin и padding, поставлен с ног на голову (к слову, причина здесь в том, что это позволяет пропускать конечные положения для элементов, охватывающих только одну ячейку).

Отрицательные номера линии и  объединение ячеек

По умолчанию элементы охватывают один ряд или колонку. Как мы уже видели, благодаря алгоритму автоматического размещения элементы автоматически размещаются в первой пустой области, где могут поместиться. Поскольку элемент .grid-item-a первый по порядку в исходном коде, нам не нужно заботиться о следующих вещах:

  • Что он располагается в первом ряду
  • Что он охватывает один ряд

На секунду задержите эту мысль в уме.

Если хотите ссылаться на grid-линии в обратном направлении, то используйте отрицательные числа:  крайняя правая линия колонки находится под номером -1, а крайняя левая — под -3. Пускай нам неизвестно итоговое число колонок в grid’е, зато мы уверены, что .grid-item-a должен охватывать все колонки. В этом случае отрицательная нумерация линии очень кстати.

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

.grid-item-a {
  grid-column: 1/-1;
}

Если необходимо, чтобы вместо целого ряда элемент охватывал конкретное число колонок, то можно указать это явно. Поскольку начальная позиция уже установлена автоматическим размещением (первый элемент по порядку в исходном коде начинается в колонке 1, строке 1), можно конкретно указать, что .grid-item-a занимает две колонки.

.grid-item-a {
  grid-column: span 2;
}

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

Объединение рядов и высота колонок

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

.grid-item-a {
  grid-row: 1/-1;
}

grid-rowspan

Теперь элемент «А» охватывает всю первую колонку. (Ссылка на  JSBin для рисунка 4)

Теперь, если элемент «С» будет гораздо выше, элемент «А» по-прежнему растянется, чтобы занять всю высоту grid-а. Нет больше проблем с «одинаковой высотой колонок»

.grid-item-c {
  height: 6em;
}

grid-autoheight

Элемент «C» сдвигает высоту всего второго ряда. (Ссылка на для рисунка 5)

Этого хватит для создания базового grid-контейнера и размещения элементов в созданных grid-полосах — рядах и колонках. В следующей статье мы  углубимся в более продвинутые аспекты определения grid’ов. Увидимся в третьей части!

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

10 Комментарии

  1. Andrew

    Это все не работает в актуальном хроме (Canary не ставил)? По крайней мере jsbin отображает только А,Б,С друг под другом.

    1. Николай Шабалин

      Отвечу сайтом http://caniuse.com/#search=grid
      Там же вы можете посмотреть в каких браузерах стоит эксперементировать над Grid и что сделать, чтобы в других тоже можно было.

    2. SelenIT

      Работает. Но надо включить «Экспериментальные функции веб-платформы» в chrome://flags/ (и перезапустить браузер после этого, на всякий случай).

  2. Andrew

    Всем спасибо :)

  3. Артём

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

    На Chrome Canary 54.0.2787 ничего не изменилось, это потому, что такое поведение «по умолчанию» было изменено?

    P.S. Все остальные примеры работают также.

    1. SelenIT

      Похоже, что да, изменилось поведение по умолчанию. Ширина неявных грид-ячеек по умолчанию auto, что, действительно, означает ширину по содержимому — но на них влияет еще и justify-content, значение которого по умолчанию (normal) во флексбоксах и грид-раскладке равносильно stretch. Поэтому они растягиваются. Если явно прописать для контейнера justify-content: start, будет как на рисунке.

      1. Артём

        Спасибо. Это первая статья по CSS Grid, которую я прочел, даже не подозревал, что здесь работают flexbox-свойства.
        Еще такой вопрос, чем отличается
        justify-content: start от justify-content: flex-start. В CSS Grid же нет понятий главная и поперечная оси?

        1. SelenIT

          Сейчас W3C старается сделать свойства вида justify/align-content/self универсальными, чтобы они могли работать не только для флексбоксов, но и для других механизмов раскладки (включая обычные блоки). Для них завели отдельную спецификацию CSS Box Alignment. И поэтому решили сделать значения более универсальными — не flex-start, а просто start, и т.д. И заодно добавили новый способ распределения свободного места, поровну между элементами и краями — space-evenly (то, чего многие интуитивно ожидали от space-around).

          Спецификация флексбоксов появилась раньше, поэтому пока некоторые браузеры поддерживают только значения оттуда. Но в будущем, как я понимаю, flex-start и start должны стать взаимозаменяемыми.

          Главной и поперечной осей в гридах нет, но есть блочная и инлайновая оси. Описанные в еще одной спецификации (уж так всё запутано в этом CSS..:)

          1. Артём

            добавили новый способ распределения свободного места, поровну между элементами и краями — space-evenly
            Такое впечатление, что я где-то в прошлом десятилетии застрял…

            есть блочная и инлайновая оси
            Это же зависит от направления текста, которое устанавливается с помощью writing-mode? Наверное, на практике как-то менять значения данного свойства случается крайне-крайне редко. Однако, спасибо, не знал, что вообще такая терминология существует.

            1. SelenIT

              Это же зависит от направления текста, которое устанавливается с помощью writing-mode?

              Да, именно так. Сейчас CSS вообще старается всё больше уходить от физических привязок (право-лево, верх-низ) к логическим, относительно направления письма.

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

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

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

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