Макет «Святой Грааль» при помощи CSS Grid


Данный материал является вольным переводом статьи:
Ire Aderinokun The Holy Grail Layout with CSS Grid

Материал вычитывал: Михаил Синяков

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

CSS Grid Layout реально сложен, даже больше, чем Flexbox. Он имеет 17 новых свойств и вводит множество новых концепций на всем пути написания CSS. В попытке понять новую спецификацию, я использовала модуль для создания макета «Святой Грааль».

Что такое макет «Святой Грааль»?

Святой Грааль это макет, который состоит из четырех разделов — header, footer, основное содержимое и две боковых колонки, по одной с каждой стороны. Макет так же придерживается следующих правил:

  • «Плавающая» ширина центральной части и фиксированная ширина сайдбаров
  • Центральная часть в разметке должна идти раньше, чем два сайдбара (но после header’а)
  • Все три колонки должны быть одинаковой высоты, вне зависимости от содержимого
  • Футер должен быть всегда прижат к низу, даже если контент не заполняет вьюпорт
  • Макет должен быть отзывчивым, все разделы должны схлопываться в один столбец на маленьких экранах

Сделать такое при помощи обычного CSS без хаков довольно сложно.

Решение с использованием CSS Grid

Вот такое решение я придумала используя CSS Grid. Во-первых, разметка:


<body class="hg">  
<header class="hg__header">Title</header>
<main class="hg__main">Content</main>
<aside class="hg__left">Menu</aside>
<aside class="hg__right">Ads</aside>
<footer class="hg__footer">Footer</footer>
</body>

И CSS, всего 31 строка!


.hg__header { grid-area: header; }
.hg__footer { grid-area: footer; }
.hg__main { grid-area: main; }
.hg__left { grid-area: navigation; }
.hg__right { grid-area: ads; }

.hg {
    display: grid;
    grid-template-areas: "header header header"
                         "navigation main ads"
                         "footer footer footer";
    grid-template-columns: 150px 1fr 150px;
    grid-template-rows: 100px 
                        1fr
                        30px;
    min-height: 100vh;
}

@media screen and (max-width: 600px) {
    .hg {
        grid-template-areas: "header"
                             "navigation"
                             "main"
                             "ads"
                             "footer";
        grid-template-columns: 100%;
        grid-template-rows: 100px 
                            50px 
                            1fr
                            50px 
                            30px;
    }
}

Разбор

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

  • grid-area
  • grid-template-areas
  • grid-template-columns
  • grid-template-rows

Мое решение, по созданию макета «Святой Грааль» при помощи CSS Grid можно разбить на пять шагов.

1. Определение сетки

Первое, что мы хотим сделать, это определить области сетки, к которым мы можем обратиться через псевдоним. Делается это при помощи свойства grid-area.


.hg__header { grid-area: header; }
.hg__footer { grid-area: footer; }
.hg__main { grid-area: main; }
.hg__left { grid-area: navigation; }
.hg__right { grid-area: ads; }

Затем, используя свойство grid-template-areas мы можем расположить элементы на сетке интуитивным и визуальным способом. Свойство grid-template-areas принимает список из строк разделенных пробелами. Каждая строчка представляет собой ряд. В каждой строке, у нас есть список областей сетки разделенных пробелами. Каждая область сетки занимает один столбец. Так что, если мы хотим, чтобы область охватила два столбца мы определяем ее дважды.

В макете «Святой Грааль» у нас есть 3 столбца и 3 ряда. Header и footer занимают 3 колонки, в то время как другие области охватывают по 1 колонке каждый.


.hg {
    display: grid;
    grid-template-areas: "header header header"
                         "navigation main ads"
                         "footer footer footer";
}

С помощью этой разметки мы получим следующий результат.

2. Определение ширины столбцов

Далее, мы хотим определить ширину столбцов. Она определяется при помощи свойства grid-template-columns. Это свойство принимает разделенный пробелами список. Поскольку у нас 3 колонки, то и ширину мы определяем 3 раза.


grid-template-columns: [column 1 width]  [column 2 width]  [column 3 width];

В макете «Святой Грааль» мы хотим видеть 2 сайдбара по 150 пикселей каждый.


.hg {
  grid-template-columns: 150px  [column 2 width] 150px;
}

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


.hg {
    grid-template-columns: 150px 1fr 150px;
}

Сейчас наш макет выглядит следующим образом.

3. Определение высоты рядов

Теперь нам нужно определить высоту рядов. Подобно тому, как мы определяем ширину столбцов при помощи grid-template-columns, мы определяем высоту при помощи grid-template-rows. Это свойство принимает разделенный пробелами список содержащий высоту для каждого ряда в нашей сетке. Хотя мы можем записать его на одной строке, я думаю, лучше и визуально более понятно, будет написать по одному ряду в строку.


.hg {
    grid-template-rows: 100px 
                        1fr
                        30px;
}

Таким образом, высота header будет равняться 100px, высота footer 30, а средний ряд (основное содержимое и две боковые панели) займет оставшуюся свободную часть.

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


.hg {
    min-height: 100vh;
}

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

5. Делаем макет отзывчивым

И, наконец, мы хотим сделать макет отзывчивым. На небольших устройствах все элементы сетки должны отображаться в одном столбце, один за другим. Для этого нам необходимо переопределить 3 свойства, которые мы определили ранее grid-template-areas, grid-template-columns и grid-template-rows.

Во-первых, мы хотим чтобы все элементы в сетке были в одном столбце в определенном порядке.


@media screen and (max-width: 600px) {
    .hg {
        grid-template-areas: "header"
                             "navigation"
                             "main"
                             "ads"
                             "footer";
    }
}

Далее, мы хотим чтобы все элементы растянулись на всю ширину сетки.


@media screen and (max-width: 600px) {
    .hg {
        grid-template-columns: 100%;
    }
}

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


@media screen and (max-width: 600px) {
    .hg {
        grid-template-rows: 100px /* Header */
                            50px /* Navigation */
                            1fr /* Main Content */
                            50px /* Ads */
                            30px; /* Footer */
    }
}

Вот и все! Вы можете посмотреть демо по этой ссылке, а так же исходники.

Поддержка браузерами

Материалы по теме