Многоколоночные макеты
При вёрстке сайта, одной из первых задач верстальщика является создание основного шаблона.Основным шаблоном в данном случае называется вёрстка без контента - это совокупность шапки сайта, меню, футера и прочих элементов, которые встречаются на каждой странице.
Итак, попробуем сверстать простой макет сайта. Сверху у нас будет шапка сайта, слева будет навигация по разделу сайта, справа контент, а снизу футер.Стандартный шаблон, ничего необычного. Начнём с 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, чтобы при недостаточной высоте навигации, внутри неё появлялся скроллбар.