Верстка макета сайта
В настоящее время при создании отзывчивого (англ. 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
не соблюдается, статья и футер обратно вернутся к своему основному правилу, то есть окажутся в центре.
Если мы сильно сузим окно, то статья чрезмерно сожмется.
На смартфонах принято убирать сайдбары вниз или скрывать, а основной контент растягивать по ширине. Последнее время обычно меню скрывают и делают раскрывающимся при нажатии на кнопку. Чтобы реализовать подобное, нам надо:
- При размере окна меньше N пикселей сайдбар должен быть убран.
- При размере окна меньше N пикселей должна появляться кнопка.
- При нажатии на кнопку должен появляться сайдбар.
- При нажатии куда-нибудь еще (например, другую кнопку) сайдбар должен убираться.
В нашем макете разместим кнопку перед логотипом сайта. Вместо текста кнопки используем код символа ☰.
<header> <button>☰</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()">☰</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).