CSS-live.ru

Вёрстка реальных проектов на гридах (CSS Grid Layout) уже сейчас

Перевод статьи Building Production-Ready CSS Grid Layouts Today с сайта smashingmagazine.com для CSS-live.ru, автор — Мортен Рэнд-Хедриксен

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

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

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

Я буду рассматривать и приводить примеры для тем WordPress, но практические подходы и примеры универсальны и их можно использовать в любом веб-проекте, независимо от CMS, стека технологий или инструмента.

Приступим!

Удачный пример для CSS-гридов

Подумайте, как бы вы сделали на CSS вот такой макет: две отзывчивых колонки, шапка и подвал, шапка и подвал на всю ширину браузера, а основная область по центру и ограничена максимальной шириной 60em. Контент занимает две трети свободного места, сайдбар одну треть, а два раздела под ними делят доступное место пополам.

http://css-live.ru/Primer/grid-production/mrh_CSS_grid_fig_01-800w-opt.png

(Посмотреть крупнее)

Чтобы решить эту задачу по верстке традиционными CSS-методами, пришлось бы объединить контент, сайдбар и два однотипных раздела в один контейнер, установить ему max-width в 60em; и отцентрировать, задав для margin-right и margin-left значение auto, выстроить разные разделы в один ряд пришлось бы с помощью  display: flex; для главного контейнера и значения flex для каждого элемента, а в дофлексбоксные времена — «зафлоатив» их влево и вправо.

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

В печатной верстке вы не станете центрировать контент с помощью полей или применять гибкие блоки для выравнивания высоты разделов — вы просто поставите их на нужное место в сетке: шапка, область контента с сайдбаром и подвал займут по ряду, шапка и подвал займут все восемь колонок, контент заполнит колонки со 2-й по 5-ю, а сайдбар — 6-ю и 7-ю колонки.

http://css-live.ru/Primer/grid-production/mrh_CSS_grid_fig_01-800w-opt.png

(Посмотреть крупнее)

Благодаря CSS-гридам можно сделать то же самое в браузере:

.site {
	display: grid;
	grid-template-columns: 1fr repeat(6, minmax(auto, 10em)) 1fr;
	grid-template-rows: minmax(1em, auto) 1fr auto minmax(1em, auto);
}

.masthead,
.colophon {
	grid-column: span 8;
}

.main-content {
	grid-column: 2/6;
}

.sidebar {
	grid-column: 6/8;
}

.twin {
	grid-column: 2/5;
	grid-row: 3/4;
}

.twin:last-of-type {
	grid-column: 5/8;
}

Можно посмотреть живой пример на Codepen

See the Pen Standard grid-based 3-column layout with 2-column option by Morten Rand-Hendriksen (@mor10) on CodePen.

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

Как и флексбоксы, гриды учитывают направление текста в документе, так что если поменять атрибут dir на rtl, макет автоматически отразится зеркально, переместив сайдбар влево.

Учимся думать CSS-гридами

Как показал этот пример, чтобы начать работать с CSS-гридами, сначала нужно отбросить привычки, допущения и приемы, что раньше помогали вам в верстке сложных макетов на CSS. Зачастую эти общепринятые подходы были хаками, придуманными для обхода ограничений CSS как инструмента верстки. CSS-гриды, на мой взгляд, первый модуль в CSS, созданный именно для раскладки блоков. Он позволяет работать в двух измерениях и размещать любой элемент в любой ячейке или комбинации таковых. Для этого нужно думать совсем по-новому: не спрашивать себя «Как заставить эту вертикальную пачку контента сделать вид, что она разложена по сетке?», а просто определить сетку и размещать в ней каждый элемент контента.

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

Рассмотрим этот одноколоночный макет, в котором есть как ограниченный по ширине центрированный контент, так и элементы на всю ширину (картинки и фоны):

http://css-live.ru/Primer/grid-production/mrh_CSS_grid_fig_01-800w-opt.png

(Посмотреть крупнее)

В соответствующей раскладке на гридах (справа) 8 рядов и 4 колонки. С помощью CSS-гридов должна быть возможность размещать элементы в этой сетке как угодно. Однако, грид-контейнер (которым становится элемент с display: grid) воспринимает как грид-элементы только своих непосредственных потомков. Это значит, что одной сеткой для этого макета не обойтись. Вместо этого придется создавать гриды на уровне компонентов, фактически несколько разных гридов с одинаковыми свойствами.

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

Чтобы сверстать вышеуказанный макет в браузере, надо будет сочетать CSS-гриды с другими инструментами и приемами, как мы сейчас увидим.

Если ничего не делать, каждый раздел будет на всю ширину блока. Каждому разделу с центрированным контентом мы указываем класс .grid и создаем CSS-правила, которые задают четырехколоночный грид и размещают контент в двух центральных колонках. Раскладка трех вертикальных блоков в третьем разделе сделана флексбоксами. Последний раздел, из двух сплошных половин, образован двумя отдельными грид-элементами, занимающими по две колонки каждый. Это достигается с помощью  grid-column: span 2; (т.е. грид-элемент охватывает две колонки), всё остальное уладит алгоритм авторазмещения..

/* Двухколоночная раскладка. Суммарная max-width двух центральных колонок равна 50em: */
.grid {
	display: grid;
	grid-template-columns: 1fr repeat(2, minmax(auto, 25em)) 1fr;
}
/* Центрируем элементы, помещая их в две центральные колонки: */
.splash-content,
.more-content,
.buckets ul {
	grid-column: 2/4;
}
/* Используем автоматическое размещение + span, чтобы каждый элемент занимал две колонки: */
.twin,
.colophon aside {
	grid-column: span 2;
}

Можно посмотреть живой пример на Codepen.

See the Pen Full-bleed layout with fixed-width content by Morten Rand-Hendriksen (@mor10) on CodePen.

Этот пример показывает как возможности CSS-гридов для решения типовых проблем в верстке, вроде разделов на всю ширину, так и то, что и у этого модуля всё-таки есть свои ограничения. Как показано выше, в идеале вы предпочли бы разметить один-единственный грид и работать со всеми разделами и подразделами с помощью подсеток. Однако, пока что размещать в гриде можно только непосредственных потомков контейнера со значением grid для display, а свойство subgrid в браузерах не реализовано, так что мы вынуждены придумывать такие вот обходные пути. Хорошая новость в том, что это всё равно лучше старых методов и дает чистый и читаемый CSS на выходе.

Инструкция по использованию CSS-гридов в продакшне

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

CSS-гриды — не просто модуль для раскладки, но еще и повод заново подтвердить нашу изначальную цель веб-дизайна и веб-разработки: создавать доступные, расширяемые решения, наилучшим возможным способом доставляющие контент тем, кто в нем заинтересован.

В основе любого проекта во фронтенде лежит простой принцип: сначала сделайте доступно, потом сделайте красиво, и убедитесь, что красота не вредит доступности.

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

  1. Создать доступный HTML с логичной иерархической и семантической структурой.
  2. Сделать отзывчивую одноколоночную раскладку для всех размеров экрана.
  3. Добавить продвинутую раскладку и функциональность (гриды, флексбоксы, JavaScript и т.д.)

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

Обратная совместимость и браузерная поддержка

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

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

Если вы с этим согласны (а надо бы), то вам ничто не мешает использовать CSS-гриды уже сейчас!

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

Прежде чем применять какой-либо CSS, мы начинаем с правильно размеченного HTML-документа, выводимого в одну колонку. По этому документу можно перемещаться с помощью любого устройства ввода, а его иерархическая структура гарантирует, что чтение сверху вниз передает заключенную в нем мысль наилучшим образом. Именно это и делает его доступным. Кое-что зная об аудитории веба, мы можем предположить, что существенная ее часть будет заходить на сайт со смартфона. Разрабатывая сначала для мобильных, мы оформляем единственную колонку документа, чтобы она вписалась в наименьший мобильный экран. Это будет основой нашего дизайна.

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

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

Пример: CSS-гриды в теме для WordPress

CSS-гриды упрощают давние подходы и открывают двери новым динамическим макетам для всех типов приложений. Давайте посмотрим, как это работает в жизни, и применим грид для готовой темы для WordPress по намеченному только что плану. Здесь я буду отталкиваться от начальной темы _s (или Underscores). Как я отметил во введении, эти подходы универсальны и подходят для любой начальной темы или фреймворка для тем, и даже вообще не для WordPress.

Если вам нужен надежный контроль над тем, как CSS-гриды работают в браузере, рекомендую взять Firefox c его инспектором гридов. Так у вас будет наглядная справка, где находятся ваши гриды и для каких элементов они действуют.

0. Структурные наброски раскладки

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

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

Для современных браузеров есть две основных раскладки:

  • Главная страница и архив показывают опубликованные записи в виде плитки на гридах, где выделенные записи занимают вдвое больше места, чем остальные.

    http://css-live.ru/Primer/grid-production/mrh_CSS_grid_fig_01-800w-opt.png

    (Посмотреть крупнее)

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

    http://css-live.ru/Primer/grid-production/mrh_CSS_grid_fig_01-800w-opt.png

    (Посмотреть крупнее)

1. Напишите доступный HTML с логичной иерархической и семантической структурой

Одно из главных преимуществ использования CMS наподобие WordPress в том, что, как только вы создали доступные, семантичные и валидные шаблоны, вам не придется самим заботиться о структурных компонентах генерируемых HTML-документов. Взяв за основу проект _s, мы уже получаем доступный фундамент для дальнейшей надстройки, с самым минимумом интерактивных элементов, вроде небольшого скрипта, который добавляет клавиатурную навигацию для главного меню.

Из-за исторически сложившихся ограничений CSS в большинстве фреймворков типа _s элементы группируются «матрёшками» из вложенных контейнеров, чтобы облегчить разработчикам задачи типа размещения сайдбара в один ряд с основным контентом. На упрощенной схеме ниже видно, как див .site-content оборачивает .content-area и .widget-area, чтобы их можно было «флоатить» влево и вправо.

http://css-live.ru/Primer/grid-production/mrh_CSS_grid_fig_01-800w-opt.png

(Посмотреть крупнее)

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

Если сделать .page грид-контейнером, это сразу же превратит .site-header, .site-content и .site-footer в грид-элементы, но .site-main и .widget-area вложены внутрь этих контейнеров, и поэтому их нельзя сразу разместить в гриде.

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

Как объяснялось раньше, _s определяет контейнеры, единственная цель которых — использование старых CSS-приемов для раскладки и внешней обертки. Обычно такие контейнеры можно заметить визуально,потому что это просто дивы, отсюда название «диватоз».

Теперь, когда мы делаем раскладку на CSS-гридах, можно убрать некоторые их этих контейнеров, сделав структуру HTML более плоской и более чистой в плане семантической иерархии.

http://css-live.ru/Primer/grid-production/mrh_CSS_grid_fig_01-800w-opt.png

(Посмотреть крупнее)

На практике это значит, что можно удалить <div id="content" class="site-content"> из header.php (где он открывается) и footer.php (где он заканчивается), а также удалить <div class="content-area" id="primary">из archive.php, index.php, page.php, search.php и single.php. И у нас останется логическая иерархия контента, которую можно расположить в гриде.

<div id="page" class="site">
	<header id="masthead" class="site-header" role="banner"></header>
	<main id="main" class="site-main" role="main"></main>
	<aside id="secondary" class="widget-area" role="complementary"></aside>
	<footer id="colophon" class="site-footer" role="contentinfo"></footer>
</div>

2. Сделайте отзывчивую одноколоночную раскладку для всех размеров экрана

Перед добавлением новых стилей необходимо подчистить готовый CSS, который идет в комплекте с темой «из коробки». Тема _s предполагает, что мы будем размещать элементы в ряд с помощью флоатов, и пытается решить проблему «клиринга» контейнеров по принципу «чтобы уж наверняка», добавляя почти ко всем элементам clearfix. Такой подход добавляет в DOM (точнее, в дерево отрисовки — прим. перев.) невидимые псевдоэлементы, которые распознаются браузером и мешают и флексбоксам, и гридам. Если оставить эти правила, флексбоксы и гриды воспримут эти псевдоэлементы как флекс- и грид-элементы, из-за чего в раскладке визуально появятся лишние пустые ячейки. Самое быстрое решение — убрать эти CSS-правила совсем, удалив весь блок кода с клирингом, либо обернуть их в @supports или медиавыражение, чтобы они применялись только тогда, когда флексбоксы и гриды не используются. Если вам понадобится clearfix для конкретных элементов внутри макета, для этого должен быть специальный класс .clearfix , чтобы применять его когда нужно. Clearfix — это хак для обхода проблем с обтеканием и его отменой, и теперь, когда доступны флексбоксы и гриды, к нему нужно относиться как к изящной деградации.

Чтобы всем посетителям было удобно, применяйте стили ко всем элементам в документе, начиная с разумного минимума ширины окна, обычно с 320px.

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

http://css-live.ru/Primer/grid-production/mrh_CSS_grid_fig_01-800w-opt.png

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

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

Примечание: пара слов о браузерной поддержке

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

То, как вы к этому подойдете, зависит от вашей стратегии фолбэка в целом: если дизайн у вас требует, чтобы фолбэки появлялись при отсутствии поддержки гридов, решением вполне может быть просто объявить другое значение свойства display выше по каскаду. Грид переопределяет другие объявления свойства display, а не поддерживающие его браузеры будут довольствоваться теми объявлениями. У Рэйчел Эндрю есть подробное описание с примерами этого подхода. Можно также вообще не показывать CSS-правила браузерам без поддержки гридов с помощью @supports. В текущем примере проблема фолбэка решается тем, что все браузеры получают мобильную раскладку. Это значит, что мы применяем @supports для того, что я называю «прогрессивным улучшением выжженной земли». Отдаем всем браузерам базовый интерфейс, описанный выше, а раскладки на гридах — только тем браузерам, которые умеют с ними работать.

Для этого мы используем @supports по прямому назначению. Как и в случае медиавыражений, CSS, вложенный внутрь правила @supports, применится только если браузер поддерживает указанное свойство или возможность. Так можно прогрессивно улучшать CSS в зависимости от браузерной поддержки. Стоит также отметить, что @supports проверяет заявленную поддержку в браузере. И не гарантирует, что браузер действительно поддерживает возможность или следует спецификации.

В самой базовой форме проверка поддержки гридов будет выглядеть так: @supports (display: grid) {}.

Трудность возникает с Microsoft Edge, единственным современным браузером, который на момент выхода статьи всё ещё использует старую спецификацию гридов. Он возвращает true для @supports (display: grid) {}, несмотря на то, что поддержка гридов в нем неполная и нестандартная. Для нашего примера важнее всего отсутствие поддержки свойств grid-template-areas и grid-area, а также функции minmax(). В результате правило @supports, проверяющее только  display: grid, не исключит Microsoft Edge, и пользователи этого браузера получат битую раскладку. Чтобы решить эту проблему и отдавать гриды для Microsoft Edge только тогда, когда в нем появится полная поддержка спецификации, лучше проверяйте одно из неподдерживаемых свойств:

@supports (grid-area: auto) {}

Это в нынешних версиях Microsoft Edge возвращает false, и браузер не будет пытаться отрисовать CSS, который ему непонятен.

3. Добавляйте продвинутые раскладки и функциональность

С этого момента мы продолжаем подход «сначала мобильные» для всех правил:

  1. Начинаем с наименьшего размера окна.
  2. Увеличиваем ширину, пока всё не начнет выглядеть странно.
  3. Добавляем контрольную точку.
  4. Возвращаемся к шагу 2.

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

Раскладка структуры всей страницы (главный грид)

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

http://css-live.ru/Primer/grid-production/mrh_CSS_grid_fig_01-800w-opt.png

(Посмотреть крупнее)

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

@supports (grid-area: auto) {
	@media screen and (min-width: 56.25em) {
		.site {
			display: grid;
			grid-template-columns: 15em 1fr;
			grid-template-rows: 1fr minmax(1em, auto);
		}
	}
}

Чтобы легче понимать, что в гриде происходит, дадим имена разным частям грида с помощью grid-template-areas. Свойство grid-template-area дает возможность построить карту своего рода именованных прямоугольных областей в гриде, охватывающих одну и более ячеек. Как только такая область определена, грид-элемент можно привязать к ней с помощью свойства grid-area и имени области. В примере ниже свойство grid-template-area служит для «рисования» двухколоночной раскладки, определяя всю первую колонку как область header и деля вторую колонку на области main, sidebar и footer:

@supports (grid-area: auto) {
	@media screen and (min-width: $query__medium) {
		.site {
			display: grid;
			grid-template-columns: 15em 1fr;
			grid-template-rows: 1fr minmax(1em, auto);
			grid-template-areas: "header main"
						   "header sidebar"
			   			   "header footer";
		}
	}
}

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

@supports (grid-area: auto) {
	@media screen and (min-width: $query__medium) {
		.site {
			display: grid;
			grid-template-columns: 15em 1fr;
			grid-template-rows: 1fr minmax(1em, auto);
			grid-template-areas: "header main"
						   "header sidebar"
			   			   "header footer";
		}
		.site-header {
			grid-area: header;
		}
		.site-main {
			grid-area: main;
		}
		.widget-area {
			grid-area: sidebar;
		}
		.site-footer {
			grid-area: footer;
		}
	}
}

Для самых широких экранов будет своё медиавыражение. Здесь сайдбар занимает новую колонку по правой стороне грида. Для этого нужно изменить шаблон грида, чтобы поместить сайдбар в новую колонку. Поскольку сайдбар уже привязан к области шаблона «sidebar», нам нужно лишь изменить правило для .site:

@supports (grid-area: auto) {
	@media screen and (min-width: 56em) {
		.site {
			display: grid;
			grid-template-columns: 15em 1fr;
			grid-template-rows: 1fr minmax(1em, auto);
			grid-template-areas:
				"header main"
				"header sidebar"
			   	"header footer";

			@media screen and (min-width: 70em) {
				grid-template-columns: 15em 1fr 15em;
				grid-template-rows: 1fr minmax(1em, auto);
				grid-template-areas:
					"header main sidebar"
					"header footer footer";
			}
		}
		.site-header {
			grid-area: header;
		}
		.site-main {
			grid-area: main;
		}
		.widget-area {
			grid-area: sidebar;
		}
		.site-footer {
			grid-area: footer;
		}
	}
}

Используя @supports (grid-area: auto) { }, вы можете где угодно в файле создавать добавочные CSS-правила, которые сработают только если браузер поддерживает грид-раскладку.

Раскладка для архива записей

В WordPress к архивным страницам относятся главная страница блога, архивы по категориям, тегам, авторам и датам, а также страница результатов поиска. В теме _s они выводятся с помощью шаблонов index.php (главная блога), archive.php (архивы по категориям, тегам, авторам и датам) and search.php (результаты поиска). Другие шаблоны архивов можно добавить с помощью иерархии шаблонов.

Чтобы свести к минимуму необходимость в собственных CSS-правилах для каждого отдельно взятого архива, можно назначить свой класс элементу body для каждой архивной страницы с помощью фильтра для темы. Лучшее место для этого фильтра — inc/extras.php, рядом с подобными фильтрами. Можно не прописывать условия для всех возможных видов архивов, а пойти от противного: «Если эта страница не единичный элемент — т.е. не отдельная запись или статичная страница — то назначим элементу body класс .archive-view». Для этого в _s уже предусмотрено условие, так что нам надо просто добавить к нему дополнительный класс:

function mytheme_body_classes( $classes ) {

	// Добавляет классы hfeed и archive-view не-единичным страницам
	if ( ! is_singular() ) {
		$classes[] = 'hfeed archive-view';
	}
	return $classes;
}
add_filter( 'body_class', 'mytheme_body_classes' );

Теперь можно прицельно применять CSS-правила только для архивных страниц с помощью класса .archive-view.

http://css-live.ru/Primer/grid-production/mrh_CSS_grid_fig_01-800w-opt.png

(Посмотреть крупнее)

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

Записи — это отдельные элементы article, вложенные в раздел с классом .site-main. Это дает нам следующий SCSS:

@media screen and (min-width: $query__medium) {
	.archive-view {
		.site-main {
			display: grid;
			grid-template-columns: repeat(2, 1fr);

			@media screen and (min-width: $query__wide) {
				grid-template-columns: repeat(3, 1fr);
			}

			@media screen and (min-width: $query__x_wide) {
				grid-template-columns: repeat(4, 1fr);
			}

			@media screen and (min-width: $query__xx_wide) {
				grid-template-columns: repeat(5, 1fr);
			}
		}

		.entry-title {
			word-break: break-word;
		}
	}
}

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

http://css-live.ru/Primer/grid-production/mrh_CSS_grid_fig_01-800w-opt.png

(Посмотреть крупнее)

Если вам непременно нужны однопиксельные линии между ячейками, вы быстро обнаружите, что border или outline не подходят, поскольку линии будут перекрываться. Чтобы это обойти, можно задать 1px свойству grid-gap, добавив зазор в 1px между соседними ячейками по горизонтали и по вертикали, а затем установить для background-color цвет линий, а для background-color всех ячеек — белый цвет:

@media screen and (min-width: $query__medium) {
	.archive-view {
		.site-main {
			display: grid;
			grid-template-columns: repeat(2, 1fr);
			grid-gap: 1px;
			background: grey;

			@media screen and (min-width: $query__wide) {
				grid-template-columns: repeat(3, 1fr);
			}

			@media screen and (min-width: $query__x_wide) {
				grid-template-columns: repeat(4, 1fr);
			}

			@media screen and (min-width: $query__xx_wide) {
				grid-template-columns: repeat(5, 1fr);
			}
		}

		.entry-title {
			word-break: break-word;
		}

		.post {
			background: white;
		}
	}
}

(Прим. перев.: такой подход может дать не лучший результат, если грид-элементы заполнят грид не целиком, оставив пустое место в последнем ряду. Альтернативный вариант — обычный border в сочетании с тем же [code]grid-gap:1px[/code] и [code]margin:-1px[/code], чтобы рамки накладывались на зазор и сливались в одну линию.)

Чтобы грид был чуть динамичнее, по макету напрашивается, чтобы избранные элементы занимали две колонки. Для этого мы каждой избранной записи присваиваем категорию «Featured». WordPress автоматически присваивает элементу article каждой записи классы по схеме category-[название], а значит, мы можем выбрать эти записи с помощью селектора .archive-view .category-featured. Мы не определем явно, где именно в гриде будет каждый элемент, так что мы укажем с помощью ключевого слова span, сколько рядов или колонок этот элемент должен занимать, а браузер сам найдёт место, куда он сможет вписаться. Поскольку мы растягиваем элемент на две колонки, будем делать это только для тех раскладок, где колонок две и больше:

@media screen and (min-width: $query__medium) {
	.archive-view {
		.site-main {
			display: grid;
			grid-template-columns: repeat(2, 1fr);
			grid-gap: 1px;
			background: grey;

			@media screen and (min-width: $query__wide) {
				grid-template-columns: repeat(3, 1fr);
			}

			@media screen and (min-width: $query__x_wide) {
				grid-template-columns: repeat(4, 1fr);
			}

			@media screen and (min-width: $query__xx_wide) {
				grid-template-columns: repeat(5, 1fr);
			}
		}

		.entry-title {
			word-break: break-word;
		}
		.post {
			background: white;
		}

		.category-featured {
			grid-column: span 2;
		}
	}
}

http://css-live.ru/Primer/grid-production/mrh_CSS_grid_fig_01-800w-opt.png

(Посмотреть крупнее)

Раскладка отдельной записи или статичной страницы

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

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

body:not(.archive-view) {
	@supports (grid-area: auto) {
		@media screen and (min-width: $query__medium) {
			.site-main {
				display: grid;
				grid-template-columns: 1fr minmax(auto, 46em) 1fr;
				align-content: start;
				grid-template-areas:
					". post ."
					". nav ."
					". comments .";
			}
			.post {
				grid-area: post;
			}
			.post-navigation {
				grid-area: nav;
			}
			.comments-area {
				grid-area: comments;
			}
		}
	}
}

Затем давайте взглянем на саму запись. Здесь мы задаем четырехколоночный грид для класса .post:

.post {
	grid-area: post;
	display: grid;
	grid-template-columns: repeat(4, 1fr);
}

Теперь можно использовать CSS-гриды для создания динамической раскладки, которая меняет визуальный порядок и внешний вид заголовка и вспомогательной информации в зависимости от ширины окна:

http://css-live.ru/Primer/grid-production/mrh_CSS_grid_fig_01-800w-opt.png

(Посмотреть крупнее)

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

Основное правило: никогда не меняйте значения контента, перемещая его.

«Из коробки» у записи с картинкой иерархия следующая:

  1. Картинка
  2. Шапка записи: категории + заголовок + метаданные (т.е. автор, дата, количество комментариев)
  3. Контент

По макету, показанному на иллюстрации выше, на широких экранах нам нужна скорее такая визуальная структура:

  1. Шапка записи (категории + заголовок)
  2. Картинка
  3. Метаданные (автор, дата, количество комментариев)
  4. Контент

Чтобы этого добиться, нам придется перекроить еще немного вложенности, идущей в комплекте с _s. Как и раньше, мы получаем больше контроля над элементам, делая структуру HTML более плоской. В данном случае мы просто хотим вынести раздел с метаданными из шапки, чтобы он мог стать самостоятельным грид-элементом. Это делается в файле header.php:

<header class="entry-header">
	<?php
		if ( is_single() ) :
			the_title( '<h1 class="entry-title">', '</h1>' );
		else :
			the_title( '<h2 class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h2>' );
		endif;
	?>
	</header><!-- .entry-header -->

	<?php
	if ( 'post' === get_post_type() ) : ?>
		<div class="entry-meta">
			<?php kuhn_posted_on(); ?>
		</div><!-- .entry-meta -->
	<?php endif; ?>

Как и раньше, изменять раскладку можно с помощью grid-template-areas:

.post {
	grid-area: post;
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	grid-template-areas:
		"header header header header"
		"meta meta meta meta"
		"featimg featimg featimg featimg"
		"content content content content"
		"footer footer footer footer";
}

.entry-header {
	grid-area: header;
}

.entry-meta {
	grid-area: meta;
}

.featured-image {
	grid-area: featimg;
}

.entry-content {
	grid-area: content;
}

.entry-footer {
	grid-area: footer;
}

В нашем случае записям без картинки не нужны отдельные правила: область шаблона featimg просто схлопнется, потому что будет пуста. Однако, если использовать grid-gap для рядов, придется завести отдельное правило для .post, без featimg в grid-template-areas.

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

post {
	grid-area: post;
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	grid-template-areas:
		"header header header header"
		"meta meta meta meta"
		"featimg featimg featimg featimg"
		"content content content content"
		"footer footer footer footer";

	@media screen and (min-width: $query__wide) {
		grid-template-areas:
			"header header header header"
			"featimg featimg featimg featimg"
			"meta content content content"
			"footer footer footer footer";
	}
}

.entry-header {
	grid-area: header;
}

.entry-meta {
	grid-area: meta;
}

.featured-image {
	grid-area: featimg;
}

.entry-content {
	grid-area: content;
}

.entry-footer {
	grid-area: footer;
}

Пример из жизни

На этом месте вы, наверное, уже задались вопросом, как всё это могло бы выглядеть на реальном сайте. Вот ответ на этот вопрос. В ходе работы над этой статьей я создал бесплатную тему для WordPress под названием Kuhn, включив в нее описанные здесь раскладки и не только. Она уже работает на моем личном сайте, и вы можете просмотреть код, использовать эту тему для собственного сайта на WordPress, а также помочь улучшить ее на GitHub.

Заключение

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

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

Даже если вы работаете над проектами, требующими обратной совместимости, и считаете CSS-гриды чем-то слишком новым, всё равно начните включать их в свои проекты. Использование @supports и подход, который я наметил в этой статье, позволят вам прогрессивно улучшать существующие сайты, не вызывая проблем в старых браузерах. C CSS-гридами нужно думать по-новому, и уже сегодня нам всем пора начинать переучиваться. Так что вперед, смелее «огридивайте» веб!

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

2 комментария

  1. Как вы считаете, можно ли уже пользоваться гридами?
    В скором времени надо писать проект и хочется не задумываться о макете, о floatах и flexах с их ограничениями, а уже сразу лепить на гриде.

    Да, я видел статистику caniuse, но спрашиваю вас как практиков от реальной жизни. (не прошу писать в ответ статью, а так, пару предложений). Хром/лиса/сафари/адроидовские аналоги как переваривают?

    И вопрос по edge: в статье сказано, что у него ещё проблемы, вместе с тем, на caniuse сказано, что в 16-й версии будет поддержка. На сколько я знаю, осенью у винды выйдет обновление, вы не в курсе, будет ли обновление edge, и не тестировали ли вы грид в шеснадцатой версии edge?

  2. В начале раздела «Раскладка для архива записей» приведенный пример точно представлен в Javascript? По стилю именования функций и определения переменных это PHP.

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

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

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