Многоколоночные макеты
При вёрстке сайта, одной из первых задач верстальщика является создание основного шаблона.Основным шаблоном в данном случае называется вёрстка без контента - это совокупность шапки сайта, меню, футера и прочих элементов, которые встречаются на каждой странице.
Итак, попробуем сверстать простой макет сайта. Сверху у нас будет шапка сайта, слева будет навигация по разделу сайта, справа контент, а снизу футер.Стандартный шаблон, ничего необычного. Начнём с 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; }
Казалось бы, на этом можно закончить наш урок, но, если хорошо подумать, можно увидеть, как много проблем мы породили этим решением:
- Мы не можем жёстко зафиксировать ширину навигационного меню
- Если перед футером нам потребуется вставить какой-то блок, например, рекламный, вёрстка "поедет", ведь мы благополучно забудем про
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; }
Как мы видим, каким бы длинным ни был контент, под навигацией не образуется пробела, а так как больше нет флоатов, то перед футером можно вставить любой блок.К сожалению, таким способом мы не смогли решить последнюю проблему: как задать у меню фиксированную ширину, а ширина контента при этом была переменной?
Больше о 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' /* (3) Задаём названия областей */ 'nav content' 'footer footer'; } 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; }
Как можно заметить, мы избавились от всех негативных последствий. А теперь разберёмся подробнее, как это работает.
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); }
Таким образом мы избавились от проблемы фиксированной ширины меню. Благодаря функции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; }
Что тут сделано?
- Основной контейнер спозиционирован относительно, чтобы абсолютно-спозиционированные элементы выстраивались внутри него.
- Шапка и футер прижимаются к верхней и нижней части контейнера.
- Навигация прижимается к левой части контейнера.
- Чтобы блоки не налезали друг на друга, с помощью внутренних отступов у основного контейнера, отделим контент от остальных блоков.
- Так как теперь высота блока навигации зависит от высоты контента, добавляем свойство
overflow
, чтобы при недостаточной высоте навигации, внутри неё появлялся скроллбар.