Грид + флексбокс: мощнейшее комбо в веб-раскладке

Перевод статьи Grid + Flexbox: the best 1-2 punch in web layout с сайта www.chenhuijing.com, опубликован на CSS-live.ru с разрешения автора — Чэнь Хуэй Цзина

Через 5 дней выходит стабильный релиз Firefox 52. Знаете, что это значит? Это значит, что через 5 дней начнут поддерживаться CSS-гриды. А совсем скоро, 14 марта, подтянется Chrome 57, за ним Safari 10.1 и, надеемся, до конца 2017-го присоединится и Edge.

Я весь в предвкушении.

Представляете, насколько я в предвкушении? Может, немного эмодзи поможет передать мои чувства (конфетти, человек показывает жест «ОК», хлопушка, человек танцует).

Как я вникал в CSS-гриды

Помните, как Рэйчел Эндрю отвечала на вопрос, когда использовать флексбоксы, а когда — гриды? Нет? Тогда посмотрите видео по предыдущей ссылке.

Флексбоксы — для одномерной раскладки. Гриды — для двумерной.

Рэйчел Эндрю

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

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

Затем я сел и написал этот раздел справочника.

Три недели спустя у меня было чувство, будто я вобрал в себя самого прокачанного Металлического кактуара (это отсылка к Final Fantasy Brave Exvius, ничего не могу поделать, Final Fantasy — важная часть моей жизни), другими словами, я порядком повысил свой уровень. Я много времени проводил с самой спецификацией, всеми ее 86 страницами (согласно моим настройкам печати).

Еще были статьи о CSS-гридах (многие из них есть у нас в переводе — прим. перев.) Мануэля Рего Касановаса, с поистине глубоким разбором особенностей гридов, вроде позиционированных элементов, размещения элементов в гриде и автоматического размещения. И меня просто спасла шпаргалка по выравниванию блоков Рэйчел Эндрю, потому что в другом ресурсе, которым я пользовался, оси были подписаны неправильно, что крайне запутало меня на несколько дней кряду.

Вот мой совет. Изучая новое CSS-свойство, держите под рукой пустой HTML-шаблон, чтобы можно было испытать его в чистом и безопасном окружении. Особенно полезно это было для такой новинки, как гриды. Знаю, есть же Codepen и всё такое, но мне нравится экспериментировать на чистом листе, чтобы ничто не отвлекало.

Примеры

Когда я разбирался со свойствами, я начал с создания простейшего грида, просто чтобы посмотреть, как действует каждое свойство. Если вы видели синтаксис для grid-template-rows в спецификации, вы поймете, что это было не такой уж тривиальной задачей. Сами по себе гриды не очень сложны в изучении. Но, поскольку созданы они с прицелом на гибкость и мощь, вам придется затратить чуть больше времени, чтобы узнать их как следует.

Из нескольких таких элементарных гридов выросли полноценные демо-примеры. На некоторые примеры меня вдохновили беседы с участниками клуба CSS-раскладки. Я также слежу за идеями из истории графического дизайна на сайте Coursera, так что немало вдохновения черпаю и оттуда (прошлая неделя была неделей Баухауса ❤️).

Я наткнулся на эту страницу из работы «Malerei, Fotografie, Film» («Живопись, фотография, кино») Ласло Мохоли-Надя, которая выстроена в виде сетки, и первой моей мыслью было, что это можно сделать на CSS… наверное. Что ж, есть лишь один способ узнать это.

Страница 126 из «Malerei, Fotografie, Film»
Страница 126 из «Malerei, Fotografie, Film»

Баухаус у меня в браузере

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

.grid {
  display: grid;
  grid-template-columns: 30% 9% 9% 9% 9% 9%;
  justify-content: center; /* чтобы выровнять грид по середине контейнера */
}

После этого шла целая куча кода со свойствами grid-row и grid-column для размещения элементов. Но если снова взглянуть на исходную картинку, видно, что содержимое каждой ячейки выравнивается по-своему. Скажем, содержимое первой ячейки прижато к правому краю, слово во второй ячейке — к левому нижнему углу, и т.д.

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

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

Это не те границы, которые вы ищете
Рисунок грид-элементов с размером по содержимому

Флексбоксы спешат на помощь

По умолчанию все грид-элементы ведут себя так, будто им задано выравнивание stretch по обеим осям. Я не стал это трогать, чтобы грид выглядел действительно как сетка. Вместо этого я применил к грид-элементам display: flex, что позволило мне использовать для размещения содержимого грид-элементов свойства флекс-выравнивания, задаваемые для флекс-контейнера (крутой смайлик).

Вот так-то лучше
Рисунок грид-элементов с размером по содержимому

.grid__item:nth-child(5) {
  grid-row: 3 / 5;
  border-right: 1em solid;
  padding: 1em;
  
  display: flex;
  align-items: flex-start;
  justify-content: flex-end;
}

Примерно так выглядит код, но главная моя мысль — это замечательный прием для построения раскладок. Грид для общей схемы всего и флексбокс для точной настройки отдельных частностей. Вот ссылка на Codepen, если кому-нибудь вдруг интересен итоговый результат.

See the Pen Malerei, Fotografie, Film (pg. 126) by Chen Hui Jing (@huijing) on CodePen.

Довесок: CSS-фигуры

За исключением 2 фотографий на странице, всё остальное сделано на CSS, т.е. стрелка и шестеренка — на самом деле divы со стилями. Мне нравится делать фигуры на CSS, по возможности из одного divа. Вам пригодится несколько удобных вспомогательных свойств, box-shadow, border, а также псевдоэлементы.

Стрелка

Со стрелкой всё достаточно просто. Нужен лишь 1 дополнительный псевдоэлемент для кончика стрелки. Делаем из div основу стрелки и задаем ему position: relative, так что кончик стрелки можно абсолютно позиционировать относительно основы. Кончик стрелки — это треугольник, который можно сделать с помощью фокуса с border-ом.

.arrow {
  width: 0.5em;
  height: 65%;
  background-color: #000;
  position: relative;
  
  &::after {
    display: block;
    content: '';
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    bottom: -1em;
    border-style: solid;
    border-width: 1em 1em 0 1em;
    border-color: #000 transparent transparent transparent;
  }
}

Шестеренка

Это было посложнее. Основа шестеренки — круг, т.е. border-radius: 50%, но для зубцов нужно кое-что похитрее. В этот раз я не смог сделать их одним divом (если вдруг кто-нибудь сможет, пожалуйста, поделитесь со мной этим секретом). Для зубцов шестеренки мне понадобился добавочный вложенный вспомогательный div. К счастью, все зубцы у шестеренки одной формы, так что можно применить трюк с box-shadow.

.gear {
  height: 5em;
  width: 5em;
  background-color: #000;
  border-radius: 50%;
  position: relative;

  &::before,
  &::after {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    display: block;
    content: '';
  }
  
  &::before {
    height: 3em;
    width: 1em;
    box-shadow: 0em -3em 0em 0em #000, 0em 3em 0 0em #000;
  }
  
  &::after {
    height: 1em;
    width: 3em;
    box-shadow: 3em 0 0em 0em #000, -3em 0 0 0em #000;
  }
}

Основа шестеренки и 4 зубца, направленные «по сторонам света», сделаны одним divом и двумя его псевдоэлементами. Для оставшихся четырех зубцов я воспользовался внутренним divом с псевдоэлементами, затем повернул тени (box-shadow). Мне еще нужно разобраться с нюансом с transform-origin, а то мне кажется, что сейчас оно выглядит слегка асимметрично.

.inner-gear {
  height: 2em;
  width: 2em;
  border-radius: 50%;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: #e1e1d5;
  
  &::before,
  &::after {
    position: absolute;
    display: block;
    content: '';
  }
  
  &::before {
    height: 3em;
    width: 1em;
    box-shadow: 0em -3em 0em 0em #000, 0em 3em 0 0em #000;
    transform: rotate(45deg);
    transform-origin: (75% 75%);
  }
  
  &::after {
    height: 1em;
    width: 3em;
    box-shadow: 3em 0 0em 0em #000, -3em 0 0 0em #000;
    transform: rotate(45deg);
    transform-origin: (25% 75%);
  }
}

Под занавес

Я в восторге от гридов, и, очевидно, не я один так считаю. Джен Симмонс собрала список поистине замечательных ресурсов по гридам, так что посмотрите «Уроки по CSS-гридам» и попробуйте сделать что-нибудь на гридах. Не пожалеете (широко улыбающийся смайлик).

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

7 Комментарии
  1. Антон

    Все ок, поддержка браузерами не ок.

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

      У флексбоксов уже >97%. У гридов к концу этого месяца уже будет больше половины (см. первый абзац статьи:).

  2. Илья

    Зачетно!!!

  3. Алексей

    Воу воу, тематика годная, НО
    Layout в контексте данного повествования — это не расладка, это МАКЕТ.

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

      Добро пожаловать в один из старейших околоверстальных холиворов! :)

      Макет — годное слово, НО в контексте работы верстальщика оно обычно значит то, что приходит от дизайнера («заверстай вот этот макет»), т.е. «mockup», а вовсе не «layout» (в любом из его значений). И опыт упрямо показывает, что вариант «раскладка» — наименьшее зло, создающее меньше всего путаницы для большинства читателей.

      Но можете попробовать предложить еще более удачный вариант в словарик!

      1. Serator

        Сам работаю с иностранными дизайнерами и подтверждаю, для макета они используют «mock-up» (только через дефис).

  4. shurupkirov

    Поделился с автором шестеренкой на одном div’е

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

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

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

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