Статьи

Редизайн сайта для использования CSS Grid Layout

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

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

Grid может сделать сторонние фреймворки, такие как 960gs или Bootstrap grid, избыточными, так как вы можете легко сделать все сами! Эта функция поддерживается всеми основными браузерами , хотя Internet Explorer реализует более старую версию спецификации.

Что мы собираемся построить

Итак, нас попросили создать типичный макет сайта с заголовком, областью основного контента, боковой панелью справа, списком спонсоров и нижним колонтитулом:

Начальная отправная точка

Другой разработчик уже пытался решить эту задачу и придумал решение, которое включает float, display: table и некоторые хаки для clearfix. Мы будем называть этот существующий макет «начальным»:

До недавнего времени поплавки считались лучшим вариантом для создания таких макетов. До этого нам приходилось использовать таблицы HTML, но у них был ряд недостатков. В частности, такая компоновка таблицы очень жесткая и требует большого количества тегов ( table , tr , td , th т. Д.), И семантически эти теги используются для представления данных таблицы, а не для разработки макетов.

Но CSS продолжает развиваться, и теперь у нас есть CSS Grid. Концептуально он похож на старый макет таблицы, но может использовать семантические элементы HTML с более гибким макетом.

Планирование сетки

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

  • .container — это глобальная оболочка с небольшими полями слева и справа.
  • .main-header — это заголовок, содержащий .logo (занимающий 20% пространства, плавающий влево) и .main-menu (занимающий 79% пространства, плавающий справа). Заголовок также имеет хакерское исправление для очистки поплавков.
  • .content-area-wrapper оборачивает основную .content-area (занимающую 66,6% пространства минус 1rem зарезервированное для поля, плавающего влево) и .sidebar (занимающую 33,3% пространства, плавающего справа). Сама оболочка также назначается с прозрачным.
  • .sponsors-wrapper содержит логотипы спонсоров. Внутри есть раздел .sponsors со свойством display установленным в table . Каждый спонсор, в свою очередь, отображается в виде ячейки таблицы.
  • .footer колонтитул является нашим нижним колонтитулом и занимает 100% пространства.

Наш новый макет будет очень похож на первоначальный, но с одним исключением: мы не будем добавлять .main-header и .content-area-wrapper потому что исправления больше не потребуются. Вот новая версия HTML:

 <div class="container"> <header class="logo"> <h1><a href="#">DemoSite</a></h1> </header> <nav class="main-menu"> <ul> <li class="main-menu__item"><a href="#">Our clients</a></li> <li class="main-menu__item"><a href="#">Products</a></li> <li class="main-menu__item"><a href="#">Contact</a></li> </ul> </nav> <main class="content-area"> <h2>Welcome!</h2> <p> Content </p> </main> <aside class="sidebar"> <h3>Additional stuff</h3> <ul> <li>Items</li> <li>Are</li> <li>Listed</li> <li>Here</li> <li>Wow!</li> </ul> </aside> <section class="sponsors-wrapper"> <h2>Our sponsors</h2> <section class="sponsors"> <figure class="sponsor"> <img src="https://via.placeholder.com/150x150"> </figure> <figure class="sponsor"> <img src="https://via.placeholder.com/200x150"> </figure> <figure class="sponsor"> <img src="https://via.placeholder.com/100x200"> </figure> <figure class="sponsor"> <img src="https://via.placeholder.com/100x100"> </figure> <figure class="sponsor"> <img src="https://via.placeholder.com/200x200"> </figure> </section> </section> <footer class="footer"> <p> &copy; 2018 DemoSite. White&amp;Sons LLC. All rights (perhaps) reserved. </p> </footer> </div> в <div class="container"> <header class="logo"> <h1><a href="#">DemoSite</a></h1> </header> <nav class="main-menu"> <ul> <li class="main-menu__item"><a href="#">Our clients</a></li> <li class="main-menu__item"><a href="#">Products</a></li> <li class="main-menu__item"><a href="#">Contact</a></li> </ul> </nav> <main class="content-area"> <h2>Welcome!</h2> <p> Content </p> </main> <aside class="sidebar"> <h3>Additional stuff</h3> <ul> <li>Items</li> <li>Are</li> <li>Listed</li> <li>Here</li> <li>Wow!</li> </ul> </aside> <section class="sponsors-wrapper"> <h2>Our sponsors</h2> <section class="sponsors"> <figure class="sponsor"> <img src="https://via.placeholder.com/150x150"> </figure> <figure class="sponsor"> <img src="https://via.placeholder.com/200x150"> </figure> <figure class="sponsor"> <img src="https://via.placeholder.com/100x200"> </figure> <figure class="sponsor"> <img src="https://via.placeholder.com/100x100"> </figure> <figure class="sponsor"> <img src="https://via.placeholder.com/200x200"> </figure> </section> </section> <footer class="footer"> <p> &copy; 2018 DemoSite. White&amp;Sons LLC. All rights (perhaps) reserved. </p> </footer> </div> в <div class="container"> <header class="logo"> <h1><a href="#">DemoSite</a></h1> </header> <nav class="main-menu"> <ul> <li class="main-menu__item"><a href="#">Our clients</a></li> <li class="main-menu__item"><a href="#">Products</a></li> <li class="main-menu__item"><a href="#">Contact</a></li> </ul> </nav> <main class="content-area"> <h2>Welcome!</h2> <p> Content </p> </main> <aside class="sidebar"> <h3>Additional stuff</h3> <ul> <li>Items</li> <li>Are</li> <li>Listed</li> <li>Here</li> <li>Wow!</li> </ul> </aside> <section class="sponsors-wrapper"> <h2>Our sponsors</h2> <section class="sponsors"> <figure class="sponsor"> <img src="https://via.placeholder.com/150x150"> </figure> <figure class="sponsor"> <img src="https://via.placeholder.com/200x150"> </figure> <figure class="sponsor"> <img src="https://via.placeholder.com/100x200"> </figure> <figure class="sponsor"> <img src="https://via.placeholder.com/100x100"> </figure> <figure class="sponsor"> <img src="https://via.placeholder.com/200x200"> </figure> </section> </section> <footer class="footer"> <p> &copy; 2018 DemoSite. White&amp;Sons LLC. All rights (perhaps) reserved. </p> </footer> </div> 

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

  1. логотип
  2. Меню
  3. Основное содержание
  4. Боковая панель
  5. Спонсоры
  6. нижний колонтитул

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

Расположение решетчатой ​​колонны

Итак, я предлагаю иметь три столбца (выделены красным) и четыре строки (выделены синим цветом). Некоторые области, такие как логотип, будут занимать только один столбец, тогда как другие, например основной контент, будут занимать несколько столбцов. Позже мы можем легко изменить макет, переместить области или добавить новые.

Следуя схеме, дайте каждой области уникальное имя. Они будут использоваться в макете, определенном ниже:

 .logo { grid-area: logo; } .main-menu { grid-area: menu; } .content-area { grid-area: content; } .sidebar { grid-area: sidebar; } .sponsors-wrapper { grid-area: sponsors; } .footer { grid-area: footer; } 

Теперь установите для свойства display значение grid , определите три столбца и добавьте небольшие поля слева и справа от основного контейнера:

 .container { display: grid; margin: 0 2rem; grid-template-columns: 2fr 6fr 4fr; } 

display: grid определяет контейнер grid и устанавливает специальный контекст форматирования для его дочерних элементов. fr — это специальная единица, которая означает «долю свободного пространства контейнера сетки». 2 + 6 + 4 дает нам 12 , а 6 / 12 = 0.5 . Это означает, что средняя колонка будет занимать 50% свободного пространства.

Я также хотел бы добавить некоторый интервал между строками и столбцами:

 .container { // ... grid-gap: 2rem 1rem; } 

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

 * { box-sizing: border-box; } html { font-size: 16px; font-family: Georgia, serif; } body { background-color: #fbfbfb; } h1, h2, h3 { margin-top: 0; } header h1 { margin: 0; } main p { margin-bottom: 0; } 

Хорошо! Теперь мы можем перейти к первой цели, которая будет заголовком.

Проектирование Заголовка

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

 .main-header { height: 3rem; } 

Также обратите внимание, что логотип и меню выровнены по центру по вертикали, что достигается с помощью трюка с line-height :

 .logo { // ... height: 100%; line-height: 3rem; } 

С CSS Grid, однако, все будет проще: нам не понадобятся CSS-хаки.

Начнем с определения первого ряда:

 .container { // ... grid-template-rows: 3rem; } 

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

 .container { // ... grid-template-areas: "logo menu menu"; } 

Что тут происходит? Ну, говоря logo только один раз, мы убеждаемся, что он занимает только один — самый левый столбец. menu menu означает, что меню занимает два столбца: средний и самый правый. Посмотрите, насколько просто это правило!

Теперь выровняйте логотип по оси Y:

 .logo { grid-area: logo; align-self: center; } 

Меню должно быть отцентрировано по вертикали и повернуто вправо:

 .main-menu { grid-area: menu; align-self: center; justify-self: end; } 

Наше меню построено с тегами ul и li , поэтому давайте немного их стилизуем, удалив маркеры, обнуляя поля / отступы и установив меню в гибкий контейнер:

 .main-menu ul { margin: 0; padding: 0; display: flex; } .main-menu__item { list-style-type: none; padding: 0; font-size: 1.1rem; margin-right: 0.5rem; } .main-menu .main-menu__item:last-of-type { margin-right: 0; } 

Вот и все. Чтобы понаблюдать за результатом, я собираюсь использовать Firefox с удобным инструментом подсветки CSS Grid. (Существуют аналогичные инструменты для других браузеров: например, Gridman для Chrome.) Чтобы получить доступ к этому инструменту, нажмите F12 и выберите элемент .container , который должен иметь метку grid :

Элемент с меткой сетки

После этого перейдите на вкладку «Правила CSS» и найдите свойство display: grid . Нажав на маленький значок рядом со значением grid , вы можете включить или отключить подсветку:

Значок сетки

Вот результат:

Подсветка сетки в действии

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

Настройка вывода раздела Layout

Итак, мы рассмотрели заголовок, поэтому давайте перейдем к основной области содержимого и боковой панели.

Основное содержание и боковая панель

Наша основная область содержимого должна занимать две колонки, тогда как боковая панель должна занимать только одну. Что касается строки, я бы хотел, чтобы ее высота была установлена ​​автоматически. Мы можем обновить сетку .container соответствующим образом:

 .container { // ... grid-template-rows: 3rem auto; grid-template-areas: "logo menu menu" "content content sidebar"; } 

Я хотел бы добавить отступы для боковой панели, чтобы придать ей больше визуального пространства:

 .sidebar { grid-area: sidebar; padding: 1rem; } 

Вот результат, который можно увидеть в инструменте Grid Firefox:

Результат компоновки контейнера

Спонсоры

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

В первоначальном макете этот блок стилизован с помощью display: table , но мы не будем полагаться на него. На самом деле, секция спонсоров может быть отличным кандидатом для применения CSS-сетки!

Прежде всего, настройте области grid-template-areas чтобы включить область sponsors :

 .container { // ... grid-template-areas: "logo menu menu" "content content sidebar" "sponsors sponsors sponsors" } 

Теперь также .sponsors секцию .sponsors в сетку:

 .sponsors { display: grid; } 

Пока нам нужно пять элементов с одинаковой шириной, можно использовать функцию repeat для определения столбцов:

 .sponsors { display: grid; grid-template-columns: repeat(5, 1fr); } 

Что касается ряда, его высота должна быть установлена ​​автоматически. Разрыв между столбцами должен быть равен 1rem :

 .sponsors { display: grid; grid-template-columns: repeat(5, 1fr); grid-template-rows: auto; grid-column-gap: 1rem; } 

Стиль каждого элемента:

 .sponsor { margin-left: 0; margin-right: 0; background-color: #fff; border-radius: 0.625rem; } 

Вот промежуточный результат:

Спонсорский раздел прогресса

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

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

 .sponsor { place-self: center; } 

place-self выравнивает элемент по осям X и Y. Это сокращенное свойство для align-self и justify-self .

Изображения действительно будут выровнены, но, к сожалению, белый фон исчез. Это потому, что каждый .sponsor теперь имеет ширину и высоту, равные размерам изображения:

Результаты размещения самостоятельно

Это означает, что здесь нужен другой подход, и одним из возможных решений является использование Flexbox:

 .sponsor { // ... display: inline-flex; align-items: center; justify-content: center; } 

Теперь все отображается правильно, и теперь мы знаем, что Grid прекрасно работает с Flexbox:

Спонсор макет с использованием flexbox

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

 .container { // ... grid-template-areas: "logo menu menu" "content content sidebar" "sponsors sponsors sponsors" "footer footer footer"; } 

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

Создание адаптивного макета

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

Большие экраны

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

 @media all and (max-width: 992px) { .container { margin: 0 1rem; } .sponsors { grid-column-gap: 0.5rem; } } 

Средние экраны

На средних экранах мне бы хотелось, чтобы основная область контента и боковая панель занимали все три столбца:

 @media all and (max-width: 768px) { .container { grid-template-areas: "logo menu menu" "content content content" "sidebar sidebar sidebar" "sponsors sponsors sponsors" "footer footer footer"; } } 

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

 @media all and (max-width: 768px) { // ... html { font-size: 14px; } .sponsors { grid-template-columns: 1fr; grid-column-gap: 0; grid-row-gap: 1rem; } } 

Вот так выглядит макет на средних экранах:

Просмотр макета на средних экранах

Маленькие экраны

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

 @media all and (max-width: 540px) { .container { grid-template-columns: 1fr; grid-template-rows: auto; grid-template-areas: "logo" "menu" "content" "sidebar" "sponsors" "footer"; } } 

В этом случае меню не должно быть смещено вправо, и нам также не нужен промежуток между столбцами:

 @media all and (max-width: 540px) { .container { // ... grid-gap: 2rem 0; } .main-menu { justify-self: start; } } 

Работа выполнена:

Эленец укладывает в мобильный вид

Обратите внимание, что вы можете даже легко переставить элементы сетки для различных экранов. Предположим, мы хотим разместить меню внизу на маленьких экранах (чтобы посетителям не приходилось прокручивать страницу после того, как они закончили читать материал на странице). Чтобы сделать это, просто настройте grid-template-areas :

 @media all and (max-width: 540px) { .container { // ... grid-template-areas: "logo" "content" "sidebar" "sponsors" "footer" "menu"; } } 

Обойтись без медиа-запросов

Стоит отметить, что мы можем заставить спонсоров блокировать отзывчивость без каких-либо медиа-запросов вообще. Это возможно с помощью свойства minmax функции minmax . Чтобы увидеть их в действии, .sponsors стили для .sponsors следующим образом:

 .sponsors { // ... grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); } 

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

auto-fill означает «заполнить строку как можно большим количеством столбцов». Если для столбца недостаточно места, он будет помещен на следующую строку.

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

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

Спонсоры блокируют макет, используя автозаполнение вместо медиа-запросов

откаты

К сожалению, CSS Grid еще не полностью поддерживается всеми браузерами, и вы можете догадаться, какой из них все еще реализует более старую версию спецификации. Да, это Internet Explorer 10 и 11. Если вы откроете демонстрацию в этих браузерах, вы увидите, что сетка не работает вообще, а области просто сложены:

Макет разделов сложен в IE

Конечно, это еще не конец света, так как сайт еще можно использовать, но давайте добавим хотя бы некоторые запасные правила. Хорошей новостью является то, что если элемент является плавающим, а также ему назначена сетка, эта сетка имеет приоритет Кроме того, display , vertical-align и некоторые другие свойства также не влияют на элементы сетки , поэтому давайте воспользуемся этим фактом.

Сложенное меню выглядит хорошо, как есть, но боковая панель, вероятно, должна располагаться рядом с основным содержимым, а не под ним. Мы можем добиться этого, используя display: inline-block :

 .content-area { display: inline-block; vertical-align: top; } .sidebar { display: inline-block; vertical-align: top; } 

Во всех браузерах, которые поддерживают grid, эти свойства не будут иметь никакого эффекта, но в IE они будут применены, как и ожидалось. Еще одно свойство, которое нам нужно настроить, это width :

 .content-area { width: 69%; display: inline-block; vertical-align: top; } .sidebar { width: 30%; display: inline-block; vertical-align: top; } 

Но добавив эти стили, наш макет сетки теперь будет выглядеть намного хуже, потому что свойство width не игнорируется элементами сетки. Это можно исправить с помощью CSS-запроса @supports . IE не понимает эти запросы , но в этом нет необходимости: мы будем использовать его для исправления сетки!

 @supports (display: grid) { .content-area, .sidebar { width: auto; } } 

Теперь давайте позаботимся о спонсорских товарах и добавим верхнее поле для каждого блока:

 .sponsor { vertical-align: middle; } .main-menu, .content-area, .sidebar, .sponsors-wrapper, .footer { margin-top: 2rem; } 

Нам не нужен верхний край, когда сетка поддерживается, поэтому @supports его внутри запроса @supports :

 @supports (display: grid) { // ... .main-menu, .content-area, .sidebar, .sponsors-wrapper, .footer, .sponsor { margin-top: 0; } } 

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

 @media all and (max-width: 760px) { .content-area, .sidebar { display: block; width: 100%; } .sponsor { width: 100%; margin-top: 1rem; } } 

Не забудьте исправить ширину спонсора для браузеров, которые поддерживают сетку:

 @supports (display: grid) { // .. .sponsor { width: auto; } } 

Вот как теперь выглядит макет в Internet Explorer:

Окончательный макет в Internet Explorer

Вы можете просмотреть окончательный результат на CodePen:

Вывод

В этой статье мы увидели CSS Grid в действии и использовали его для перепроектирования существующего макета с плавающей точкой. Сравнивая эти два решения, мы видим, что HTML и CSS-код решения «grid» меньше (конечно, не считая запасных вариантов), проще и выразительнее. С помощью свойства grid-template-areas легко понять, как размечены отдельные области, и мы можем быстро изменить их расположение или изменить их размеры. Кроме того, нам не нужно полагаться на различные хитрые трюки, такие как clearfix.

Итак, как вы видите, CSS Grid — отличная альтернатива float, и он очень готов к работе. Возможно, вам придется предоставить некоторые резервные правила для Internet Explorer (который реализует более старую версию спецификации), но, как вы видели, они не очень сложны, и в целом сайт по-прежнему можно использовать даже без какой-либо обратной совместимости при все.

Вы уже пробовали создавать сайты с помощью CSS Grid? Какие у вас впечатления? Поделитесь своими мыслями в комментариях!