Найти в Дзене
Практика HTML

CSS: Многоколоночные макеты

Оглавление

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

Итак, попробуем сверстать простой макет сайта. Сверху у нас будет шапка сайта, слева будет навигация по разделу сайта, справа контент, а снизу футер. Стандартный шаблон, ничего необычного. Начнём с HTML.

<div class="main-container">
<header>Header</header>
<nav>Site navigation</nav>
<main>Site content</main>
<footer>Footer</footer>
</div>

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

Float

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

.main-container {
margin: 0 auto;
max-width: 800px;
}
header {
height: 50px;
background: cornflowerblue;
}
nav {
height: 80px;
background: darksalmon;
width: 20%; /* Задаём ширину блока навигации */
float: left; /* Устанавливаем обтекание */
}
main {
height: 120px;
background: khaki;
width: 80%; /* Задаём ширину контента */
float: left; /* Устанавливаем обтекание */
}
footer {
clear: both; /* Сбрасываем обтекание */
height: 50px;
background: darkseagreen;
}

Взглянуть на полученный результат можно здесь:
https://codepen.io/artik-man/pen/GRKBqye

Казалось бы, на этом можно закончить наш урок, но, если хорошо подумать, можно увидеть, как много проблем мы породили этим решением:

  • Мы не можем жёстко зафиксировать ширину навигационного меню
  • Если перед футером нам потребуется вставить какой-то блок, например, рекламный, вёрстка "поедет", ведь мы благополучно забудем про clear: both;
  • Высота навигации никак не зависит от высоты контента и наоборот. Под более коротким блоком будет пустота.

Подробнее о float читайте тут: float

Flex

Рассмотрим более современный способ. Мы можем использовать display:flex; у .main-container, тогда мы сможем избавиться от пары недостатков предыдущего примера.

.main-container {
margin: 0 auto;
max-width: 800px;
display: flex; /* Объявляем контейнер флексом */
align-items: stretch; /* Высота элементов должна подстраиваться по высоте самого высокого элемента */
flex-wrap: wrap; /* Если не хватает места в строке, переносить блок на следующую */
}
header {
width: 100%; /* Обязательно задаём ширину для шапки */
height: 50px;
background: cornflowerblue;
}
nav {
background: darksalmon;
width: 20%; /* Задаём ширину навигационного меню */
}
main {
height: 120px;
background: khaki;
width: 80%; /* Задаём ширину контента */
}
footer {
width: 100%; /* Обязательно задаём ширину для футера */
height: 50px;
background: darkseagreen;
}

-2

Получившийся результат посмотрите тут:
https://codepen.io/artik-man/pen/LYPBZdm

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

Больше о flex здесь:

Grid

Самым современным способом вёрстки макетов на сегодняшний день является т.н. Grid layout. Грид позволяет выстраивать элементы внутри себя по заранее заданной сетке. Для начала разберём пример, а затем разберёмся подробнее, как это работает.

.main-container {
margin: 0 auto;
max-width: 800px;
display: grid; /* Объявляем контейнер гридом */
grid-template-rows: 50px 1fr 50px; /* (1) Задаём строки*/
grid-template-columns: 200px 1fr; /* (2) Задаём колонки*/
grid-template-areas: 'header header'
'nav content'
'footer footer';
/* (3) Задаём области*/
}
header {
grid-area: header; /* Шапка займёт область с названием header */
background: cornflowerblue;
}
nav {
background: darksalmon;
grid-area: nav; /* Навигация займет область nav */
}
main {
height: 120px;
background: khaki;
grid-area: content; /* Контент займёт content */
}
footer {
grid-area: footer; /* Футер - footer */
background: darkseagreen;
}

-3

Результат тут:
https://codepen.io/artik-man/pen/KKPBMRz

Как можно заметить, мы избавились от всех негативных последствий. А теперь разберёмся подробнее, как это работает.

  • grid-template-rows: 50px 1fr 50px означает, что если смотреть на сайт по вертикали, то у нас образуются три строки: шапка, навигация с контентом, футер. Высоту первой строки, шапки, установим равной 50px, высота второй строки нам неизвестна, а высота третьей, футера, тоже 50px.
  • grid-template-columns: 200px 1fr означает, что если смотреть на сайт по горизонтали, то образуются два столбца: слева навигация, справа контент. Ширину навигации установим равной 200px, а ширина контента нам неизвестна и она займёт всё доступное пространство.
  • Итак, на этом этапе мы поняли, что у нас будет три строки и два столбца. Это и указываем далее:
    grid-template-areas:
    'header header'
    'nav content'
    'footer footer'
    .
    Этот код создаёт три строки и два столбца, состоящие из именованных областей. Именовать эти области можно как угодно, их названия будут указаны в дочерних элементах в свойстве
    grid-area. Здесь мы видим, что шапка займёт две колонки; навигация - одну, левую колонку; контент - одну правую; футер - две колонки.

Таким образом, мы получили идеальную сетку для нашего сайта. Подробнее о grid layout читать здесь:

Calc

А теперь настало время удивляться. Вернёмся к примеру с флексом и добавим еще немного CSS:

nav {
width: 200px;
}
main {
width: calc(100% - 200px);
}

-4

Результат: https://codepen.io/artik-man/pen/mdbjELo

Таким образом мы избавились от проблемы фиксированной ширины меню. Благодаря функции calc(), мы заставили ширину контента зависеть от ширины блока навигации. О calc() можно почитать здесь

Ещё один вариант вёрстки шаблона

На самом деле, есть еще один вариант. Он сложный и ненадёжный, но для общего развития, стоит упомянуть и его.

.main-container {
margin: 0 auto;
max-width: 800px;
position: relative;
padding: 50px 0 50px 200px;
box-sizing: border-box;
}
header {
position: absolute;
top: 0;
right: 0;
left: 0;
height: 50px;
background: cornflowerblue;
}
nav {
background: darksalmon;
position: absolute;
top: 50px;
bottom: 50px;
left: 0;
width: 200px;
overflow-y: auto;
}
main {
height: 120px;
background: khaki;
width: 100%;
}
footer {
position: absolute;
bottom: 0;
right: 0;
left: 0;
height: 50px;
background: darkseagreen;
}
-5

Результат здесь:
https://codepen.io/artik-man/pen/ExYpyRb

Что тут сделано?

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

Таким образом, мы рассмотрели несколько способов вёрстки многоклоночных макетов. Каждый имеет свои достоинства и недостатки, а применять их нужно по ситуации. К примеру, макетом на grid не стоит пользоваться, если на вашем проекте подразумевается поддержка Internet Explorer 10 и старше.

Эту и другие статьи можно почитать в моём практическом руководстве HTML Practice: https://artik-man.github.io/HTML-Practice/ Если у вас возникли идеи для новой главы этой книги, присылайте issue на GitHub: https://github.com/Artik-Man/HTML-Practice/issues