Верстка макета сайта

В настоящее время при создании отзывчивого (англ. responsive), то есть подстраивающегося под ширину окна, макета веб-страницы не так часто используют проценты, как было показано в конце прошлого урока. Это связано с тем, что современные мониторы достаточно большие. Если контент распределяется по всей доступной ширине, воспринимать его может быть неудобно. Особенно это актуально для сайтов, у которых текстовый контент является основным.

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

В этом уроке рассмотрим пример процесса верстки отзывчивого макета для сайта одним из способов (есть и другие подходы).

Пусть шаблон содержит всего четыре семантических блока: шапку вверху (header), статью в центральной области (article), меню слева (nav), подвал внизу (footer).

Без таблицы стилей каждый следующий семантический элемент-блок размещается под предыдущим.

Примечание: адрес ../logo.png в элементе img означает, что изображение находится в каталоге на уровень выше. Если файл находится в том же каталоге, что index.html, в атрибуте src указывают просто его имя.

Когда создают сайты, то общие таблицы стилей, которые используются на всех страницах сайта, добавляют в отдельные файлы с расширением .css. К документам HTML их подключают с помощью тега link. Добавим перед закрывающим тегом </head> следующий элемент:

<link rel="stylesheet" href="style.css">

В том же каталоге, где находится index.html, создадим файл style.css. В него будем записывать правила таблицы стилей. При этом обрамлять их в контейнер <style></style> здесь не надо. Атрибут rel="stylesheet" в элементе link подскажет интерпретатору html-документа, что содержимое файла style.css написано на языке CSS.

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

body {
  font-size: 1.3em;
  margin: 0;
  background: Grey;
}

header {
  height: 46px;
  padding: 2px;
  background: LightGrey;
}
header span {
  font-size: 28px;
}
header img {
  padding: 0 10px;
  vertical-align: -12px;
}

nav {
  background: #F0F0F0;
}

article {
  max-width: 810px;
  margin: 0 auto;
  padding: 5px 15px 20px;
  background: WhiteSmoke;
}

footer {
  max-width: 840px;
  margin: 20px auto;
  text-align: center;
  color: WhiteSmoke;
} 

На следующем шаге оформим ссылки в блоке навигации и в правило для nav добавим объявления, которые разместят блок с левой стороны:

nav {
  position: fixed;
  top: 50px;
  bottom: 0;
  width: 280px;
  padding: 20px 0;
  overflow: auto;
  background: #F0F0F0;
}
nav a {
  display: block;
  padding: 10px; padding-left: 15px;
  text-decoration: none;
  color: DarkSlateGrey;
}
nav a:hover {
  background: LightGrey;
}

С помощью значения fixed свойства position мы фиксируем сайдбар (боковую панель, роль которой в нашем случае играет элемент nav) в определенном месте окна просмотра (англ. viewport). В результате этого при проктутке (скроллинге) страницы сайдбар будет оставаться в одном и том же месте окна, то есть не будет прокручиваться вместе с остальным контентом.

Свойства top и bottom используются совместно с position и после него. Здесь мы отступаем сверху 50 пикселей и снизу 0, то есть растягиваем блок до самого низа окна.

Если мы сделаем статью подлиннее и начнем прокручивать вниз, то увидим такую картину:

Шапка сайта вместе со статьей уходят за пределы окна просмотра. Поскольку мы зафиксировали nav с отступом в 50 пикселей сверху, то над ним появляется пустота.

Используя JavaScript, можно отслеживать скроллинг страницы и менять значение свойства динамически, в данном случае сводить top к нулю, что заставит блок занимать всю высоту окна. Однако поступим проще, зафиксировав заголовок сайта. Изменим правило для header:

header {
  position: fixed;
  width: 100%;
  height: 46px;
  padding: 2px;
  background: LightGrey;
}

Фиксированные блоки размещаются на своих собственных слоях (слои накладываются друг на друга как стопка листов). Поэтому место, которое занимает fixed-блок, не учитывается при позиционировании других. В результате, когда header фиксируется, статья поднимается к самому верху окна.

Чтобы исправить ситуацию, подкорректируем свойство padding статьи, добавив к отступу сверху 50 единиц. Было: padding: 5px 15px 20px;. Стало:

padding: 55px 15px 20px;

Обратим внимание на объявление overflow: auto в правиле nav. Благодаря ему, если содержимое не будет помещаться в блок, то у блока появится полоса прокрутки. Иначе вышедшее за пределы блока содержимое было бы просто недоступно.

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

При этом справа остается пустое пространство. Хорошо бы, чтобы статья, приблизившись к сайдбару, перестала центрироваться по горизонтали (margin: 0 auto). Вместо этого обзавелась бы полем слева (margin-left: 280px), равным ширине nav или чуть больше.

Другими словами, нам надо менять значение свойства в зависимости от размеров окна. В данном случае использовать JavaScript не требуется. В CSS есть так называемые медиа запросы, с помощью которых можно менять свойства элементов, отслеживая в том числе ширину окна просмотра. Правила в запросах @media применяются после основных.

Сначала надо определить, в какой момент свойство должно меняться. Если ширина статьи 840px, сайдбара – 280px, то минимальная ширина окна, когда центрированная статья не заходит за сайдбар будет составлять 840 + 280*2 = 1400 пикселей. Значит, начиная с ширины как минимум 1399px, значение свойства должно быть другим. Добавляем в таблицу стилей новое правило, заключив его в запрос @media:

@media (max-width: 1399px) {
  article, footer {
    margin-left: 280px;
  }
}

Условие max-width: 1399px означает срабатывание вложенных правил для вьюпортов, которые не превышают указанную ширину, то есть меньше нее или равны ей. Другими словами, устанавливается максимальный предел.

При расширении окна, когда условие max-width: 1399px не соблюдается, статья и футер обратно вернутся к своему основному правилу, то есть окажутся в центре.

Если мы сильно сузим окно, то статья чрезмерно сожмется.

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

  1. При размере окна меньше N пикселей сайдбар должен быть убран.
  2. При размере окна меньше N пикселей должна появляться кнопка.
  3. При нажатии на кнопку должен появляться сайдбар.
  4. При нажатии куда-нибудь еще (например, другую кнопку) сайдбар должен убираться.

В нашем макете разместим кнопку перед логотипом сайта. Вместо текста кнопки используем код символа ☰.

<header>
<button>&#9776;</button>
<img src="../logo.png" width="46" height="46">
<span>Название сайта</span>
</header>

Стилизуем кнопку и потом скроем:

button {
  display: none;
  width: 40px;
  height: 40px;
  font-size: 24px;
  margin-left: 10px;
  vertical-align: 4px;
}

Часто вместо элемента button используют оформленную под кнопку ссылку.

Теперь надо решить, в какой момент будет происходить ротация: появляться кнопка, скрываться навигация. Пусть такой отправной точкой будет предельная ширина в 1100 пикселей.

@media (max-width: 1100px) {
  article {
    margin: 0 auto;
  }
  footer {
    margin: 20px auto;
  }
  nav {
    display: none;
  }
  button {
    display: inline;
  }
}

При этом мы также должны вернуть центрирование статье и подвалу сайта.

Остался самый сложный момент, который потребует от нас использования JavaScript и следующей хитрости. Добавим в HTML-код вспомогательный блок, который будет появляться при нажатии на кнопку и затенять основное содержимое. Поверх него будет отображаться сайдбар. При клике по вспомогательному блоку, он сам и сайдбар будут убираться.

Добавлять так называемый оверлей следует между элементами header и nav, потому что лучше, чтобы он был на слое выше заголовка сайта, но обязательно под навигацией. Слои фиксированных блоков накладываются друг друга в порядке следования. Для справки: порядок можно менять с помощью свойства z-index.

<header>
<button onclick="navOpen()">&#9776;</button>
<img src="../logo.png" width="46" height="46">
<span>Название сайта</span>
</header>
 
<div id="overlay" onclick="navClose()"></div>
 
<nav id="sidebar">
<a href="#">Первая ссылка</a>
<a href="#">Вторая ссылка</a>
<a href="#">Третья ссылка</a>
</nav>

Мы назначаем вспомогательному блоку идентификатор "overlay", чтобы иметь возможность обращаться к нему из кода JS. В нашем случае мы могли бы это делать по именам тегов. Однако на реальных страницах может быть множество div-блоков и даже несколько nav.

С помощью атрибута onclick происходит вызов указанной в качестве значения функции в момент клика по элементу. Мы забежали вперед и еще не написали этих функций.

В коде CSS добавим правило для слоя-оверлея:

#overlay {
  display: none;
  position: fixed;
  width: 100%;
  height: 100%;
  background: rgba(0,0,0,0.5);
}

Цветовая модель RGBA позволяет задавать не только цвет, но и непрозрачность. Три первых нуля задают черный цвет. Значение 0.5 – непрозрачность в 50%. Для справки: 0 – полная прозрачность, 1 – полная непрозрачность).

Создадим файл script.js с таким кодом на языке JavaScript:

var bar = document.getElementById("sidebar");
 
var lay = document.getElementById("overlay");
 
function navOpen() {
  bar.style.display = "block";
  lay.style.display = "block";
}
 
function navClose() {
  bar.style.display = "none";
  lay.style.display = "none";
}

Подключим js-код, добавив в файл index.html перед тегом </body> следующий элемент:

<script src="script.js"></script>

Теперь при нажатии на кнопку будет появляться сайдбар, а при клике по затененной области он будет скрываться. Чтобы сайдбар появлялся без отступа в 50px, добавим в его правило в @media (max-width: 1100px) объявление top: 0.

  nav {
    display: none;
    top: 0;
  }

Макет готов. Но у него есть один недочет. Если свойству устанавливается значение с помощью JS, то оно переопределяет (оказывается специфичнее, сильнее), чем указание значения для этого свойства с помощью CSS.

Поэтому, если вы скроете меню с помощью клика по оверлею (при этом срабатывает код JS), то после этого при увеличении ширины окна элемент nav не появится. Его свойство display останется со значением none, потому что оно было назначено в скрипте.

Проблема решается еще одним медиа-запросом с директивой !impotant ("важный").

@media (min-width: 1101px) {
  nav {
    display: block!important;
  }
}

Мы не можем сделать важным значение block в основном правиле для nav (которое без медиа-запроса). Иначе для nav не будет срабатывать display: none в медиа-запросах.

Условие min-width: 1101px соблюдается для окон шириной больше 1100 пикселей (не меньше 1101px).

Введение в веб-разработку и создание сайтов