Отзывчивый дизайн на HTML5 и CSS3 для любых устройств [Бен Фрэйн] (pdf) читать онлайн

Книга в формате pdf! Изображения и текст могут не отображаться!


 [Настройки текста]  [Cбросить фильтры]
  [Оглавление]

Бен Фрэйн

Отзывчивый
дизайн на HTML5
и CSS3 для любых
устройств

Третье издание

2022

ББК 004.738.5
УДК 004.738.5
Ф86

Фрэйн Бен
Ф86

Отзывчивый дизайн на HTML5 и CSS3 для любых устройств. 3-е изд. — СПб.:
Питер, 2022. — 336 с.: ил. — (Серия «Библиотека программиста»).
ISBN 978-5-4461-1495-5
Вы фуллстек-разработчик, которому нужно развивать навыки фронтенд-разработки? Или фронтенд-разработчик, ищущий качественный обзор современных возможностей HTML и CSS? А может,
вы создаете свой веб-сайт и хотите сделать его отзывчивым? Тогда, эта книга вам просто необходима!
Со времени выхода предыдущего издания многое изменилось, теперь отзывчивый дизайн — это
не новая технология, а стандарт разработки на HTML5 и CSS3. Неформальный и открытый стиль
автора позволяет быстро освоить все возможности современного веб-дизайна. Вы получите практические знания о SVG, разметке HTML, создании потрясающей эстетики и эффектов с помощью
CSS, переходах, преобразованиях и анимациях и многом другом. Если же вы опытный веб-игрок, то
смело переходите к новым темам — гридам (CSS Grid layout) или вариативным шрифтам. К концу
книги вы не только получите полное представление об отзывчивом веб-дизайне и возможностях последних версий HTML5 и CSS, но и узнаете, как максимально эффективно использовать эти знания
на практике. Все, что нужно для начала работы, — это представление о том, что такое HTML и CSS.

16+ (В соответствии с Федеральным законом от 29 декабря 2010 г. № 436-ФЗ.)
ББК 004.738.5
УДК 004.738.5
Права на издание получены по соглашению с Packt Publishing. Все права защищены. Никакая часть данной
книги не может быть воспроизведена в какой бы то ни было форме без письменного разрешения владельцев
авторских прав.

ISBN 978-1839211560 англ.

© Packt Publishing 2020. First published in the English language
under the title ‘Responsive Web Design with HTML5 and CSS3 —
Third Edition — 9781839211560)’

ISBN 978-5-4461-1495-5

© Перевод на русский язык ООО Издательство «Питер», 2022
© Издание на русском языке, оформление
ООО Издательство «Питер», 2022
© Серия «Библиотека программиста», 2022

Краткое оглавление
Предисловие......................................................................................................16
Глава 1. Основы отзывчивого веб-дизайна................................................19
Глава 2. Создание HTML-разметки..............................................................38
Глава 3. Медиазапросы — поддержка различных окон просмотра.....65
Глава 4. Fluid Layout, Flexbox и отзывчивые изображения.......................85
Глава 5. CSS Grid........................................................................................... 121
Глава 6. CSS-селекторы, типографика, цветовые режимы
и многое другое........................................................................................ 149
Глава 7. Потрясающая эстетика с помощью CSS.................................. 187
Глава 8. SVG и независимость от разрешения....................................... 219
Глава 9. Переходы, преобразование и анимация................................. 253
Глава 10. Освоение форм с помощью HTML5 и CSS............................ 281
Глава 11. Бонусные техники и советы....................................................... 309

Оглавление
Краткое оглавление . ........................................................................................5
Об авторе . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
О научных редакторах. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

Предисловие......................................................................................................16
Для кого эта книга . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Структура. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Что нужно для работы с книгой. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Загрузка файлов с примерами кода. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Цветные изображения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Типографские соглашения. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
От издательства. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

Глава 1. Основы отзывчивого веб-дизайна . .............................................19
Браузеры и устройства. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Что такое отзывчивый дизайн . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Коротко об отзывчивом веб-дизайне . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Поддержка браузерами. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Текстовые редакторы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Инструменты для разработки софта. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Первый пример отзывчивого дизайна. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Базовый файл HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Укрощение изображений . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Ввод медиазапросов. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Несовершенство нашего примера . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Итоги. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

Глава 2. Создание HTML-разметки..............................................................38
Правильное начало работы с HTML‑страницами . . . . . . . . . . . . . . . . . . . . . . . . . 40
Элемент doctype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Тег html и атрибут lang . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Кодировка символов. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

Оглавление

7

Добрый HTML5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Разумный подход к HTML-разметке . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Да здравствует могущественный тег !. . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Новые семантические элементы в HTML5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Элемент main . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Элемент section . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Элемент nav . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Элемент article . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Элемент aside. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Элемент header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Элемент footer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Алгоритм схемы HTML5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Замечания относительно элементов h1–h6 . . . . . . . . . . . . . . . . . . . . . . . . 48
Элемент . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Элемент . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Элемент . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Элементы и . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Элементы и . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
Элемент . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Семантика HTML на уровне текста. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Элемент . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Элемент . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Элемент . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Элемент . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Элемент . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Устаревшие функции HTML. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Практическое применение HTML‑элементов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Использование WCAG и WAI-ARIA для повышения доступности
веб‑приложений. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
WCAG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
WAI-ARIA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Медиавозможности, встроенные в HTML5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Добавление видео и аудио в разметку HTML. . . . . . . . . . . . . . . . . . . . . . . 59
Отзывчивое HTML5-видео и iFrames. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Итоги. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Упражнение . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

8

Оглавление

Глава 3. Медиазапросы — поддержка различных окон просмотра ...65
Метатег viewport . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Зачем нужны медиазапросы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Основная условная логика в CSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Синтаксис медиазапроса . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Медиазапросы в тегах link. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Медиазапросы с использованием правила @import . . . . . . . . . . . . . . . . 71
Медиазапросы в файле CSS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Инверсия логики медиазапросов. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Объединение медиазапросов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Ряд различных медиазапросов. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Повседневные медиазапросы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Что можно тестировать с помощью медиазапросов . . . . . . . . . . . . . . . . 73
Использование медиазапросов для изменения веб-дизайна. . . . . . . . . . . . . . . 74
Расширенные рекомендации по медиазапросам . . . . . . . . . . . . . . . . . . . . . . . . . 77
Организация медиазапросов. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Практические аспекты разделения медиазапросов . . . . . . . . . . . . . . . . . 78
Вложение медиазапросов через встраивание. . . . . . . . . . . . . . . . . . . . . . 79
Что делать — объединять медиазапросы или же записывать их там,
где они пригодятся?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Спецификация Media Queries Level 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Медиафункции взаимодействия со страницей . . . . . . . . . . . . . . . . . . . . . . 82
Медиафункция prefers-color-scheme. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Итоги. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

Глава 4. Fluid Layout, Flexbox и отзывчивые изображения .....................85
Преобразование фиксированного пиксельного дизайна
в пропорциональный резиновый макет . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
Зачем нужен Flexbox. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
Представляем Flexbox. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Тернистый путь Flexbox. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Кому-то все еще нужны префиксы. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Возможность динамического изменения . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
Различные макеты Flexbox внутри разных медиазапросов . . . . . . . . . . . . . . . . . 98
Свойство inline-flex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
Свойства выравнивания, предоставляемые Flexbox . . . . . . . . . . . . . . . 100
Простой зафиксированный подвал. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Изменение порядка следования исходных элементов . . . . . . . . . . . . . 109

Оглавление

9
Свертка flex-элементов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Итоги по Flexbox. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116

Отзывчивые изображения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
Проблема, присущая отзывчивым изображениям. . . . . . . . . . . . . . . . . 116
Простое переключение разрешения с помощью srcset. . . . . . . . . . . . 117
Более совершенный вариант переключения с помощью
srcset и sizes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Управление элементом picture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
Итоги. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120

Глава 5. CSS Grid . ........................................................................................ 121
Что такое CSS Grid и какие проблемы она решает . . . . . . . . . . . . . . . . . . . . . 121
Базовый синтаксис Grid. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Терминология, специфичная для Grid. . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Настройка сетки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Явное и неявное позиционирование элементов . . . . . . . . . . . . . . . . . . 127
Размещение и изменение размера элементов сетки . . . . . . . . . . . . . . . . . . . . 130
Свойство gap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Функция repeat(). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Единица fr. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Размещение элементов в сетке . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
Ключевое слово span . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
Ключевое слово dense . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
Именованные линии сетки. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
Свойство grid-template-areas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
Применение ваших знаний на практике . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
Ключевые слова auto-fit и auto-fill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
Функция minmax(). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
Сокращения в синтаксисе . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
Сокращение grid-template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Сокращение grid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Итоги. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148

Глава 6. CSS-селекторы, типографика, цветовые режимы
и многое другое ............................................................................................ 149
Селекторы, единицы измерения и возможности. . . . . . . . . . . . . . . . . . . . . . . . . 150
Анатомия правила CSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
Псевдоэлементы и псевдоклассы. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Селекторы CSS Level 3 и как их использовать . . . . . . . . . . . . . . . . . . . . 152

10

Оглавление

Структурные псевдоклассы. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Отзывчивые меры длины, выражаемые в процентных отношениях,
применительно к окнам просмотра (vmax, vmin, vh, vw). . . . . . . . . . . . 166
Функция calc() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Пользовательские свойства CSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Использование @supports для создания альтернативных вариантов . . . 171
Веб-типографика . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
Системные шрифты. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
CSS-правило @font-face . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
Реализация веб-шрифтов с помощью @font-face . . . . . . . . . . . . . . . . . 175
Оптимизация загрузки шрифтов с помощью @font-face . . . . . . . . . . . 176
Вариативные шрифты. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
Форматы цвета в CSS и альфа‑прозрачность . . . . . . . . . . . . . . . . . . . . . . . . . . 183
Цвет в формате RGB. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
Цвет в формате HSL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
Итоги. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186

Глава 7. Потрясающая эстетика с помощью CSS ................................. 187
Создание теней для текста средствами CSS. . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
Если размытие не нужно, его значение можно опустить . . . . . . . . . . . 189
Создание теней для блоков. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
Тень внутри элемента . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
Создание нескольких теней . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
Понятие протяженности. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
Градиентные фоны. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
Запись линейного градиента . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
Радиальные градиентные фоны . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
Удобные ключевые слова «распространения» для задания
размеров отзывчивых конструкций . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
Повторяющиеся градиенты. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
Паттерны градиентных фонов. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
Использование нескольких фоновых изображений . . . . . . . . . . . . . . . . . . . . . 199
Размер фона. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
Позиционирование фона . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
Краткая запись настроек фона . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
Фоновые изображения с высоким разрешением . . . . . . . . . . . . . . . . . 202
CSS-фильтры . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
Доступные CSS-фильтры . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
Объединение CSS-фильтров. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208

Оглавление

11

Предупреждения, касающиеся CSS‑производительности. . . . . . . . . . . . . . . . 209
CSS-свойство clip-path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
Свойство clip-path с URL-адресом. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
Базовые формы CSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
Анимация с помощью свойства clip-path . . . . . . . . . . . . . . . . . . . . . . . . . 214
Изображение в качестве маски . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
Пример изображения-маски . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
Свойство mix-blend-mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
Итоги. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218

Глава 8. SVG и независимость от разрешения ..................................... 219
Краткая история SVG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
Изображение — считываемый веб‑документ . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
Корневой элемент SVG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
Пространство имен. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
Теги title и desc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
Тег defs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
Элемент g . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
Фигуры SVG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
SVG-пути . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
Создание SVG-графики с помощью популярных пакетов и сервисов
редактирования изображений. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
Сервисы SVG-значков экономят время . . . . . . . . . . . . . . . . . . . . . . . . . . 226
Вставка SVG-графики в веб-страницы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
Использование тега img . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
Использование тега object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
Вставка SVG-графики в качестве фонового изображения . . . . . . . . . 229
Краткое отступление о URI-идентификаторах данных . . . . . . . . . . . . . 229
Создание спрайтов изображений. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
Непосредственная вставка SVG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
Повторное использование графических объектов из символов . . . . . . . . . . 231
Встраиваемая в код SVG-графика позволяет задавать разные
цвета в разных контекстах. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
Изменение цветов SVG-изображений с помощью
пользовательских свойств CSS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
Повторное использование графических объектов из внешних
источников. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
На что влияет способ вставки SVG‑данных?. . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
Особенности браузеров. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238

12

Оглавление

Дополнительные возможности и особенности технологии SVG. . . . . . . . . . . 239
SMIL-анимация . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
Задание стилей SVG с помощью внешней таблицы стилей. . . . . . . . . 241
Задание стилей SVG с помощью внутренних стилей . . . . . . . . . . . . . . 242
Анимация SVG-графики с помощью CSS. . . . . . . . . . . . . . . . . . . . . . . . . 242
Анимация SVG-графики с помощью JavaScript. . . . . . . . . . . . . . . . . . . . . . . . . . 244
Простой пример анимации SVG-графики с помощью
GreenSock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
Оптимизация SVG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246
Использование SVG в качестве фильтров. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
Медиазапросы внутри SVG. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
Советы по внедрению. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
Итоги. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
Дополнительные ресурсы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252

Глава 9. Переходы, преобразование и анимация . .............................. 253
Что такое CSS-переходы и как ими можно воспользоваться. . . . . . . . . . . . . . 254
Свойства перехода. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
Краткая форма записи перехода с помощью свойства
transition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
Переходы различных свойств за разные периоды. . . . . . . . . . . . . . . . . 257
Функции развития процесса перехода по времени . . . . . . . . . . . . . . . . . . . . . 258
2D-преобразования в CSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
Масштабирование (scale) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
Перемещение (translate) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
Поворот (rotate) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
Наклон (skew) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
Матрица (matrix) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
Свойство transform-origin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
3D-преобразования в CSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
Свойство transform3d. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
Использование преобразований при постепенном улучшении
на примере функции translate3d . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
Эффекты анимации с помощью CSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
Свойство animation-fill-mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
Упражнения и практика . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
Итоги . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280

Оглавление

13

Глава 10. Освоение форм с помощью HTML5 и CSS .......................... 281
Формы HTML5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
Основные сведения о компонентах формы HTML5. . . . . . . . . . . . . . . . 283
Атрибут placeholder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
Стилизация указателя ввода с помощью свойства caret-color. . . . . . 284
Атрибут required . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
Атрибут autofocus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
Атрибут autocomplete. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
Атрибут list и элемент datalist . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
Типы вводимой информации, определяемые HTML5. . . . . . . . . . . . . . . . . . . . . 289
Тип email . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
Тип number . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
Тип url . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
Тип tel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294
Тип search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
Атрибут pattern. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
Тип color. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
Типы date и time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
Тип range . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
Стилизация форм HTML5 с помощью CSS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
Обозначение полей, требующих обязательного заполнения . . . . . . 305
Создание эффекта заливки фона . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
Итоги. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308

Глава 11. Бонусные техники и советы....................................................... 309
Разбивка длинных URL-адресов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
Обрезка текста . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
Создание панелей с горизонтальной прокруткой. . . . . . . . . . . . . . . . . . . . . . . 312
Создание панелей с горизонтальной прокруткой с помощью
Grid. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
Модуль CSS Scroll Snap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
Свойство scroll-snap-type. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
Свойство scroll-snap-align . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316
Свойство scroll-padding. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
Плавная прокрутка с помощью свойства scroll‑behavior. . . . . . . . . . . 319
Привязка брейкпоинтов CSS к JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
Обкатка веб-дизайна в браузере на самых ранних стадиях . . . . . . . . . . . . . 323
Тестирование на реальных устройствах . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323

14

Оглавление

Использование принципа постепенного улучшения. . . . . . . . . . . . . . . . . . . . . 324
Определение матрицы браузерной поддержки . . . . . . . . . . . . . . . . . . 324
Функциональное, но не эстетическое единообразие. . . . . . . . . . . . . . 325
Выбор поддерживаемых браузеров . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325
Создание нескольких уровней пользовательского восприятия . . . . . 326
Отказ от использования сред разработки CSS при создании
конечного продукта. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
Скрытие, показ и загрузка содержимого для разных окон просмотра . . . . 327
Средства контроля качества кода. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328
Повышение производительности. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329
Инструменты для оценки производительности. . . . . . . . . . . . . . . . . . . . 330
В преддверии великих перемен . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
Итоги. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332

Об авторе
Бен Фрэйн (Ben Frain) занимается веб-дизайном и разработкой веб-приложений
с 1996 года. Сейчас он UI-UX техлид в Bet365.
Был скромным, не получившим должного признания актером на телевидении
и писал технические статьи. Учился театральному искусству в Салфордском университете. Написал четыре недооцененных (по его мнению) киносценария и до
сих пор вынашивает, но уже с угасающим энтузиазмом, планы продать хотя бы
один из них. В свободное время наслаждается простыми радостями жизни — играет в мини-футбол, пока позволяют здоровье и жена, и воспитывает двух сыновей.

О научных редакторах
Х. Педро Рибейро — бразильский фронтенд-разработчик, живет в центре Лондона. Несколько лет посвятил веб-разработке, фокусируясь на производительности
и доступности веб-сайтов для улучшения пользовательского опыта.
Педро уже был научным редактором проектов издательства Packt, Mastering
Responsive Web Design и Responsive Web Design Patterns.
Разработал Baseliner — бразуерное расширение, у которого больше 6000 пользователей в неделю.
y Блог — https://jpedroribeiro.com/
y Twitter — https://twitter.com/jpedroribeiro
y GitHub — https://github.com/jpedroribeiro
Кларисса Петерсон — UX-разработчик и стратег, посвятившая более пятна­
дцати лет созданию эффективных и интуитивно понятных интерфейсов. Начинала как фронтенд-разработчик, а затем много лет была «человеком-оркестром»
в некоммерческих и правозащитных организациях Вашингтона. Сейчас преподает веб-дизайн: пишет статьи, выступает с лекциями и проводит уроки.
Кларисса написала книгу Learning Responsive Web Design: A Beginner's
Guide (издательство O'Reilly). Cоставила онлайн-курсы для LinkedIn Learning
и преподавала в Технологическом институте Южной Альберты (SAIT). Спикер
международных конференций по веб-дизайну и технологиям.
Проявляя научный интерес к инклюзивности и доступной среде, сейчас работает над новым проектом на стыке гражданских прав и технологий.

Предисловие
Когда я писал первое издание в 2011–2012 годах, никто и подумать не мог, что
в обозримом будущем отзывчивый (responsive) веб-дизайн фактически станет
стандартом веб-дизайна. Поэтому популярность и полезность книги не уменьшаются даже спустя девять лет и два издания.
Бытует выражение, применимое к авторам технических книг: «Когда один учит
другого, учатся оба». Именно это и произошло при работе над третьим изданием.
Я узнал гораздо больше, чем мог себе представить. На работе я возвращаюсь к некоторым главам и разделам и вспоминаю, как делать ту или иную вещь, о которой
уже забыл! Надеюсь, эта книга окажется такой же находкой и для вас.
Вспоминая первое издание, я поражаюсь, насколько продвинулись технологии.
Если вы опытный игрок в веб-разработке, то смело переходите к новым темам —
гридам (CSS Grid layout) или вариативным шрифтам. Очень удивлюсь, если вас
нисколько не тронут возможности этих технологий. А ведь еще каких-то десять
лет назад такое трудно было представить.
Но не буду вас задерживать. Спасибо, что решили прочитать эту книгу. Надеюсь,
она вам понравится и вы многое из нее извлечете. И буду рад получить любой
фидбек — и положительный, и отрицательный. Он во многом определяет содержание будущих изданий.

Для кого эта книга
Вы фуллстек-разработчик, которому нужно развивать навыки фронтенд-разработки? Или фронтенд-разработчик и ищете исчерпывающий обзор по современным HTML и CSS? А может, вы сейчас создаете веб-сайт и вам нужно глубокое
понимание отзывчивого веб-дизайна? Эта книга для вас!
Все, что нужно для начала работы, — это современное представление об HTML
и CSS. Знание JavaScript не требуется.

Структура
Глава 1 «Основы отзывчивого веб-дизайна» — это краткий обзор ключевых составляющих в создании программных продуктов, отвечающих требованиям отзывчивого веб-дизайна.
Глава 2 «Создание HTML-разметки» раскрывает все семантические элементы
HTML5, семантику на уровне текста и соображения доступности, а также объясняет, как добавлять медиаэлементы (например, видео) на страницу.

Что нужно для работы с книгой

17

Глава 3 «Медиазапросы — поддержка различных окон просмотра» охватывает все, что вам нужно знать о медиазапросах CSS: их возможностях, синтаксис
и различные варианты использования.
Глава 4 «Fluid Layout, Flexbox и отзывчивые изображения» показывает, как
создавать пропорциональный макет и отзывчивые изображения, а также подробно описывет Flexbox-макеты.
Глава 5 «CSS Grid» — глубокое погружение в систему двухмерного макета CSS
Grid.
Глава 6 «CSS-селекторы, типографика, цветовые режимы и многое другое»
охватывает бесконечные возможности CSS-селекторов, цветов HSLA и RGBA,
веб-типографики, включая вариативные шрифты, единицы измерения области
просмотра (вьюпорт единицы), и многое другое.
Глава 7 «Потрясающая эстетика с помощью CSS» охватывает CSS-фильтры,
тени блоков, линейные и радиальные градиенты, многочисленные фоны и способы переноса фоновых изображений на устройства с высоким разрешением.
Глава 8 «SVG и независимость от разрешения» рассказывает обо всем, что
нужно для использования SVG-графики внутри документов и в качестве фоновых
изображений, а также о том, как взаимодействовать с ними с помощью JavaScript.
Глава 9 «Переходы, преобразование и анимация» приведет CSS в движение,
по мере того как мы будем учиться создавать взаимодействия и анимацию с помощью CSS.
Глава 10 «Освоение форм с помощью HTML5 и CSS» объясняет, что вебформы всегда были сложными, но теперь новейшие функции HTML5 и CSS
сделали работу с ними проще, чем когда-либо прежде.
Глава 11 «Бонусные техники и советы» освещает основные моменты, которые
необходимо учесть перед началом работы, а также включает несколько важных
советов, которые помогут принять верное дизайн-решение.

Что нужно для работы с книгой
Вам понадобятся:
y Текстовый редактор: Sublime Text, Vim, Visual Studio Code и т. д.
y Современный браузер, например Firefox, Edge, Safari или Chrome.
y Понимание так себе шуток и неявных отсылок к фильмам.

Загрузка файлов с примерами кода
Вы можете загрузить файлы с примерами кода для этой книги с github.com. Нужный код лежит в репозитории: https://github.com/PacktPublishing/Responsive-WebDesign-with-HTML5-and-CSS-Third-Edition. Там же будут отображаться все возможные
изменения.

18

Предисловие

После загрузки файла убедитесь, что вы распаковали или извлекли папку, используя последнюю версию:
y WinRAR/7-Zip для Windows.
y Zipeg/iZip/UnRarX для Mac.
y 7-Zip/PeaZip для Linux.

Цветные изображения
Мы также предоставляем PDF-файл с цветными скриншотами и схемами, используемыми в книге. Их можно скачать здесь: https://static.packt-cdn.com/downloads/
9781839211560_ColorImages.pdf.

Типографские соглашения
Код и примеры пользовательского ввода выделены моноширинным шрифтом.
Имена папок, файлов, расширения имен файлов, названия путей, URL-адреса
и элементы интерфейса выделены шрифтом без засечек.
Листинги приводятся в следующем виде:
img {
max-width: 100%;
}

Новые понятия и важные слова выделены курсивным шрифтом.

В такой врезке приводится важная сопутствующая информация.

А в такой врезке содержатся советы и подсказки.

От издательства
Ваши замечания, предложения, вопросы отправляйте по адресу: comp@piter.com
(издательство «Питер», компьютерная редакция).
Мы будем рады узнать ваше мнение!
На веб-сайте издательства www.piter.com вы найдете подробную информацию
о наших книгах.

1

Основы отзывчивого
веб-дизайна

Здесь мы рассмотрим все, что нужно знать для создания полностью отзывчивой
веб-страницы.
Вы спросите, а зачем тогда остальные десять глав? Ответ на этот вопрос ниже
в этой главе.
Когда в 2012 году вышло первое издание этой книги, отзывчивый веб-дизайн был
новой и захватывающей возможностью настраивать вид страниц для появляющихся
разнообразных устройств с доступом к интернету. В 2020 году отзывчивый вебдизайн — это стандарт. Если вы создаете неотзывчивые веб-сайты или веб-приложения
без уважительной причины, то, скорее всего, вы все делаете неправильно!
Возможно, вы читаете эту главу, потому что хотите понять, что делает веб-дизайн
отзывчивым, и разобраться в возможностях HTML и CSS. Или вы уже создаете
отзывчивые веб-сайты и хотите побольше узнать о функциях и методах, которые
прошли мимо вас либо только появились.
В любом случае мы вам поможем. Если вы из второго лагеря, эта глава послужит
вам шпаргалкой. А если из первого — воспринимайте эту главу как курс молодого
бойца, чтобы в итоге мы все оказались на одной волне.
Вот что мы рассмотрим в этой главе:
y Обзор браузеров и устройств.
y Определение отзывчивого веб-дизайна.
y Настройка уровней поддержки браузера.
y Инструменты разработки и текстовые редакторы.
y Создание простой страницы с помощью HTML5 — наш первый отзывчивый
пример.
y Метатег viewport.
y Отзывчивые изображения.
y Написание медиазапросов CSS3 для адаптации страниц.
y Недостатки из первого примера.
y Почему наше путешествие только началось.
Устраивайтесь поудобнее и поехали!

20

Глава 1. Основы отзывчивого веб-дизайна

Браузеры и устройства
Менее десяти лет назад еще можно было создавать веб-сайты с фиксированной
шириной. Считалось, что они подойдут более или менее всем пользователям. Фиксированная ширина страницы сайта (около 960 пикселей) была не слишком широкой для экранов ноутбуков, да и на мониторах с высоким разрешением практически не оставалось пустого места с любой стороны.
Но в 2007 году iPhone открыл первую по-настоящему удобную возможность
просмотра веб-страниц на телефоне, навсегда изменив способы доступа к интернету и взаимодействия с веб-сайтами.
В первом издании этой книги, опубликованном в начале 2012 года, я упомянул о процентном соотношении общего использования браузера по типам
устройств:
«За 12 месяцев с июля 2010 года по июль 2011 года глобальное использование
мобильных браузеров выросло с 2,86 до 7,02 %».
Во втором издании книги я отметил:
«На момент написания этих строк в середине 2014 года та же статистическая система gs.statcounter.com свидетельствует, что этот показатель
вырос до 29,48 % (для сравнения, показатель использования мобильной связи
в Северной Америке составляет 24 %). Это растущая тенденция, которая
не показывает каких-либо признаков спада».
Когда я пишу эти строки в сентябре 2019 года, согласно той же StatCounter, на
мобильные устройства приходятся колоссальные 51,11 % от общего использования
браузеров, на стационарные компьютеры — 45,18 %, а на планшеты — 3,71 %.
Количество людей, использующих устройства с меньшим экраном, постоянно
растет, в то время как на другом конце шкалы 27- и 30-дюймовые дисплеи теперь
тоже распространены (вместе с планшетами и консолями). Сейчас разница между
самыми маленькими и самыми большими экранами для просмотра веб-страниц
стала больше, чем когда-либо прежде.
К счастью, для такого постоянно расширяющегося ландшафта браузеров
и устройств есть решение. Отзывчивый веб-дизайн, созданный с помощью HTML
и CSS, позволяет веб-сайту «просто работать» на различных устройствах и экранах.
Он помогает макету и возможностям веб-сайта реагировать на среду (размер экрана, тип ввода и возможности устройства/браузера).
До того как появился отзывчивый веб-дизайн, компании часто поддерживали
отдельные сайты для мобильных устройств с собственными URL. Приходилось
обнаруживать пользовательский агент на сервере хоста и перенаправлять его на
соответствующий URL для стационарных либо мобильных устройств. Еще одно

Что такое отзывчивый дизайн

21

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

Что такое отзывчивый дизайн
Понятие «отзывчивый веб-дизайн» было введено Итаном Маркоттом (Ethan Marcotte) в 2010 году. В своей новаторской статье на сайте A List Apart (http:// www.
alistapart.com/articles/responsive-web-design/) он свел три существовавшие на тот момент технологии (макет flexible grid layout, подстраиваемые по размеру изображения и мультимедийные элементы, а также медиазапросы) в единый подход, который он назвал отзывчивым веб-дизайном1.

Коротко об отзывчивом веб-дизайне
Философию отзывчивого веб-дизайна можно выразить так: это представление
веб-содержимого в наиболее удобном формате для окна просмотра и устройства,
обращающегося за этим содержимым.
На заре развития реализация отзывчивого веб-дизайна начиналась с проектирования десктопного варианта страницы с фиксированным размером. Затем этот
вариант дорабатывался для устройств с меньшими экранами. Но прогресс не
стоял на месте. Стало понятно, что есть более правильный путь — все, от дизайна
до управления контентом и разработки, получается лучше, если начинать с небольших экранов, а затем «постепенно улучшать» все это для больших мониторов
и/или более функциональных устройств. Если вы не поняли термин «постепенное
улучшение», не волнуйтесь. Мы поговорим о нем еще раз совсем скоро.
Но сначала я хочу рассмотреть несколько вопросов, касающихся браузерной
поддержки, текстовых редакторов и инструментов.

Поддержка браузерами
Сейчас есть так много разных устройств с выходом в интернет, что необходимость
единого технологического решения для большинства из них не приходится объяснять.
Распространение отзывчивого веб-дизайна сильно упрощает коммерческую
реализацию веб-проектов. В наши дни у большинства людей уже сложилось
1

В русскоязычных изданиях есть путаница в понятиях «отзывчивый» (responsive)
и «адаптивный» (adaptive) дизайн. Можно сказать, что отзывчивый веб-дизайн является подмножеством адаптивного. Отзывчивый дизайн подстраивается под размер
макета, в адаптивном используется несколько макетов для адаптации к разным размерам экрана. — Примеч. науч. ред.

22

Глава 1. Основы отзывчивого веб-дизайна

какое-то представление об отзывчивом дизайне, даже если оно недалеко ушло от
определения «веб-сайт, который хорошо выглядит и на телефонах, и на компьютерах».
Но при запуске проекта с отзывчивым дизайном почти всегда возникает вопрос
поддержки со стороны браузеров. Сейчас браузеров и устройств так много, что
вряд ли есть смысл реагировать на изменения каждого отдельно взятого браузера.
Возможно, здесь играет роль фактор времени. Или денег. А может быть, и того
и другого.
Как правило, чем старее браузер, тем больший объем работы и кода нужен для
достижения того эстетического восприятия, которое пользователь получает при
работе с современными браузерами.
Мы будем практиковать постепенное улучшение. По сути, мы начнем с разработки функционального и доступного веб-сайта для самых простых браузеров
и дополним его для самых продвинутых. На практике веб-сайты, которые не могут
работать в старом браузере или устройстве, создаются не так уж часто.

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

Прежде чем рассматривать какой-либо веб-проект, лучше заранее решить, какие
платформы вы будете поддерживать полноценно, а в каких готовы смириться
с визуальными и функциональными аномалиями.
Например, если вам не повезет и 25 % посетителей вашего сайта будут пользоваться Internet Explorer 11, придется учесть, какие функции поддерживаются этим
браузером, и подстраивать под них свои решения. То же правило работает, если
большой процент ваших пользователей посещает сайт с устаревших платформ
вроде Android 4.
Если вы еще этого не сделали, ознакомьтесь с сайтом http://caniuse.com. С его
помощью легко проверить, есть ли у определенного браузера поддержка какойлибо функции.
Вообще, при запуске проекта я определяю перечень поддерживаемых браузеров
такой грубой логикой: если стоимость разработки и поддержки браузера X больше,
чем доход/выгода, приносимая пользователями этого браузера, то разрабатывать
конкретные решения для браузера X не стоит.

Что такое отзывчивый дизайн

23

Рис. 1.1. На сайте caniuse.com можно посмотреть, поддерживает ли браузер
какую-либо функцию веб-платформы

Текстовые редакторы
Неважно, какой инструмент вы используете для написания кода. Если самый простой из текстовых редакторов позволяет эффективно писать код на HTML, CSS
и JavaScript, вы вполне можете его использовать. Sublime Text, Vim, Emacs, Nova,
Visual Studio Code или Notepad — в итоге это не имеет большого значения. Пользуйтесь тем, что вам нравится.

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

24

Глава 1. Основы отзывчивого веб-дизайна

Sass, помогают с организацией кода, переменными, манипуляциями с цветом
и арифметическими операциями. Постпроцессоры CSS, такие как PostCSS, могут
автоматизировать утомительную работу, например по выставлению префикса
CSS‑кода. Линтеры и инструменты проверки помогут убедиться в процессе, что
коды HTML, JavaScript и CSS соответствуют стандартам: они выявляют множество опечаток, поиск и исправление вручную которых отнимает много времени.
Совсем недавно средства форматирования кода изменили нашу повседневную
работу. Например, Prettier автоматически форматируют код с отступом и интервалом при сохранении. Все эти инструменты необязательны, но могут в чем-то
помочь.
Новые инструменты появляются все время. Поэтому какие бы актуальные
и полезные средства ни упоминались в этой книге, имейте в виду, что где-то уже
готовится к выходу что-то более интересное. Так что в своих примерах мы не можем полагаться на что-либо иное, кроме стандартов на основе HTML и CSS. Но вам
все же стоит выбрать наиболее удобный для себя инструмент, чтобы писать качественный код как можно быстрее и эффективнее.

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

ЛИСТИНГИ
Все листинги из этой книги можнозагрузить по ссылке https://rwd.education/. Имейте в виду, что, загрузив примеры из главы 2, вы увидите их в том виде, в котором
они приводятся в конце главы 1. В отличие от текста самой главы, в этих примерах
кода нет промежуточных версий.

Базовый файл HTML
Начнем с простой структуры HTML5. Пока что не обращайте внимания на смысл
каждой строки, особенно на содержимое — в главе 2 мы подробно рассмотрим эту тему.
Предлагаю пока сконцентрироваться на элементах внутри . Здесь есть
несколько элементов div, изображение логотипа, один-два абзаца текста и список
ингредиентов.

Первый пример отзывчивого дизайна

25

На скриншотах контента больше, но примеры кода сокращены. Я намеренно
удалил абзацы текста, поскольку нас интересует лишь структура.
Но что действительно нужно знать: в тексте описывается рецепт приготовления
сконов — вершины британских десертов.
И помните, если вам нужен весь файл HTML, его можно скачать с сайта https://
rwd.education/:




Our first responsive web page with HTML5 and CSS3






Scones: the most resplendent of snacks


Occasionally maligned and misunderstood; the
scone is a quintessentially British classic.

Incredible scones, picture from Wikipedia


Recipe and serving suggestions follow.

Ingredients



Method





По умолчанию веб-страницы гибкие. Если я открою страницу из нашего примера в ее нынешнем виде без какой-либо отзывчивости и изменю размер окна
браузера, текст подгонится как надо.

26

Глава 1. Основы отзывчивого веб-дизайна

А как насчет других устройств? Опять же, без добавления на страницу какоголибо CSS-кода на iPhone XR текст отобразится так:

Рис. 1.2. Выглядит не очень красиво, но по умолчанию все веб-страницы гибкие

Как видите, страница отображается, но так, будто уменьшили экран ПК. Дело
в том, что изначально iOS отображает веб-страницы шириной 980 px и сжимает
их до размера области просмотра (viewport).
Раньше веб-сайты на iPhone выглядели так почти всегда. Но благодаря повсеместному распространению отзывчивого веб-дизайна теперь встретить такое отображение практически невозможно!
Чтобы адаптировать страницу для мобильных устройств, добавим в этот
фрагмент:

Первый пример отзывчивого дизайна

27



На самом деле метатег с именем viewport не считается стандартным способом
указания браузеру, как отобразить страницу (хотя и является им де-факто). Несмотря на то что этот метатег ввела компания Apple, а не стандарты, он важен для
отзывчивого веб-дизайна. Рассмотрим его в главе 3.
Пока что просто знайте, что в нашем примере метатег viewport задает четкое
предписание — отобразить содержимое во всю ширину экрана устройства.
Легче, наверное, просто показать действие этой строки кода на устройствах:

Рис. 1.3. Мы изменили всего одну строку, а страница уже выглядит гораздо лучше

Отлично! Исправлена еще одна проблема: теперь текст отобразился более
естественно. Идем дальше.

28

Глава 1. Основы отзывчивого веб-дизайна

Укрощение изображений
Как говорится, лучше один раз увидеть, чем сто раз услышать. Разве можно писать
о булочках, но так и не показать этой красоты? Я хочу разместить изображение
булочки ближе к началу страницы в качестве своеобразной приманки для пользователей, чтобы им захотелось прочитать текст:

Рис. 1.4. Придется добавить пару строк CSS — без них не настроить нормальный
размер изображения

Увы! Весьма привлекательное, но крупное изображение в 2000 пикселей шириной заставило страницу показать лишь часть картинки. Нужно все исправить.
Есть идеи? Что ж, можно, конечно, задать с помощью CSS фиксированную
ширину изображения, но перед нами стоит задача другого рода: мы хотим, чтобы
изображение масштабировалось под разные размеры экрана. Например, в CSS
экран iPhone XR имеет размер 414 на 896 пикселей. Предположим, мы установим

Первый пример отзывчивого дизайна

29

для этого изображения ширину 414 пикселей. Что произойдет, если пользователь
повернет экран? Ширина области просмотра станет 896 пикселей. К счастью,
всего одна строка CSS может сделать изображения отзывчивыми.
Теперь я собираюсь создать файл css/styles.css, ссылка на который уже есть
в заголовке HTML-страницы.
Первым делом я добавлю в чистый файл css/styles.css следующий код. Хотя его
можно было бы записать как одну строку, я разобью ее на три ради удобства чтения.
Обычно я добавляю прочие исходные настройки, речь о которых пойдет в следую­
щих главах, но для выполнения нашей задачи пока что хватит и этого:
img {
max-width: 100%;
}

Теперь после сохранения файла и обновления страницы мы увидим что-то
более соответствующее ожиданиям.

Рис. 1.5. После добавления небольшого фрагмента CSS изображения больше
не выходят за границы области просмотра

30

Глава 1. Основы отзывчивого веб-дизайна

Область окна браузера, которая позволяет просматривать веб-страницу, называется областью просмотра (вьюпортом). В область просмотра не входят панели инструментов браузера, адресная строка и т. д. Далее мы будем использовать именно этот термин.

Правило, на котором основано свойство max-width, предполагает, что максимальная ширина изображений не должна превышать 100 % их размера. Если содержащий изображение элемент (такой, как body или находящийся внутри него
div) меньше полной реальной ширины изображения, браузер отобразит максимально возможный размер этого изображения при таких ограничениях.

Пара слов о width и max-width для изображений
Чтобы сделать изображение подстраиваемым, можно также применить более востребованное свойство width, например width: 100%. Но в результате эффект будет
совершенно другим: при использовании процентов картинка отобразится с заданной шириной, зависящей от ширины контейнера, при этом неважно, какая у нее
реальная ширина. Так, наш логотип растянется, чтобы заполнить 100 % своего
контейнера, потому что контейнер шире самого изображения логотипа.
Превосходно! Теперь все так, как мы и ожидали. Независимо от размера окна
просмотра ничто теперь не выходит за его границы по горизонтали.

Примеры кода, представленные в этой книге, не включают стили префиксов
брау­зеров. Раньше префиксы браузеров использовались для экспериментальных
свойств CSS в различных браузерах, например webkit-backface-visibility.
Без префиксов в CSS часто не обойтись, если нужно обеспечить поддержку определенных свойств в старых браузерах. Теперь есть инструменты, которые автоматизируют простановку префиксов и, как вы могли догадаться, выполняют эту
задачу быстрее и точнее, чем мы.
Я не буду добавлять эти префиксы в примеры кода, надеясь, что вы используете
этот подход. Префиксы браузеров и инструменты автоматизации подробно описаны в главе 7.

Но если открыть страницу в более крупном окне просмотра, основные стили
растягиваются. Взгляните, как отображается наш код при размере окна просмотра
около 1400 пикселей.

Первый пример отзывчивого дизайна

31

Рис. 1.6. Определенно нужно изменить размер этого изображения для больших
областей просмотра

О нет! Фактически страница начинает выглядеть растянутой уже при ширине
примерно 800 пикселей. Самое время сейчас что-нибудь поправить. Может быть,
изменить размер изображения и выровнять его по одной из сторон. Или изменить
размеры части шрифтов и цвета фона элементов.
К счастью, все эти функциональные возможности мы без особого труда можем
получить с помощью медиазапросов CSS.

Ввод медиазапросов
Как выяснилось, если ширина окна просмотра больше 800 пикселей, макет становится растянутым. Давайте воспользуемся медиазапросами CSS для подгона макета в зависимости от ширины экрана. Более подробно разберем медиазапросы
в главе 3, а пока достаточно знать, что медиазапросы — это директивы CSS, которые позволяют привязывать CSS-правила к определенным условиям среды (в нашем случае это размер экрана).

32

Глава 1. Основы отзывчивого веб-дизайна

Брейкпоинты
Прежде чем мы продолжим, стоит познакомиться с контрольными точками, или
брейкпоинтами.
Это понятие используется веб-разработчиками для определения конкретной
ширины или высоты области просмотра, при которой отзывчивый дизайн заметно
меняется.
Когда медиазапросы только появились, проекты часто строились с определенными брейкпоинтами для обслуживания популярных устройств того времени.
В то время это были iPhone (320 × 480 пикселей) и iPad (768 × 1024 пикселей).
Даже тогда такая практика была плохим решением, а сейчас тем более. Проблема в том, что такой подход подстраивает дизайн под конкретные размеры
экрана. А нам нужен отзывчивый дизайн — такой, который не зависит от размера
экрана и подстраивается под любое окно просмотра. Недостаточно того, что лучше
всего смотрится только при определенных размерах.
Представьте, что я ваш отец. С благими намерениями я нахмурился и настойчиво заявляю: «Нет никаких конкретных брейкпоинтов — используй брейкпоинт,
если он нужен для дизайна, а не для конкретного устройства!» Ладно, снимаю
шапку с надписью «папа» и обещаю не шутить в присутствии ваших друзей.
Небольшой вывод из этого лирического отступления: лучшие результаты получаются тогда, когда вы руководствуетесь своим дизайном при принятии решения
о вводе брейкпоинтов.
Но мы вовсе не хотим, чтобы наш простой пример разрастался. Поэтому сконцентрируемся на одном типе медиазапроса, связанном с минимальной шириной.
Правила CSS внутри него применяются только если окно просмотра равно какойнибудь конкретной ширине или превышает ее. Эту ширину можно задать с помощью различных единиц измерения, включая проценты, em, rem, пиксели и т. п.
В CSS медиазапрос минимальной ширины записывается так:
@media screen and (min-width: 800px) {
/* стили */
}

Директива @media сообщает браузеру о начале медиазапроса, а компонент screen
(объявлять его здесь, в принципе, не обязательно, но мы все же будем работать
с ним в главе 3) сообщает, что правила должны применяться ко всем типам экранов. Ключевое слово and связывает воедино второй набор условий, который в нашем случае выражен как min-width: 800px. Благодаря им браузер понимает, что
правила должны действовать для всех окон просмотра шириной не менее 800 пикселей.
Думаю, следующую фразу впервые написал Брайан Ригер (Bryan Rieger) (http://
www.slideshare.net/bryanrieger/rethinking-the-mobile-web-by-yiibu): «Отсутствие носителя для медиазапросов фактически является признаком первого медиазапроса».
Он имел в виду, что вне медиазапроса прежде всего нужно записать начальные,

Первый пример отзывчивого дизайна

33

или базовые, правила для большинства основных устройств, которые мы затем
будем наращивать для новых устройств и больших экранов.
Именно это мы и делаем: сначала прописываем основные стили и вводим медиазапрос только тогда, когда хотим что-то добавить.
Такой подход помогает мыслить в рамках принципа «сначала маленькие экраны» и позволяет постепенно наслаивать детали, когда приходит время настраивать
дизайн для больших экранов.

Адаптируем пример к большому экрану
Мы уже выяснили, что дизайн портится, когда ширина достигает 800 пикселей.
Поэтому внесем в простой пример кое-что новенькое: подстроим макет под
разные окна просмотра.
Для начала сделаем так, чтобы наше главное изображение не разрасталось — закрепим его в правой части экрана. Тогда вводный текст можно поместить в левую часть.
Затем снизу по левому краю расположим основную часть текста — рецепт (наш
«метод» приготовления булочек), а справа в маленькой врезке перечислим ингредиенты.
Проделать все это довольно просто: нужно лишь поместить соответствующие
стили в медиазапрос. Вот как выглядит страница после того, как мы добавили в нее
эти стили:

Рис. 1.7. С помощью нескольких правил в медиазапросе мы получаем макет для
больших экранов

34

Глава 1. Основы отзывчивого веб-дизайна

На маленьких экранах страница будет выглядеть так же, как и раньше, но, как
только сайт откроют на экране шириной 800 пикселей или больше, страница подстроится под новый макет.
Можно было бы добавить еще улучшений для красоты, но они не помогут лучше понять отзывчивость, так что я их опустил. Если интересно взглянуть на код,
который их содержит, скачайте код для этой главы на сайте http://rwd.education.
Вот добавленные стили разметки:
@media screen and (min-width: 800px) {
.IntroWrapper {
display: table;
table-layout: fixed;
width: 100%;
}
.MoneyShot,
.IntroText {
display: table-cell;
width: 50%;
vertical-align: middle;
text-align: center;
}
.IntroText {
padding: 0.5rem;
font-size: 2.5rem;
text-align: left;
}
.Ingredients {
font-size: 0.9rem;
float: right;
padding: 1rem;
margin: 0 0 0.5rem 1rem;
border-radius: 3px;
background-color: #ffffdf;
border: 2px solid #e8cfa9;
}

}

.Ingredients h3 {
margin: 0;
}

Неплохо, правда? С минимумом кода мы создали страницу, которая подстраивается под размер окна просмотра и выдает подходящий макет. А благодаря добавлению всего нескольких стилей мы получили еще более привлекательный
вариант.

Первый пример отзывчивого дизайна

Вот как теперь выглядит наша простая отзывчивая страница на iPhone:

Рис. 1.8. Еще несколько стилей — и наша страница выглядит приятнее

35

36

Глава 1. Основы отзывчивого веб-дизайна

А так она выглядит при ширине окна просмотра свыше 800 пикселей.

Рис. 1.9. Тот же HTML- и CSS-код, но другой макет для больших окон просмотра

Да, наш пример прост, но он описывает основную методологию создания отзывчивого веб-дизайна.
Повторим все самое важное из главы и базового примера:
y Используйте любой текстовый редактор, который вам нравится.
y Некоторые инструменты упрощают написание кода, но не стоит зацикливаться на их выборе.
y Отзывчивый дизайн стал возможен благодаря гибким макетам, отзывчивым
изображениям и медиазапросам.
y В заголовке HTML-кода нужно прописывать метатег, чтобы браузер знал,
как отображать страницу.
y Максимальная ширина изображения в CSS не должна превышать 100 % по
умолчанию.

Итоги

37

y

Брейкпоинт — это просто ориентир, обычно равный ширине экрана, который
используется в медиазапросе для изменения дизайна.
Когда вы пишете CSS-код для отзывчивого дизайна, начните с базовых
стилей, которые работают на любом устройстве. Отталкивайтесь от макетов
для маленьких экранов, а затем используйте медиазапросы, чтобы адаптировать его для больших.
Булочки со взбитыми сливками и джемом действительно вкусные.

y

y

Полную спецификацию медиазапросов CSS Media Queries (Level 3) можно найти
по ссылке http://www.w3.org/TR/css3-mediaqueries/.
А рабочий вариант CSS Media Queries (Level 4) можно найти здесь: http://dev.
w3.org/csswg/mediaqueries-4/.

Несовершенство нашего примера
В этой главе мы рассмотрели базовые составляющие простой отзывчивой вебстраницы с помощью HTML и CSS. Конечно, страница далека от идеальной,
и я простил бы вас за эпитеты «недоразвитая», «ленивая» и «уродливая». Но не
произносите это вслух: у меня ведь тоже есть чувства!
Этот базовый пример непохож на реальный проект и не отражает пределы наших возможностей.
А ведь еще нужно подумать о типографике, цветовых схемах, тенях и реакциях
на наведение. Изучить семантическую разметку, вопросы доступности, анимацию,
масштабируемую графику, формы и многое другое.
Ну вы поняли. А ведь мы едва поскребли по поверхности. Но не волнуйтесь.
Для этого и нужна оставшаяся часть книги.

Итоги
Теперь вы знаете самое важное для создания полностью отзывчивой веб-страницы.
Но как мы только что выяснили, совершенству нет предела.
В следующей главе речь пойдет о разметке HTML5. HTML — это каркас любой
веб-страницы или приложения, фундамент, на котором можно построить что-либо
значимое, воздух, которым дышит веб-сайт...
Ладно, у меня закончились аналогии. Скажу проще: HTML очень важен, так
что приступим.

2

Создание
HTML-разметки

HTML — это Hypertext Markup Language, язык гипертекстовой разметки. Он поз­
воляет размечать содержимое так, чтобы сделать его более понятным для устройств,
а в итоге и для людей.
Страницу можно создать вообще без CSS- или JS-кода. Но без HTML страниц
не бывает.
Думать, будто написание HTML дается легче всего, — распространенное заблуждение. Мой опыт подсказывает, что в HTML легко только ошибиться, не
более.
Также учтите, что ваш подход к HTML крайне важен для незрячих или слабовидящих пользователей: с его помощью можно превратить беспорядочную страницу в значимый, полезный и восхитительный опыт. Зрячие пользователи, которые по каким-то причинам полагаются на вспомогательные технологии, тоже
любят, когда страницы сверстаны как следует.
Качественная HTML-разметка — это не только про отзывчивый веб-дизайн.
Здесь все гораздо серьезнее: это обязательное условие доступности страницы для
всех пользователей.
Эта глава посвящена написанию разметки HTML. Мы рассмотрим словарь
HTML-языка, его семантику, или, более кратко, применение HTML-элементов
для описания содержимого разметки.

HTML называют рабочим стандартом (living standard). Несколько лет назад его
последнюю версию называли HTML5 — модным словцом, подразумевающим современные методы и подходы веб-разработки. Именно поэтому в названии этой
книги используется «HTML5 и CSS», а не «HTML и CSS». В 2012 году было даже
проще подчеркнуть современность методов, используя термины «HTML5» и« CSS3».
Но в 2020 году различия в названиях менее важны. С рабочим стандартом можно ознакомиться здесь: http://www.w3.org/TR/html5/.

В этой главе мы рассмотрим:

Создание HTML-разметки

y
y
y
y
y
y
y

39

правильное начало работы с HTML-страницами;
добрый HTML5;
разделение, группировку и текстовые элементы;
использование HTML-элементов;
применение WCAG и WAI-ARIA для повышения доступности веб-при­
ложений;
встраивание медиа;
отзывчивое видео и окна iframe.

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

Базовая структура HTML-страницы выглядит так:




Web Page Structure




При написании HTML вы обычно «размечаете», или вставляете содержимое
в ряд тегов или элементов. У большинства HTML-элементов есть открывающий
и закрывающий теги. Некоторые из них, такие как meta, являются самозакрывающимися и не имеют отдельных закрывающих тегов.

Самозакрывающиеся теги перечислены здесь: https://html.spec.whatwg.org/
multipage/syntax.html#void-elements.
Еще они называются пустыми элементами, потому что у них нет содержимого.
Сейчас к ним относятся area, base, br, col, embed, hr, img, input, link, meta,
param, source, track и wbr.

Дадим пример открывающего и закрывающего HTML-тегов. Абзац текста помечают открывающим тегом в начале и закрывающим тегом в конце.
Обратите внимание на слеш, которая отличает закрывающий тег.
Сейчас мы обсудим раздел заголовка, который представляет собой содержимое
между тегами , но имейте в виду, что львиная доля разработки HTML
выполняется в разделе body.

40

Глава 2. Создание HTML-разметки

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





Элемент doctype
Итак, что у нас тут? Прежде всего, мы открыли документ, объявив HTML5 его тип:


Если вы фанат нижнего регистра, можете записать объявление в виде . Разницы нет.

Тег html и атрибут lang
После объявления doctype открывается html — корневой тег документа. В нем есть
атрибут lang, указывающий язык документа. Затем открывается раздел :



УКАЗАНИЕ АЛЬТЕРНАТИВНЫХ ЯЗЫКОВ
В соответствии со спецификациями W3C (http://www.w3.org/TR/html5/dom.html#thelang-and-xml:lang-attributes) атрибут lang указывает основной язык содержания
элемента и его атрибутов, включающих текст. Это особенно важно для вспомогательных технологий вроде экранных дикторов. Если вы не пишете страницы на
английском, укажите код языка контента. Например, для японского тег html должен выглядеть так: . Полный перечень языков можно найти
на странице http://www.iana.org/assignments/language-subtag-registry.

Добрый HTML5

41

Кодировка символов
Наконец, мы указываем кодировку символов, которая просто сообщает браузеру,
как анализировать информацию. Поскольку meta — это самозакрывающийся элемент, закрывающий тег ему не нужен.


Если нет веской причины указать иное, значение кодировки всегда будет utf‑8.

Добрый HTML5
Если вы привыкли аккуратно писать код HTML, то, скорее всего, используете
строчные буквы, заключаете значения атрибутов в прямые кавычки (не круглые!)
и объявляете типы для скриптов и таблиц стилей, на которые ссылаетесь. Например, так выглядит ваша ссылка на таблицу стилей:


Но для HTML5 такая точность вовсе не обязательна. Он легко поймет эту же
строку в таком виде:


Заметили? В конце элемента нет конечного слеша, нет кавычек вокруг значений
атрибутов и нет объявления типа. Но HTML5-коду все равно. Второй пример
такой же рабочий, как и первый.
Такой нестрогий синтаксис применяется по всему документу, а не только
в ссылках на ресурсы. Например, если хотите, можете определить div следующим
образом:


И это будет вполне приемлемый код HTML5. То же самое касается вставки
изображения:


Еще один пример допустимого HTML5. Никакого слеша, никаких кавычек (хотя
они все же нужны, если в значении есть пробелы). Регистр пляшет. Можно даже
опустить открывающий тег , и страница все равно будет работать!

Хотите отличный шаблон для HTML5? Зайдите на сайт HTML5 Boilerplate (http://
html5boilerplate.com/). Там собраны лучшие примеры HTML5-файлов. А еще вы можете настроить этот шаблон под свои потребности.

42

Глава 2. Создание HTML-разметки

Разумный подход к HTML-разметке
Лично мне нравится строгая разметка: с закрывающими тегами, кавычками для
значений атрибутов и единым регистром символов. Кто-то скажет, что избавление
от подобной практики позволит сэкономить несколько байтов данных, но для
этого есть специальные инструменты (с их помощью можно убрать все ненужные
символы и данные). Я же хочу, чтобы разметка была как можно разборчивее,
и призываю всех поступать так же. Не стоит стремиться к краткости кода в ущерб
его ясности.
На мой взгляд, при создании HTML-документов можно писать чистый и разборчивый код и в то же время пользоваться экономией, предлагаемой HTML5.
К примеру, так я бы сослался на CSS:


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

Несмотря на свободный синтаксис HTML5, все же стоит проверить корректность
разметки. Проверки помогают выявить типичные ошибки вроде недостающих или
перепутанных тегов, отсутствующих атрибутов alt у изображений, неправильно
вложенных элементов и т. д. Для этих целей был создан механизм проверки на
соответствие стандартам W3C, который можно найти на сайте http://validator.
w3.org/.

Ну, хватит мне уже осуждать создателей небрежной разметки. Посмотрим на
преимущества, которые дает HTML5.

Да здравствует могущественный тег !
— это, пожалуй, самый важный и определяющий HTML-тег. Это якорный тег,

который используется для перехода по ссылке из документа, в котором находится
пользователь, в другой документ в интернете или в другую точку того же документа.

Спецификация элемента здесь: https://www.w3.org/TR/html52/textlevel-semantics.
html#the-a-element.

Новые семантические элементы в HTML5

43

Преимущество HTML5 в том, что в тег можно вложить несколько элементов. Раньше приходилось заключать каждый элемент в отдельный тег . Взгляните на следующий код:
The home page
This paragraph also links to the home page


Сегодня мы можем отказаться от такой практики и вместо этого обернуть в
группу элементов:

The home page
This paragraph also links to the home page



Но не забывайте об ограничениях: по понятным причинам нельзя обернуть
один тег другим или поместить его внутрь другого интерактивного элемента (например, кнопки). Нельзя также обернуть форму тегом .
Нет, физически вы, конечно, можете это сделать. Сомневаюсь, что текстовый
редактор начнет с вами ругаться по этому поводу. Но в таком случае не удивляйтесь, когда в браузере что-то пойдет не так.

Новые семантические элементы в HTML5
В словаре семантика определена как «раздел лингвистики и логики, изучающий
смысловое значение». Для нас семантика — это придание смысла разметке. Почему она важна?
Большинство сайтов придерживаются довольно стандартных структурных
соглашений. Типичные области — заголовок (header), подвал (footer), боковая
панель (sidebar), панель навигации (navigation bar) и т. д. Разработчики вебприложений часто дают div-элементам говорящие имена, чтобы показать их принадлежность к определенным областям (например, ).
Но любой пользовательский агент, включая веб-браузер, экранный диктор или
сканер поисковой системы, не может по ходу точно определить, какова цель каждого из этих элементов div. HTML5 решает эту проблему с помощью новых семантических элементов.

Чтобы просмотреть полный список элементов HTML5, устройтесь (максимально)
поудобней и укажите путь своему браузеру: http://www.w3.org/TR/html5/semantics.
html#semantics.

44

Глава 2. Создание HTML-разметки

Не будем здесь рассматривать все новые элементы: пройдемся лишь по тем,
которые я считаю наиболее полезными или интересными для рутинной работы
над отзывчивым веб-дизайном. После изучения этих элементов и их назначения
подумаем, как их лучше размечать, на нескольких примерах. В конце главы я поставлю перед вами более серьезную задачу.
С точки зрения спецификации HTML элементы, которые мы рассмотрим,
можно разбить на три группы:
y Элементы секционирования для самых широких штрихов на HTMLстранице. Их используют для областей верхнего и нижнего колонтитулов
и боковой панели.
y Группирующие элементы для обертывания связанных элементов: абзацы,
блоки цитирования и т. п.
y Семантика на уровне текста — элементы для обозначения деталей, например
выделенный полужирным или курсивным шрифтом текст или код.
Теперь по очереди рассмотрим наиболее полезные элементы из этих групп.

Элемент main
В HTML5 долго не было элемента для выделения основного содержимого страницы. Считалось, что содержимое, которое не находилось внутри одного из новых
семантических элементов HTML5, по умолчанию было основным. К счастью, теперь есть более декларативный способ группировки основного содержимого — тег,
метко названный . Что бы в него ни заключалось — главное содержимое
страницы или главный раздел веб-приложения — он служит для группировки
всего основного. В спецификации сказано:
Область основного содержимого документа включает уникальную для этого
документа информацию и исключает содержимое, повторяющееся в наборе
документов, такое как имеющиеся на сайте навигационные ссылки, информация об авторском праве, логотипы и баннеры сайта, а также формы поиска (кроме случаев, когда основной документ или основная функция приложения — это форма поиска).
Также стоит отметить, что на каждой странице не должно быть более одного
main (в конце концов, не бывает двух главных частей содержимого) и его не сле-

дует использовать в качестве дочернего элемента какого-либо другого семантического элемента HTML5, такого как article, aside, footer, nav или header.
Подробнее об элементе читайте на http://www.w3.org/TR/html5/groupingcontent.html#the-main-element.

Новые семантические элементы в HTML5

45

Элемент section
Элемент используется для выделения раздела документа или приложения. Например, можно создать один раздел для контактной информации, другой —
для ленты новостей и т. д. Помните, что он не предназначен для стилизации.
Если нужно обернуть элемент только ради его стилизации, тогда лучше уж
используйте div.
При работе с веб-приложениями я предпочитаю использовать section в качестве
элемента-контейнера для визуальных компонентов, поскольку он позволяет обозначить начало и конец компонента в разметке.
Вы можете также понять, стоит ли использовать section, по наличию или отсутствию заголовков у содержимого (например, h1). В случае если такого заголовка нет, пожалуй, лучше использовать div.
Чтобы узнать, что в спецификации W3C говорится о , перейдите по
ссылке: http://www.w3.org/TR/html5/ section.html # the-section-element.

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

Об элементе можно узнать больше из спецификации W3C: http://www.
w3.org/TR/html5/sections.html#the-nav-element.

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

46

Глава 2. Создание HTML-разметки

сайты без потери смысла. Или подумайте, сможет ли содержимое стать
отдельной статьей RSS-канала. Очевидные примеры подходящего контента — сообщения в блогах или новостные статьи. Имейте в виду, что, если один элемент
вложен в другой, предполагается, что они связаны (т. е. вложенный
относится к своему контейнеру).

Спецификация элемента здесь: http://www.w3.org/TR/html5/sections.
html#the-article-element.

Элемент aside
Элемент используется для содержимого, которое связано с основным
контентом, но лишь косвенно. Я часто использую его для боковых панелей или
содержимого как небольшую подсказку по соответствующей теме в сообщении
блога. Он также вполне подходит для цитат, рекламы и групп элементов навигации — всего, что не имеет прямого отношения к основному содержимому. Если бы
речь шла об онлайн-магазине, я бы выделил такие области, как «Клиенты, купившие это, также покупают», в качестве главных кандидатов на заключение в .

Об элементе можно узнать больше из спецификации W3C: http://www.
w3.org/TR/html5/sections.html#the-aside-element.

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

Вот что говорится в спецификации W3C об элементе : http://www.w3.
org/TR/html5/sections.html#the-header-element.

Элемент footer
Как и , элемент не участвует в алгоритме структурирования (подробнее об этом в следующем разделе) и не разделяет содержимое, зато подходит

Новые семантические элементы в HTML5

47

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

Спецификация W3C для элемента здесь: http://www.w3.org/TR/html5/
sections.html#the-footer-element.

Алгоритм схемы HTML5
Обычно в начале HTML-документа элементом h1 обозначается заголовок главной
страницы, затем используются элементы подзаголовков, если они есть, и т. п.
Но HTML5 предоставляет каждому контейнеру секционирования собственную
автономную схему. Это позволяет вам сосредоточиться на контейнере секционирования, а не на уровне заголовка в документе, в котором вы сейчас работаете.
Сейчас вы поймете, как это может пригодиться. В качестве иллюстрации настроим заголовки сообщений в блоге на использование тегов , в то время как
у заголовка самого блога тоже будет тег . Взгляните на эту структуру:
Ben's site

Ben's blog
All about what I do



A post about something
Trust me this is a great read
No, not really
See. Told you.



Да, у нас сразу несколько заголовков , но структура по-прежнему выглядит
так:
1. Сайт Бена (Ben’s site).
2. Блог Бена (Ben’s blog).
3. Какой-то пост (A post about something).
Так что теоретически вам не придется отслеживать элемент заголовка, который
необходимо использовать. Вы сможете применить любой необходимый уровень

48

Глава 2. Создание HTML-разметки

заголовка в каждом фрагменте разделенного на секции содержимого, и алгоритм
структуры HTML5 правильно его отобразит.
Вы можете проверить структуру своих документов с помощью планировщиков
HTML5. Вот ссылки на пару инструментов:
y

http://gsnedders.html5.org/outliner/

y

http://hoyois.github.com/html5outliner/

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

Замечания относительно элементов h1–h6
Раньше я не знал, что лучше не использовать теги h1–h6 для разметки заголовков
и подзаголовков. Я говорю о таких вещах:
Scones:
The most resplendent of snacks

Вот цитата из спецификации HTML5:
Элементы h1–h6 нельзя использовать для разметки подзаголовков, субтитров,
альтернативных заголовков и слоганов, если они не предназначены для использования в качестве заголовка для нового раздела или подраздела.
Так нам сказали!
И как мы должны создавать такой контент? В спецификации на самом деле
есть целый раздел, посвященный этому: http://www.w3.org/TR/html5/common-idioms.
html#common-idioms. Лично мне нравится элемент , но, к сожалению, он
устарел (см. раздел Obsolete HTML features — «Устаревшие функции HTML»).
Так что, следуя советам спецификации, перепишем наш предыдущий пример:
Scones:
The most resplendent of snacks

Итак, мы рассмотрели львиную долю элементов секционирования HTML.
Теперь перейдем к изучению элементов группировки.

Элемент
Самый распространенный элемент группировки — это . Сам по себе он бессмысленный, поэтому его так широко используют. Он ничего не передает. Единственное подразумеваемое значение div — то, что он что-то группирует. Несмотря
на это, вы часто будете замечать div, в котором нет ничего, кроме строчки текста.

Новые семантические элементы в HTML5

49

Обращайтесь к div только в крайнем случае. Его следует использовать лишь
тогда, когда ничего лучше не придумать.
Сегодня в HTML больше элементов, чем когда-либо прежде. Надеюсь, дальше
мы познакомимся с теми из них, которые лучше подойдут для тех задач, в решении
которых вы пока что используете div.

Элемент
Элемент используется для разметки абзаца. Но не спешите думать, будто его
можно применять только к тексту длиной в 3–4 строки. Наоборот, размечайте с его
помощью любой текст, который с каким-либо другим элементом будет выглядеть
хуже. Для неспецифического текста элемент p определенно предпочтительнее, чем
div.

Элемент
Элемент blockquote используется для разметки цитат. Дополнительно оборачивать текст каким-либо другим элементом не нужно, хоть вы и можете это сделать.
Например, зная, как используется p, мы можем поместить его внутри blockquote,
если захотим. Вот простой пример разметки цитаты. Сначала дается вводный абзац текста в теге p, а затем blockquote:
I did like Ben's book, but he kept going on about scones. For example:

All this writing about scones in our sample page and there's no image of
the beauties! I'm going to add in an image of a scone near the top of the
page; a sort of 'hero' image to entice users to read the page.


В спецификации HTML есть несколько хороших примеров использования
кавычек: https://html.spec.whatwg.org/multipage/grouping-content.html#the-blockquoteelement.

Элементы и
В спецификации HTML говорится, что элемент figure:
...может использоваться для подписи иллюстраций, диаграмм, фотографий,
листингов кода и т. д.
Мы используем его для создания визуальных элементов, а сопровождающий
его элемент — для добавления текста, поддерживающего эти визуальные элементы. В отличие от атрибута alt тега , где мы всегда должны

50

Глава 2. Создание HTML-разметки

указывать текст для поддержки вспомогательных технологий и смягчения проблем
загрузки изображений, figcaption не обязательно добавлять к изображению. Он
лишь добавляет видимое пользователю описание визуальных элементов. Вот как
мы можем исправить часть кода из главы 1:



This image isn't of scones I have made, instead it's a stock photo
from Wikipedia



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

Спецификация figure здесь: http://www.w3.org/TR/html5/grouping-content.html#thefigure-element. Спецификация figcaption здесь: http://www.w3.org/TR/html5/
grouping-content.html#the-figcaption-element.

Элементы и
Наверное, вам не раз хотелось создать на странице простой виджет, по щелчку на
который открывается панель с дополнительной информацией. HTML5 облегчает
его создание с помощью элементов details и summary. Взгляните на разметку (можете открыть файл example3.html из каталога кода для этой главы и поиграть с виджетом):

I ate 15 scones in one day

Of course I didn't. It would probably kill me if I did. What a way
to go.
Mmmmmm, scones!



Этот файл, открытый в браузере Chrome без добавления какого-либо стиля,
покажет изначально только текст из summary.

Новые семантические элементы в HTML5

51

Рис. 2.1. Элементы details и summary пытаются решить общую проблему,
но их реализация ограничена

Щелкните в любом месте строчки из summary — перед вами откроется панель.
При повторном щелчке эта панель закрывается. Чтобы панель была сразу открытой, добавьте к элементу details атрибут open:

I ate 15 scones in one day

Of course I didn't. It would probably kill me if I did. What a
way to go.
Mmmmmm, scones!



Рис. 2.2. При добавлении атрибута open содержимое по умолчанию отображается

Браузеры, которые поддерживают эти элементы, обычно указывают на возможность открытия панели с помощью стиля. Так, в браузере Chrome (а также Safari)
отображается темный треугольник. Каждый браузер имеет собственные реализации маркеров детализации. Поскольку такого рода селекторы обычно не определены спецификациями W3C, используйте фирменный псевдокласс для их отключения (обратите внимание на префикс -webkit-):
summary::-webkit-details-marker {
display: none;
}

Разумеется, этот же селектор можно использовать для другого стилевого оформления маркера.

52

Глава 2. Создание HTML-разметки

На сегодняшний день нет анимации закрытия и открытия. Нет также (без кода
JavaScript) способа закрытия панелей подробностей (отображаемых на том же
уровне) при открытии других панелей. Не уверен, что эти возможности воплотятся в жизнь. Вместе с тем я обнаружил, что полезность этих элементов сама по себе
довольно ограничена. Их следует воспринимать в основном как способ упрощения
работы, связанной с переключением display: none; на стандартном div с помощью
кода JavaScript.

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

Подробнее об в спецификации W3C HTML5: http://www.w3.org/TR/
html5/sections.html#the-address-element.

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

Семантика HTML на уровне текста
До HTML5 семантические элементы на уровне текста в спецификациях назывались встроенными. Так что если раньше у вас на слуху были только «встроенные»
элементы, знайте: мы говорим именно о них.
Раздел спецификации HTML, в котором подробно описывается семантика на
уровне текста, можно найти по ссылке: http://www.w3.org/TR/html5/text-level-semantics.
html#text-level-semantics.
Рассмотрим наиболее распространенные и полезные текстовые элементы.

Семантика HTML на уровне текста

53

Элемент
Элемент span — текстовый эквивалент div. Он идеально подходит для простого
размещения текста для его стилизации.

Элемент
Раньше элемент означал «выделить жирным шрифтом» (http://www.w3.org/TR/
html4/present/graphics.html#edef-B). Но теперь официально его можно использовать
только в качестве стилевой привязки в коде CSS, поскольку в текущей спецификации HTML5 о нем сказано следующее:
Элемент b является представлением фрагмента текста, на который обращается внимание пользователя, без придания ему какой-либо особой важности и интонационного акцентирования. Это могут быть, к примеру, выделяемые в документе ключевые слова, наименования товаров в обзоре,
побуждающие к действию слова в интерактивном, управляемом текстом
программном средстве или же первый абзац статьи.
Хотя сейчас этому элементу не придается конкретного смысла, поскольку он
относится к уровню текста, не стоит заключать в него большие группы элементов
разметки: лучше используйте div.
Причем если вам нужно, чтобы содержимое, помещенное внутрь тега , не
выводилось на экран жирным шрифтом, переключите свойство font-weight в CSS.
Например:
b {
}

font-weight: normal;

Элемент
Чтобы выделить что-то серьезное, срочное или важное, элемент — это то,
что нужно. Вот как в спецификации определены варианты его использования:
Важность. Элемент strong можно использовать в заголовке, комментарии
или абзаце, чтобы отличить действительно важную информацию от других
частей: подробностей, отступлений или шаблонов.
Серьезность. Элемент strong можно использовать для обозначения предупреждения или предостережения.
Срочность. Элемент strong можно использовать для обозначения содержимого, которое пользователь должен увидетьраньше, чем другие части документа.

54

Глава 2. Создание HTML-разметки

Полная спецификацию элемента здесь: https://www.w3.org/TR/html52/
textlevel-semantics.html#the-strong-element.

Элемент
Каюсь, я часто пользовался элементом , чтобы выделять текст курсивом. Мне
следует пересмотреть свои позиции, приняв во внимание определение из спецификации HTML:
Элемент em акцентирует внимание на своем содержимом.
Следовательно, пока вы не хотите акцентировать внимание на содержимом
внутри элемента, пользуйтесь или, там, где это уместно, тегами или .

Элемент
В спецификации HTML5 сказано, что элемент обслуживает
...отрывок текста, выделяемый в том числе интонационно, или выпадающий
из общего ряда повествования.
То есть он не используется просто для выделения чего-либо курсивным шрифтом. Например, он подойдет для разметки в строке текста какого-либо необычного названия:
However, discussion on the hgroup element is now frustraneous as it's
now gone the way of the Raphus cucullatus.

Или если вы разметили кнопку в веб-приложении для заказа еды, то могли бы
сделать следующее:

French Fries No Salt Added


В HTML есть множество других семантических текстовых элементов; полный
список можно найти в соответствующем разделе спецификации: http://www.w3.org/
TR/html5/text-level-semantics.html#text-level-semantics.

Устаревшие функции HTML
Если вы пишете код HTML в течение нескольких лет, вы, возможно, удивитесь,
узнав, что некоторые HTML-элементы устарели. В HTML5 есть две разновидности

Практическое применение HTML‑элементов

55

устаревших функций: соответствующие и несоответствующие. Соответствую­щие
функции все еще работают, но при их использовании системы проверки выдают
предупреждения. На практике лучше по возможности не применять их, но если вы
все же это делаете, небеса не рухнут на землю. Несоответствующие функции могут
по-прежнему отображаться в некоторых браузерах, но гарантий нет.
Перечень устаревших несоответствующих функций весьма обширен. Признаться, многими из них я никогда не пользовался (а некоторые даже никогда не
видел). Возможно, в вашем случае ситуация аналогичная. Полный перечень устаревших несоответствующих функций, среди которых есть strike, center, font, acronym,
frame и frameset, можно найти по ссылке http://www.w3.org/TR/html5/obsolete.html.
Есть также функции, фигурировавшие в предварительных версиях HTML5,
которые теперь попали в число отвергнутых, например hgroup. Изначально предполагалось использовать этот элемент в качестве контейнера для групп заголовков,
то есть h1 как основной заголовок и h2 как подзаголовок могли помещаться внутрь
элемента hgroup. Но теперь элемент hgroup пошел по пути вымершего Маврикийского дронта (Гугл в помощь).

Практическое применение
HTML‑элементов
Настало время применить некоторые из рассмотренных элементов на практике.
Вернемся к примеру из главы 1. Если сравнить разметку, показанную ниже, с разметкой из главы 1 (напоминаю, что все примеры можно загрузить с сайта http://
rwd.education), то можно увидеть, где добавлены новые элементы:



Scones: the most resplendent of snacks



Occasionally maligned and misunderstood; the scone is a quintessentially British classic.




Incredible scones, picture from Wikipedia



56

Глава 2. Создание HTML-разметки


Recipe and serving suggestions follow.

Ingredients


Method


Made for the book,
'Responsive web design with HTML5 and CSS'
by
Ben Frain



Чтобы сконцентрироваться на структуре, я убрал довольно много содержимого. Надеюсь, вы согласитесь, что отличить разделы разметки друг от друга несложно. Дам вам прагматичный совет: мир не рухнет, если вы не станете всякий раз
выбирать правильный элемент для каждой отдельно взятой ситуации.
Например, неважно, что бы я применил, или , — ничего плохого не случится из-за «неверного» выбора. Если вместо предписанного элемента
использовать , это не будет преступлением против человечества и ребята из
W3C не откроют на вас охоту и не станут вас очернять за неверное решение. Просто руководствуйтесь здравым смыслом. И все же постарайтесь разумно использовать такие элементы, как и . Уверен, что вы выше того, чтобы
использовать в разметке одни только элементы div!

Использование WCAG и WAI-ARIA для
повышения доступности веб‑приложений
Со времени первого издания данной книги (2011 и 2012 годы) консорциум W3C
добился многого в деле упрощения для разработчиков написания более доступных
веб-страниц.

WCAG
Руководство по обеспечению доступности веб-контента (WCAG) существует с целью предоставления
единого общего стандарта для доступности веб-контента, отвечающего на
международной основе нуждам физических лиц, организаций и правительств.

Использование WCAG и WAI-ARIA для повышения доступности веб‑приложений

57

Когда речь заходит о более простых веб-страницах (в противовес единой странице веб-приложений и подобных средств), имеет смысл ориентироваться на
руководство WCAG. Оно предлагает целый ряд (в основном вполне разумных)
рекомендаций по обеспечению доступности веб-контента. Каждая рекомендация
оценивается по уровням соответствия: A, AA или AAA. Дополнительные сведения
об этих уровнях можно найти по ссылке http://www.w3.org/TR/ UNDERSTANDINGWCAG20/conformance.html#uc-levels-head.
Возможно, вы уже придерживаетесь многих из рекомендаций, например добавляете альтернативный текст к изображениям. Краткое изложение рекомендаций
есть здесь: http://www.w3.org/WAI/ WCAG20/glance/Overview.html. А еще можно создать
собственный краткий контрольный лист-справочник по образцу отсюда: http://
www.w3.org/ WAI/WCAG20/quickref/.
Потратьте пару часов на изучение списка. Многие рекомендации совсем не
трудно выполнить и тем самым улучшить пользовательский опыт.

WAI-ARIA
Стандарт доступности интернет-приложений для людей с ограниченными возможностями (WAI-ARIA) предназначен главным образом для решения проблем
доступности динамического контента на веб-странице. Он объясняет средства
описания атрибутов, состояний и свойств для специализированных виджетов (динамических разделов в веб-приложениях), которые могли бы применять пользователи, нуждающиеся во вспомогательных технологиях. Например, если выведенный на экран виджет показывает постоянно обновляемые биржевые котировки,
то как сделать их доступными для незрячего пользователя? Стандарт WAI-ARIA
пытается решать проблемы подобного рода.
Вопрос полной реализации ARIA в веб-приложениях выходит за рамки этой
книги. Но, если вы работаете именно над таким проектом, ознакомьтесь с информацией по ссылке http://www.w3.org/WAI/intro/aria. А сейчас мы рассмотрим некоторые из наиболее важных моментов в заголовках.
Для начала обратите внимание, что раньше было желательно добавлять атрибуты в верхние и нижние колонтитулы вроде этого:
A header with ARIA landmark banner role . Теперь же атрибут role = "banner" считается излишним. Загляните в спецификации любого из
перечисленных элементов — вы найдете специальный раздел допустимых значений
ARIA-атрибута role — Allowed ARIA role attributes. В качестве примера приведу
разъяснения из раздела элемента:
Разрешенные значения ARIA-атрибута role: region role (по умолчанию не
устанавливается), alert, alertdialog, application, contentinfo, dialog,
document, log, main, marquee, presentation, search или status.

58

Глава 2. Создание HTML-разметки

Основная часть здесь — «role» (по умолчанию не устанавливается). Это означает, что явное добавление ARIA-роли к элементу бессмысленна, поскольку она
подразумевается самим элементом. Этот момент поясняется в примечании к спе­
цификации:
В большинстве случаев установка ARIA-атрибута role и/или атрибута
aria-*, соответствующего исходной подразумеваемой ARIA-семантике, является излишней и не рекомендуется, поскольку эти свойства уже установлены браузером.
Самое простое, что можно сделать с прицелом на применение вспомогательных
технологий, — это по возможности пользоваться правильными элементами. Элемент header окажется намного полезнее, чем div class="Header". Точно так же,
если у вас на странице есть кнопка, воспользуйтесь , а не или
другим элементом, стилизованным под кнопку.

Развитие стандарта ARIA
В W3C есть надежный набор доступных паттернов проектирования: https://www.
w3.org/TR/wai-aria-practices-1.1/examples/#examples_by_props_label.

Можно бесплатно протестировать свой дизайн с помощью NVDA
(non-visual desktop access)
Если вы ведете разработку под Windows и хотите протестировать конструкции,
спроектированные согласно стандарту ARIA, с помощью экранного диктора,
воспользуйтесь средством NVDA: http://www.nvda-project.org/.
Google тоже поставляет бесплатный инструмент для разработки доступных сайтов — Accessibility Developer Tools. Он предназначен для браузера Chrome (есть
и кросс-платформенные версии).
К тому же постоянно пополняется арсенал средств, помогающих быстро протестировать ваши конструкции на пригодность к использованию их людьми с нарушенным цветовосприятием. Например, по ссылке https://michelf.ca/projects/simdaltonism/ есть Mac-приложение, позволяющее переключать типы нарушения
цветовосприятия и просматривать предварительные результаты на плавающей
палитре.

Надеюсь, краткое введение в WAI-ARIA и WCAG поможет вам освоить поддержку вспомогательных технологий. Возможно, добавление такой поддержки
окажется проще, чем вы думали. И в заключение укажу еще один ресурс, касающийся всех вопросов доступности, в котором есть масса полезных ссылок и советов, — это домашняя страница проекта A11Y: http://a11yproject.com/.

Медиавозможности, встроенные в HTML5

59

Медиавозможности, встроенные
в HTML5
Многие услышали об HTML5, когда Apple отказалась добавлять поддержку Flash
на iOS-устройства. Технология Flash доминировала на рынке (некоторые утверждают, что она его и вовсе захватила) в качестве дополнительного модуля для обслуживания видео в браузере. Но вместо использования технологии от Adobe
Apple в вопросах вывода на экран сложного медиасодержимого решила положиться на HTML5. HTML5 неплохо справился с задачей, а публичная поддержка со
стороны Apple дала этой версии могучий толчок и сделала медиаинструменты
HTML5 привлекательными для широкой аудитории.
Мы уже обсуждали, что сегодня люди склонны использовать термин «HTML»
вместо «HTML5», но в отношении медиа различие имело значение. До HTML5
добавление видео и аудио в разметку было не таким удобным. Теперь эта задача
упростилась.

Добавление видео и аудио в разметку HTML
Работать с видео и аудио в HTML довольно просто. Вот пример ссылки на видео­
файл из разряда «проще некуда»:


В HTML со всей трудной работой справляется один-единственный элемент
(или для аудио). Между открывающим и за-

крывающим тегами можно вставить текст: он будет отображаться, если у пользователя возникнут проблемы с загрузкой. Можно добавить дополнительные атрибуты, например задать высоту и ширину. Сделаем это:
If you're reading this
either the video didn't load or your browser is waaaayyyyyy old!

Теперь, если добавить предыдущий фрагмент кода на страницу и посмотреть
на его работу в любом браузере, видео появится, но без элементов управления его
воспроизведением. Чтобы получить возможность управлять видео, нужно добавить
атрибут controls. В качестве примера можно добавить атрибут autoplay, но вообще этого лучше не делать: автовоспроизведение выбесит кого угодно! Вот как
выглядит код с этими атрибутами:
If
you're reading this either the video didn't load or your browser is
waaaayyyyyy old!

60

Глава 2. Создание HTML-разметки

Результат выполнения этого фрагмента показан на скриншоте.

Рис. 2.3. Мы вставили видео на страницу, добавив минимум кода

В число прочих атрибутов входят preload для управления предварительной
загрузкой медиа, loop для повторного воспроизведения и poster для определения
кадра заставки для видео (изображение, отображающееся во время загрузки видео).
Для применения атрибута достаточно вставить его в тег. Вот как выглядит пример,
включающий все эти атрибуты:
If you're reading
this either the video didn't load or your browser is waaaayyyyyy
old!

Резервные возможности
Элемент позволяет при необходимости добавить резервные возможности. Например, наряду с видео в формате MP4 можно обеспечить поддержку другого формата. Кроме того, если у пользователя в браузере нет подходящей технологии проигрывания, можно предоставить ссылки на скачивание видеофайлов.
Рассмотрим такой пример:



Медиавозможности, встроенные в HTML5

61


Download Video: MP4 Format: "MP4"


Здесь мы сначала указали выдуманный видеоформат super8. Браузер считывает
код сверху вниз, решая, какой файл воспроизводить. Если он не поддерживает формат
super8, то переходит к следующему — в нашем случае mp4. В итоге браузер переходит
по ссылкам для скачивания, если не может согласовать какой-либо из перечисленных
форматов. Атрибут type сообщает браузеру MIME-тип файла. Без этого атрибута
браузер получит контент и все равно попытается воспроизвести его. Но если вы
знаете MIME-тип, лучше добавьте его. Предыдущий пример кода и образец видеофайла в формате MP4 (по чистой случайности это фрагмент сериала Coronation
Stree, в котором я снимался; тогда у меня еще были волосы и надежды сыграть
главную роль вместе с Де Ниро) находятся в разделе example2 кода для этой главы.

Работа audio и video практически ничем не различается
Элемент работает по таким же принципам и с такими же атрибутами (исключая width, height и poster), но у отсутствует область проигрывания
визуального содержимого.

Отзывчивое HTML5-видео и iFrames
Единственная проблема со столь понравившейся нам реализацией видео
в HTML5 — в ней нет отзывчивости. И действительно, в книге приведен пример
отзывчивой HTML5- и CSS-разметки, которая не реагирует на изменение условий
просмотра. К счастью, для встроенного HTML-видео это можно легко исправить.
Просто уберите из разметки все атрибуты высоты и ширины (например, удалите
width="640" height="480") и добавьте в CSS следующий код:
video {
max-width: 100%;
height: auto;
}

Да, с файлами, которые могут храниться на локальном устройстве, этот прием
работает вполне успешно. Но он не решает проблемы видео, встроенного в iFrame (низкий поклон YouTube, Vimeo и другим сайтам). Следующий код позволяет добавить трейлер фильма «Успеть до полуночи» из YouTube:


Но если добавлять этот код к странице в неизменном виде, то даже при использовании CSS-правила произойдет обрезка, если ширина окна просмотра будет
менее 960 пикселей.
Проще всего решить эту проблему с помощью небольшого CSS-трюка, впервые
примененного французским CSS-специалистом Тьерри Кобленцем (Thierry Ko-

62

Глава 2. Создание HTML-разметки

blentz), который создал, по сути, блок с правильным соотношением сторон для
содержащегося в нем видео. Собственные объяснения этого мага можно найти по
ссылке http://alistapart.com/article/creating-intrinsic-ratios-for-video.
Если лень самим вычислять и подставлять соотношение сторон, можно не заморачиваться: один онлайн-сервис способен сделать это за вас. Просто откройте
http://embedresponsively.com/ и поместите в адресную строку этого сайта URL-адрес
вашего iFrame. В результате вы получите простой фрагмент кода, который можно
вставить в собственную разметку.
К примеру, для трейлера фильма «Успеть до полуночи» ресурс выдает следую­
щее (обратите внимание на значение padding-bottom для определения соотношения
сторон):

.embed-container {
position: relative;
padding-bottom: 56.25%;
height: 0;
overflow: hidden;
max-width: 100%;
height: auto;
}
.embed-container iframe,
.embed-container object,
.embed-container embed {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}





Вот и все! Просто добавьте этот фрагмент в код и получите полностью адаптируемое YouTube-видео (примечание: дети, не берите пример с мистера Де Ниро —
курить вредно!).

Итоги
В этой главе мы рассмотрели много всего, начиная с основ создания страницы,
проходящей проверку на соответствие стандартам HTML5, и заканчивая встраи-

63

Итоги

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

Упражнение
Мы рассмотрели множество HTML-элементов. Это лишь малая часть всех существую­
щих элементов, но мы, безусловно, рассмотрели те из них, которые могут вам понадобиться в ежедневной работе. Предлагаю сделать небольшое упражнение, чтобы увидеть, как много вы поняли. Вот скриншот с веб-дизайном сайта для этой книги:

Рис. 2.4. Веб-дизайн сайта, разработанного для этой книги

64

Глава 2. Создание HTML-разметки

Если у вас macOS, вы можете получить исходный файл Sketch: он включен в загружаемый код под названием RWD3e_design.sketch.

Взгляните на дизайн и попробуйте создать для него HTML-страницу. Рассмотрите часть заголовка. Подумайте о языке контента и о метатегах, которые могут
вам понадобиться. Затем подумайте о визуальных эффектах. Какие элементы
лучше использовать для создания раздела навигации? Как быть с каждым из этих
маленьких разделов под изображением книги? А как насчет блока DOWNLOAD
CODE? Есть идеи, как его разметить?
Сайт https://rwd.education покажет, что выбрал я. Но постарайтесь не заглядывайть туда, пока не попробуете сами!

3

Медиазапросы —
поддержка различных
окон просмотра

В этой главе подробно рассматриваются CSS-медиазапросы. Надеюсь, вы сможете полностью понять их возможности, синтаксис и пути развития. По необходимости мы будем использовать медиазапросы для настройки базовой разметки нашего тестового сайта, добавляя стили для более широких экранов.
Мы завершили предыдущую главу разговором о дизайне веб-сайта https://rwd.
education/. Для этой главы я написал черновую разметку и добавил несколько базовых «мобильных» стилей.
Если вы откроете файл index.html в папке start этой главы в браузере, то увидите, что страница выглядит приемлемо на устройствах с малыми экранами, таких
как мобильные телефоны (рис. 3.1).
Но в широком окне браузера она выглядит несколько растянуто (рис. 3.2).
Исходные стили были написаны с помощью отзывчивого/пропорционального
подхода: ширина страницы зависела от процентного соотношения сторон экрана,
а не указывалась в фиксированных величинах (пикселях). Мы стремились к тому,
чтобы содержимое расширялось и сужалось, заполняя окно браузера по мере изменения его размера.
Но по достижении определенной ширины экрана нужно вносить более весомые
изменения в дизайн, а не просто дальше расширять его элементы.
Эту проблему могут решить медиазапросы.
Медиазапросы позволяют определить целевое назначение конкретных CSSстилей с учетом возможностей устройства. Например, с помощью всего лишь
нескольких строк CSS-кода мы можем изменить способ отображения контента
в зависимости от таких параметров, как ширина окна просмотра, соотношение
сторон экрана, ориентация экрана (альбомная или портретная) и т. д.
В этой главе нам предстоит:
y разобраться в том, что представляет собой метатег viewport, позволяющий
медиазапросам правильно работать на мобильных устройствах;
y узнать, зачем медиазапросы нужны в отзывчивом веб-дизайне;

66

Глава 3. Медиазапросы — поддержка различных окон просмотра

Рис. 3.1. Дизайн выглядит неплохо в малых областях просмотра

разобраться в синтаксисе медиазапросов;
y научиться использовать медиазапросы в ссылках, правиле @import и внутри
файлов CSS;
y определить, какие свойства устройств поддаются тестированию;
y решить, нужно ли группировать медиазапросы или записывать их там, где
они потребуются;
y рассмотреть новейшие возможности Media Queries Level 4, например pointer,
hover и prefers-color-scheme.
Еще в главе 1 мы вставили метатег в заголовок веб-страницы, чтобы она работала на мобильных устройствах. В тот момент я пообещал, что в главе 3 объясню,
что это за тег. Пора выполнить обещание.
y

Метатег viewport

67

Рис. 3.2. Для широких областей просмотра дизайн определенно нужно поменять

Метатег viewport
В 2007 году с выходом iPhone компания Apple ввела собственный метатег —
viewport. Его предназначением было указывать браузерами мобильных устройств
предпочтительный способ вывода веб-страниц на экран.
Без этого метатега iPhone отображал бы страницы в окне шириной 980 пикселей, в котором вам пришлось бы масштабировать их.
С помощью этого метатега можно отобразить веб-страницу в ее фактическом размере, а затем адаптировать разметку для привычного нам отображения веб-страниц.
В обозримом будущем все веб-страницы, предназначенные для устройств с малым размером экрана, будут вынуждены использовать этот метатег, поскольку
Android и все большее число других платформ поддерживают его.
Вы уже знаете, что метатег viewport добавляется в тег HTML-кода. Он
может настраиваться на определенную ширину (которую, к примеру, можно выразить в пикселях) или содержать указание на масштаб, например 2.0 (удваивание
текущего размера). Рассмотрим пример использования viewport, настраивающего
вывод страницы в браузере в двойном масштабе (200 %):


68

Глава 3. Медиазапросы — поддержка различных окон просмотра

Разобьем предыдущий метатег на части, чтобы понять, что происходит. Атрибут
name="viewport" разъяснений не требует. Затем в разделе content="initialscale=2.0 предписывается увеличить размер содержимого вдвое (значение 0.5
уменьшило бы размер в два раза, 3.0 — увеличило бы его в три раза и т. д.). А часть
width=device-width говорит браузеру о том, что ширина страницы должна быть
равна значению device-width. Метатег также может ограничить масштабирование

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


Можно также лишить пользователей возможности масштабирования:


Ключевой здесь является часть user-scalable=no.
Поскольку масштабирование является важным средством, повышающим удобство просмотра содержимого, применять эту настройку на практике вряд ли придется. Многие браузеры отключили возможность предотвращения масштабирования по этой причине.
При масштабе 1.0 мобильный браузер будет отображать страницу на 100 %
своего окна просмотра. Установка ширины устройства означает, что страница
будет отображаться на 100 % от ширины всех поддерживаемых мобильных браузеров. Для большинства случаев отзывчивого веб-дизайна подойдет этот метатег:


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

Заметив рост популярности метатега viewport, консорциум W3C предпринял
попытки внедрения такой же возможности в CSS. Зайдите на страницу http://dev.
w3.org/csswg/css-device-adapt/ и прочитайте все о новом объявлении @viewport.
Идея заключается в том, что вместо написания в разделе head разметки вы можете написать в CSS @viewport { width: 320px; }. В результате ширина
браузера будет настроена на 320 px. Но поддержка этого объявления со стороны браузеров оставляет желать лучшего. Когда я пишу эти строки, в добавлении
этой записи в ваш CSS-код почти нет смысла, поскольку все браузеры поддерживают метатег viewport.

Зачем нужны медиазапросы

69

Зачем нужны медиазапросы
Если углубиться в W3C-спецификацию, относящуюся к модулю медиазапросов
CSS3 (http://www.w3.org/ TR/css3-mediaqueries/), можно найти вот что:
Медиазапрос включает в себя тип среды и выражения в количестве от нуля
и более, которые проверяют условия конкретных медиасвойств. К медиа­
свойствам, используемым в медиазапросах, относятся ширина —'width',
высота — 'height' и цвет — 'color'. С помощью медиазапросов представления без изменения своего содержимого могут быть привязаны к конкретному диапазону устройств вывода информации.
Хотя fluid-макет, где размеры указаны в процентах, а не фиксируются, могут
значительно утяжелить дизайн (мы подробно рассмотрим эту тему в следующей
главе), бывают случаи, когда требуется существенно пересмотреть верстку. И медиазапросы делают это возможным — считайте их базовой условной логикой для
CSS.

Основная условная логика в CSS
Во всех языках программирования есть средства для обработки одной или нескольких возможных ситуаций. Обычно такие средства существуют в виде условной логики, примером которой может служить инструкция if — else.
Если выражения из программирования вас пугают, не волнуйтесь: эта концепция весьма проста. Представьте, как в кафе вы просите друга заказать вам чтонибудь: «Если у них есть тройные шоколадные кексы, то я бы взял один, а если
нет — возьми мне морковный пирог». Это простая условная инструкция с двумя
возможными результатами.
Когда я работал над этой книгой, в CSS еще не было возможности использования настоящей условной логики или свойств, присущих программированию.
Циклы, функции, итерации и сложные математические вычисления все еще не
вышли за пределы CSS-препроцессоров (не помню, упоминал ли я о прекрасной
книге на тему препроцессора Sass, которая называется Sass and Compass for
Designers?). И тем не менее медиазапросы являются одним из механизмов, позволяющих создавать основную условную логику. В том случае, когда складываются
конкретно оговоренные в медиазапросе условия, в область видимости попадают
именно те стили, которые в нем объявлены.

70

Глава 3. Медиазапросы — поддержка различных окон просмотра

Синтаксис медиазапроса
Как же выглядят медиазапросы и, главное, как они работают?
Ниже представлена простая веб-страница без контента, но с некоторыми базовыми стилями и медиазапросами:




Media Query Test


body {
background-color: grey;
}
@media screen and (min-width: 320px) {
body {
background-color: green;
}
}
@media screen and (min-width: 550px) {
body {
background-color: yellow;
}
}
@media screen and (min-width: 768px) {
body {
background-color: orange;
}
}
@media screen and (min-width: 960px) {
body {
background-color: red;
}
}





Скопируйте и сохраните этот код в новый файл или, если у вас есть загруженный код для книги, вы можете найти его в каталоге example_03-01.
Теперь откройте файл в браузере и измените размер окна. Фоновый цвет страницы будет меняться в зависимости от текущего размера окна просмотра.
Цвет по умолчанию определен вне медиазапроса. Если какой-либо медиазапрос
верен, стили внутри медиазапроса заменяют стили по умолчанию.

Синтаксис медиазапроса

71

К базовому синтаксису медиазапроса нужно привыкнуть. Сначала в виде правила @media укажем, что нам нужен медиазапрос, затем в скобки впишем медиатест.
Чтобы применились стили в фигурных скобках, тест должен быть пройден.
Медиазапросы в ссылках в HTML-коде способны загружать целые таблицы
стилей. Вы можете писать эти медиазапросы в виде CSS-правила @import, чтобы
определить, какие таблицы стилей следует импортировать. Или вписывать их непосредственно в файл CSS, чтобы выделить правила, применяемые на основе
истинности медиазапроса.
Рассмотрим каждый вариант по очереди.

Медиазапросы в тегах link
Вот как выглядит медиазапрос в ссылке, которую вы найдете в разделе head:


Здесь с помощью выражения медиазапроса задается вопрос: «Это экран в порт­
ретной ориентации?»

Медиазапросы с использованием правила @import
Вот применение правила @import:
@import url("portrait-screen.css") screen and (orientation:
portrait);

Вы можете увидеть те же компоненты — файл, который нужно загрузить, и тест,
который необходимо пройти. Другой синтаксис, но тот же результат.

Использование правила @import в CSS заставляет браузер запрашивать соответствующий файл из сети, что может увеличить количество HTTP-запросов и отрицательно сказаться на скорости загрузки сайта.

Медиазапросы в файле CSS
Наконец, вот тот же медиазапрос, записанный в файле CSS или внутри тега style
в HTML-коде:
@media screen and (orientation: portrait) {
/* стили */
}

72

Глава 3. Медиазапросы — поддержка различных окон просмотра

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


Хотя использование ключевого слова not иногда уместно, думаю, лучше применять стили, когда они вам действительно нужны. Так вы сможете писать краткие
и простые медиазапросы.

Объединение медиазапросов
В одной строке можно построить сразу несколько выражений.
Расширим один из предыдущих фрагментов кода и ограничим применение
файла устройствами, ширина окна просмотра которых составляет не менее
800 px:


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


В нем есть две интересные особенности. Во-первых, для разделения медиазапросов используются запятые, выступающие как команда or. Во-вторых, в скобках
после ключевого слова print отсутствует and или пара свойство — значение. Дело
в том, что при отсутствии таких значений медиазапрос применяется ко всем медиаустройствам указанного типа. В нашем примере стили будут применяться ко
всем сценариям print.

Следует иметь в виду, что для указания медиазапросов можно использовать любую единицу измерения длины, применяемую в CSS. Чаще используются пикселы,
но подойдут также единицы em и rem.

Синтаксис медиазапроса

73

Повседневные медиазапросы
Обратите внимание, что в большинстве ситуаций указывать экран (screen) не
нужно. Основное положение спецификации звучит так:
Сокращенный синтаксис предлагается для тех медиазапросов, которые применяются ко всем типам медиаустройств. Ключевое слово 'all' может быть
опущено (наряду со следующим за ним 'and'). То есть, если тип медиаустройства не задан явно, подразумевается настройка 'all'.
То есть пока не возникнет потребность нацелить стили на конкретные типы
медиаустройств, screen и and можно опустить. Впредь все медиазапросы в примерах мы будем писать с учетом этой возможности. Например:
@media (min-width: 750px) {
/* стили */
}

Что можно тестировать с помощью медиазапросов
По опыту могу сказать, что описанные ниже возможности особо мне не пригодились, за исключением указания разрешения и высоты окна просмотра. Но на всякий случай дам вам перечень всех возможностей Media Queries Level 3. Может,
что-то вас заинтересуют:
y width: — ширина окна просмотра;
y height: — высота окна просмотра;
y device-width: — ширина поверхности отображения (как правило, это ширина экрана устройства);
y device-height: — высота поверхности отображения (как правило, это высота экрана устройства);
y orientation: — проверка портретной или альбомной ориентации устройства;
y aspect-ratio: — соотношение ширины окна просмотра к его высоте. Дисплей
с соотношением сторон 16 : 9 может быть описан как aspect-ratio: 16/9;
y device-aspect-ratio: — эта возможность аналогична предыдущей, но основывается на ширине и высоте не окна просмотра, а поверхности отображения
устройства;
y color: — количество битов, приходящееся на каждую составляющую цвета.
Например, min-color: 16 задаст проверку того, обладает ли устройство
цветом с глубиной 16 бит;
y color-index: — количество вхождений в таблице поиска цветов устройства (таблица отражает, как устройство меняет один набор цветов на другой).
Значения должны быть числовыми и неотрицательными;

74

Глава 3. Медиазапросы — поддержка различных окон просмотра

y

monochrome: — проверка количества битов на пиксель в монохромном фрейм-

буфере. Значение должно быть целым неотрицательным числом, например
monochrome: 2;
y resolution: — проверка разрешения экрана или принтера, например minresolution: 300dpi. Может выражаться в точках на сантиметр, например
min-resolution: 118dpcm;
y scan: — отображение значения развертки (прогрессивной или чересстрочной), которое имеет отношение в основном к телевизионным устройствам.
Например, нацеливание на устройство с параметрами 720p HDTV (буква «p»
означает progressive — «прогрессивная») можно обозначить выражением
scan: progressive , a на устройство 1080i HDTV (буква «i» означает
interlaced — «чересстрочная») — выражением scan: interlace;
y grid: — показывает, на какой основе построено устройство: сеточной или
растровой.
Все перечисленные возможности, за исключением scan и grid, для создания
диапазонов могут использоваться с префиксом min или max. Рассмотрим следующий
фрагмент кода:
@import url("tiny.css") screen and (min-width:200px) and (maxwidth:
360px);

Здесь минимум (min) или максимум (max) применен для задания диапазона
ширины — width. Файл tiny.css может быть импортирован для экранов с шириной
окна просмотра от 200 до 360 px.

ФУНКЦИИ, ОБЪЯВЛЕННЫЕ УСТАРЕВШИМИ В CSS MEDIA QUERIES LEVEL 4
Обратите внимание, что в предварительной спецификации медиазапросов Media Queries Level 4 не рекомендуется использование ряда возможностей (http://
dev.w3.org/csswg/mediaqueries-4/#mf-de-precated), в частности device-height,
device-width и device-aspect-ratio. Поддержка этих запросов останется
в браузерах, но от написания новых таблиц стилей с их использованием рекомендуется воздержаться.

Использование медиазапросов
для изменения веб-дизайна
Если вы хотя бы отчасти вникли в материал этой главы, то теперь готовы всерьез
использовать медиазапросы.
Предлагаю открыть файл index.html и связанный с ним файл styles.css из начальной папки кода этой главы и добавить несколько медиазапросов, чтобы
изменить некоторые области страницы при определенной ширине области про-

Использование медиазапросов для изменения веб-дизайна

75

смотра. Давайте вместе внесем пару изменений, а затем вы сможете попрактиковаться самостоятельно.
Посмотрим на раздел заголовка (область просмотра шириной около 1200 px):

Рис. 3.3. На более широких экранах отображаемый браузером веб-дизайн
не соответствует ожидаемому

А вот тот же фрагмент веб-дизайна, который мы изменяем:

Рис. 3.4. Веб-дизайн требует другой разметки, с более широкой областью просмотра

Необходимо сохранить веб-дизайн для меньших окон просмотра, но исправить
его для больших. Начнем с добавления медиазапроса и расположим навигационные
ссылки и логотип по обе стороны от области просмотра шириной 1200 px и выше:
@media (min-width: 1200px) {
.rwd-MastHead {
flex-direction: row;
justify-content: space-between;
max-width: 1000px;
margin: 0 auto;
}
}

76

Глава 3. Медиазапросы — поддержка различных окон просмотра

Если какой-то из этих стилей вам непонятен, не волнуйтесь. Мы рассмотрим
резиновый макет (fluid layout) в главе 4. Сейчас важно понимать сами медиазапросы. С их помощью мы сообщаем браузеру: «Применяй это правило, но только
при минимальной ширине области просмотра 1200 px».
И таков эффект этого правила в браузере:

Рис. 3.5. Первый медиазапрос переводит навигационные ссылки вправо

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

Рис. 3.6. Примененные стили, которые мы хотим сбросить в этой области просмотра

Напишем еще один медиазапрос, чтобы исправить это. Внесем изменение при
немного меньшей ширине экрана:
@media (min-width: 1000px) {
.rwd-Nav {

Расширенные рекомендации по медиазапросам

}

}

77

margin: 0;
padding: 0;

В этом случае мы сообщаем: «Если ширина области просмотра превышает
1000 px, сделай ширину полей и отступов для элемента .rwd-Nav равной нулю».
Обратили внимание, что каждый раз в медиазапросе мы изменяем только те свойства, которые нам нужно изменить?
Оставив «базовые» стили в исходном виде, мы инкапсулируем необходимые
различия с помощью медиазапросов.
Процесс кажется простым, но, по сути, это все, что нужно для работы с медиазапросами. Напишите основные стили без медиазапросов, а затем расширяйте
область просмотра, добавляя медиазапросы и изменения везде, где это необходимо, чтобы влиять на веб-дизайн.
Если у вас есть время, очень прошу вас попробовать написать несколько медиа­
запросов на нашей тестовой странице или где-то у себя. Выберите что-то, что хотите изменить, укажите ширину области просмотра и добавьте медиазапрос,
чтобы внести изменения.

ТЕСТИРОВАНИЕ ОТЗЫВЧИВОГО ВЕБ-ДИЗАЙНА НА ЭМУЛЯТОРАХ
И СИМУЛЯТОРАХ
Замены для тестирования результатов разработки на реальных устройствах нет,
но существует ряд эмуляторов для Android и симулятор для iOS, решающих задачу проверки кода. Для особо дотошных поясню, что симулятор просто симулирует нужное устройство, а эмулятор фактически пытается интерпретировать исходный код устройства. Android-эмулятор для Windows, Linux и Mac находится
в открытом доступе в Android Studio по адресу: https://developer.android.com/studio.
Симулятор для iOS доступен только пользователям Mac OS и поставляется как
часть пакета Xcode, который можно свободно получить в Mac App Store.
Конкретные настройки на эмуляцию различных мобильных устройств и окон просмотра есть и у браузеров, в частности у Firefox и Chrome.

Расширенные рекомендации
по медиазапросам
Рассмотрим проблемы, возникающие у опытных разработчиков. Эти темы можно
представить как вопросы микрооптимизации. Если вы только начинаете знакомиться с медиазапросами, пока не трогайте их и переходите к разделу Media Queries Level 4!
Что ж, супермастера медиазапросов, поехали...

78

Глава 3. Медиазапросы — поддержка различных окон просмотра

Организация медиазапросов
Браузер рассматривает CSS как ресурс, приостанавливающий отображение. Браузеру нужно извлечь и проанализировать привязанные CSS-файлы до полного
вывода страницы на экран, чтобы понять, какие стили применять для разметки
и визуализации страницы.
Но современные браузеры достаточно разумны для того, чтобы определять,
какие таблицы стилей (связанные в главном разделе страницы с медиазапросами)
должны быть проанализированы немедленно, а какие — после вывода на экран
начальной страницы.
Для таких браузеров CSS-файлы, привязанные с помощью медиазапросов,
в некоторых ситуациях могут «откладываться» до момента после загрузки начальной страницы, предоставляя преимущества в производительности. Подробности можно найти на страницах разработчиков компании Google: https://
developers.google.com/web/fundamentals/performance/critical-rendering-path/renderblocking-css.

Но хочу обратить ваше внимание вот на что:
...Учтите, что приостановка отображения относится только к вопросу,
должен ли браузер задержать начальное отображение страницы на этом
ресурсе. В любом случае CSS-ресурс все равно загружается браузером, пусть
даже с меньшим уровнем приоритета для неблокирующих ресурсов.
Все привязанные файлы все равно будут загружены, просто они не обязательно будут нуждаться в задержке браузером отображения страницы на экране.
Современный браузер загружает отзывчивую веб-страницу с четырьмя таблицами стилей, привязанными с помощью медиазапросов (для применения разных
стилей для разных диапазонов окон просмотра) с загрузкой всех четырех CSSфайлов, но с начальным анализом до вывода страницы на экран только одного из
них, применимого в сложившихся условиях. Посмотрите файл каталога примеров
кода к данной главе example_03-03, который можно скачать по адресу: https://benfrain.
com/playground/mq-downloads/. Если вы просматриваете эту страницу в узкой области просмотра и достаточно хорошо разбираетесь в инструментах разработчика
браузера, вы можете заглянуть в сетевую область и проверить, что все файлы загружены независимо от того, какие медиазапросы применены.

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

Что делать — объединять медиазапросы или же записывать их там, где они пригодятся?

79

страницу медленнее. Ничто в интернете не дается легко! Поэтому возникает вопрос вычисления общей производительности сайта и тестирования каждого сценария на различных устройствах.
Если проект располагает достаточным временем для оптимизации производительности, то искать возможности прироста производительности именно в этом
месте я стану в последнюю очередь.
Практичнее убедиться, что сжаты все изображения, объединены и минимизированы все сценарии, средством gzip обработаны все ресурсы, все статическое
содержимое кэшировано посредством CDN-сетей и удалены все избыточные
CSS‑правила. Я не стал бы заниматься вопросом о разбиении медиазапросов на
отдельные файлы с целью повышения производительности.

Вложение медиазапросов через встраивание
При любых обстоятельствах, кроме исключительных, рекомендую добавлять медиазапросы в существующие таблицы стилей наряду с обычными правилами. Если
вам удастся придерживаться этой рекомендации, возникнет следующий вопрос:
должны ли медиазапросы объявляться ниже связанного с ними селектора? Или
их нужно разбивать в конце на отдельные блоки кода? Рад, что вы задаетесь этим
вопросом.

Что делать — объединять медиазапросы
или же записывать их там, где они
пригодятся?
Я сторонник записи медиазапросов ниже исходных обычных правил. Если мне
нужно изменить ширину двух различных элементов в разных местах таблицы
стилей в зависимости от ширины окна просмотра, я обычно делаю так:
.thing {
width: 50%;
}
@media (min-width: 30rem) {
.thing {
width: 75%;
}
}
/* Между фрагментами кода помещаются другие стили */

80

Глава 3. Медиазапросы — поддержка различных окон просмотра

.thing2 {
width: 65%;
}
@media (min-width: 30rem) {
.thing2 {
width: 75%;
}
}

Видите ли вы в этом примере два отдельных медиазапроса, написанных для
тестирования одного и того же: @media (min-width: 30rem)? Неужели повторение
@media не считается многословием и расточительством? Наверное, лучше сгруппировать идентичные медиазапросы в единый блок:
.thing {
width: 50%;
}
.thing2 {
width: 65%;
}
@media (min-width: 30rem) {
.thing {
width: 75%;
}
.thing2 {
width: 75%;
}
}
/* Еще несколько стилей расположены далее */

Безусловно, это один из способов группировки. Но с точки зрения сопровождения кода он представляется мне более сложным. Правильного способа нет, но
я предпочитаю сначала определить одно правило для отдельного селектора и располагать определения любых изменений этого правила (например, изменения
внутри медиазапросов) непосредственно после него. Так мне не придется искать
отдельные блоки кода, чтобы найти объявление, относящееся к конкретному селектору.

Еще более удобным может стать использование препроцессоров и постпроцессоров CSS, поскольку вариант правила, заключенный в медиазапрос, может
быть вложен непосредственно в набор правил. Но это уже тема другой книги.
Любопытно? Можете ознакомиться с ней по ссылке: https://ecss.io/ chapter8.
html#h-H2_1.

Спецификация Media Queries Level4

81

Казалось бы, вполне резонно выступить против многословия. Но неужели размер файла может стать причиной для того, чтобы не записывать медиазапросы
таким образом? Да, никому не хочется иметь раздутый CSS-файл для обслуживания своих потребностей. Но не забывайте, что все возможные ресурсы на сервере
подвергаются gzip-сжатию. Я провел тесты (http://benfrain.com/inline-or-combinedmedia-queries-in-sass-fight/), которые показали, что, если вы предпочтете записывать
медиазапросы непосредственно после стандартных стилей, размер вашего файла
вырастет незначительно.
Чтобы писать медиазапросы непосредственно после исходных правил, но при
этом объединять идентичные определения медиазапросов в один запрос, вы можете использовать специальные инструменты (на момент написания этой книги
соответствующие дополнительные модули были как у Grunt, так и у Gulp).
Итак, у вас есть все необходимое, чтобы начать работать с медиазапросами на
профессиональном уровне. Отмечу, что в Media Queries Level 4 есть ряд функций
медиазапросов, которые мы можем начать использовать уже сегодня. Рассмотрим
их!

Спецификация Media Queries Level 4
Спецификации в W3C проходят через процесс ратификации и начинаются с рабочего проекта (WD, working draft), проходят стадии кандидата в рекомендации (CR, candidate recommendation), предложения в рекомендации (PR, proposed
recommendation) и, наконец, спустя много лет добираются до рекомендации (REC,
W3C recommendation). Как правило, безопаснее использовать модули, находящие­
ся на более высоком уровне ратификации. Например, CSS Spatial Navigation Level 1 (http://www. w3.org/TR/css-nav-1/), когда я пишу эти строки, находится в статусе WD без поддержки в браузерах. В то время как раскрываемая в данной главе
спецификация Media Queries Level 3 реализована в каждом современном брау­
зере.

Не поленитесь в свободное время ознакомиться с официальным объяснением
этого процесса по адресу: http://www.w3.org/2005/10/Process-20051014/tr.

На момент написания книги, когда CSS Media Queries Level 4 пребывает в стадии проекта спецификации (http://dev.w3.org/csswg/mediaqueries-4/), не все его
компоненты могут похвастаться реализацией в браузерах. Поэтому в данном разделе мы сосредоточимся на возможностях Media Queries Level 4, которые мы
можем использовать, — возможностях, уже реализованных в браузерах.

82

Глава 3. Медиазапросы — поддержка различных окон просмотра

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

Медиафункция pointer
В W3C медиафункция указателя pointer представлена так:
Медиафункция pointer используется для запроса наличия и точности указывающего устройства, например мыши. Если у устройства есть несколько
механизмов ввода, медиафункция pointer должно отражать характеристики первичного механизма ввода в соответствии с определением пользовательского агента (user agent).
Существует три возможных состояния указателя pointer: none (отсутствует),
coarse (грубый) и fine (точный).
Устройством указателя с параметром coarse может быть палец на сенсорном
экране или курсор игровой консоли, не обладающий такой же высокой точностью,
как указатель мыши:
@media (pointer: coarse) {
/* стили на случай присутствия указателя, имеющего состояние coarse */
}

Устройством со свойством pointer, имеющим значение fine, может быть мышь,
а также стилус-перо или любой другой указательный механизм высокой точности:
@media (pointer: fine) {
/* стили на случай присутствия указателя, имеющего состояние fine */
}

Браузеры сообщают, каким является значение указателя fine, coarse или none
в зависимости от «основного» устройства указателя. Поэтому помните, что то, что
устройство обладает способностью точного указателя, не означает, что оно будет
основным устройством указателя. Подумайте о планшетах, где основным указателем является палец (грубый), но к нему прикреплен стилус — точное устройство
указателя.

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

Спецификация Media Queries Level 4

83

О проекте этого свойства можно прочитать здесь: https://www.w3.org/TR/
mediaqueries-4/#pointer.

Медиафункция hover
Как вы, наверное, уже догадались, медиафункция hover тестирует аппаратную
возможность проведения указателя над элементами экрана. Если пользователь
располагает несколькими устройствами ввода (например, сенсором и мышью),
используются характеристики основного устройства ввода. Рассмотрим его возможные значения и примеры кода.
Для пользователей, не имеющих возможности провести указатель над элементами экрана, подойдут стили для значения none:
@media (hover: none) {
/* стили на случай, если провести указатель над элементами невозможно */
}

Или, как и раньше, мы можем выбрать сценарий без наведения по умолчанию,
а затем добавить стили наведения для активных устройств:
@media (hover) {
/* стили на случай, если пользователь может провести указатель над
элементами */
}

Существуют также медиафункции any-pointer и any-hover. Они похожи на
рассмотренные ранее hover и pointer, но проверяют возможности любого из существующих устройств ввода.
Используйте их в случае, если несколько устройств ввода могут быть указателем, независимо от того, являются ли эти устройства ввода основными:
@media (any-hover: hover) {
/* стили на случай, если несколько устройств могут быть указателем */
}

Чтобы стилизовать элемент определенным образом для взаимодействия с грубым указателем, напишите:
@media (any-pointer: coarse) {
/* стили на случай, если примененный указатель является грубым */

Медиафункция prefers-color-scheme
За последние несколько лет популярные десктопные и мобильные ОС предоставили пользователям возможность выбора «ночного режима» через медиафункцию prefers-color-scheme. Оно фактически находится на уровне 5 спецификации, а не на уровне 4, но уже реализовано в большинстве распространенных
браузеров.

84

Глава 3. Медиазапросы — поддержка различных окон просмотра

В настоящее время оно предоставляет три возможности: light, dark и nopreference. Чтобы продемонстрировать использование этого свойства, изменим
цвета по умолчанию для страницы:
body {
background-color: #e4e4e4;
color: #545454;
}
@media (prefers-color-scheme: dark) {
body {
background-color: #333;
color: #ddd;
}
}

Точно так же, как я рекомендую записывать «мобильные» стили по умолчанию
в корне таблиц стилей, советую записывать цвета по умолчанию в корне и добавлять это свойства для обслуживания альтернативного интерфейса, если это необходимо или желательно.
Проект спецификации медиафункции prefers-color-scheme можно найти по
адресу: https://drafts.csswg.org/mediaqueries-5/#prefers-color-scheme.

Итоги
Мы узнали, что такое медиазапросы, зачем они нужны и как они включаются
в файлы CSS. Мы также научились использовать метатег viewport, чтобы заставлять браузеры мобильных устройств выводить на экран страницы в соответствии
с нашими предпочтениями.
Не беспокойтесь о синтаксисе. Просто усвойте основные принципы, а синтаксис проверите в любой момент — так делают все разработчики! Если вы понимаете, чего можно добиться с помощью медиазапросов, ваше обучение по большей
части завершено.
Еще в главе 1 мы отметили, что три составляющие отзывчивого веб-дизайна —
это медиазапросы, резиновый макет и отзывчивые медиа. Из трех глав мы знаем
только медиазапросы! Исправим это.
В главе 4 мы глубоко погрузимся в тему резинового макета. Узнаем, как преобразовывать фиксированные размеры в пикселах в подстраиваемый пропорцио­
нальный макет и размещать элементы страницы, а также подробно рассмотрим
отзывчивые медиа вместе с отзывчивыми изображениями.

4

Fluid Layout, Flexbox
и отзывчивые
изображения

Напомню, что три основные составляющие отзывчивого веб-дизайна — это резиновый макет (fluid layout), медиазапросы и отзывчивые медиаэлементы. В главе 3
мы изучили медиазапросы. Теперь мы знаем, как их использовать для изменения
разметки в брейкпоинте.
В этой главе мы сфокусируемся на двух других столпах отзывчивого вебдизайна: резиновом макете и отзывчивых медиаэлементах. К концу этой главы мы
сможем добиться того, что любые фрагменты веб-дизайна, который мы создаем,
могут легко перемещаться между брейкпоинтами, реагируя на ограничения сво­его
контейнера.
Раньше (в конце 1990-х годов) ширину сайтов обычно задавали в процентах,
благодаря чему страницы подстраивались под экран просмотра. Этот подход назывался резиновым макетом (fluid layouts).
Во второй половине 2000-х годов появилась промежуточная фиксация с использованием конструкций с фиксированной шириной (я виню в этом дотошных
полиграфистов с их любовью к абсолютной точности в пикселах). Теперь, занимаясь отзывчивым веб-дизайном, мы должны обратиться в прошлое, к резиновым
макетам, и вспомнить об их преимуществах.
До недавнего времени веб-разработчики использовали несколько механизмов
CSS-верстки для создания резинового макета. Может, вам уже знакомы блоки,
линейные блоки, таблицы и другие методы организации кода. В 2020 году стоит
упоминать эти старые методы лишь вскользь. Теперь в нашем распоряжении есть
два мощных механизма CSS: Flexbox и Grid.
В этой главе речь пойдет о Flexbox, в главе 5 поговорим о сетках (гридах).
Flexbox не только предоставляет механизм резиновой верстки. Хотите быстро
выравнивать содержимое по центру, менять порядок элементов в источнике разметки и вообще относительно легко создавать великолепные макеты? Тогда Flexbox вам подойдет.

86

Глава 4. Fluid Layout, Flexbox и отзывчивые изображения

В этой главе будут рассмотрены следующие вопросы:
y преобразование фиксированных размеров в пикселах в пропорциональные
размеры;
y существующие механизмы CSS-верстки и их недостатки;
y выход за рамки ограничений с помощью механизма Flexbox;
y разбор Flexible Box Layout Module и его преимуществ;
y отзывчивые изображения и применение атрибута srcset для переключения
разрешения и режиссуры отзывчивых изображений.
Приступим к первой задаче и преобразуем фиксированный веб-дизайн в подвижный. Эту задачу придется выполнять постоянно при создании отзывчивого
веб-дизайна.

Преобразование фиксированного
пиксельного дизайна в пропорциональный
резиновый макет
Все графические элементы, экспортированные из таких программ, как Photoshop,
Illustrator или Sketch, имеют фиксированные размеры в пикселах. Для отображения в браузере этим элементам нужны пропорциональные величины.
Для этого преобразования есть красивая и простая формула, которую отец отзывчивого веб-дизайна Итан Маркотт разместил в статье Fluid Grids 2009 года
(http://alistapart.com/article/FLUIDGRIDS):
цель/среда = результат.
Она подразумевает распределение составных частей там, где они помещаются.
Введем эту формулу в обиход в качестве понятия, позволяющего выполнить преобразование любого фиксированного макета в отзывчивые (подстраиваемые)
эквиваленты.
Рассмотрим простой макет, предназначенный для просмотра на ПК. Мы всегда будем начинать верстку для ПК с верстки для меньших экранов, но сейчас для
примера рассмотрим две ситуации в обратном порядке.
Макет выглядит, как на рис. 4.1.
Ее ширина — 960 px. Заголовок и подвал выводятся на всю ширину макета.
Область слева имеет ширину 200 px, а область справа — 100 px. Значит, ширина
средней части составит 660 px. В первую очередь преобразуем среднюю и боковые
части, приведя их к пропорциональным размерам.
Начнем преобразование слева. Разделим целевой размер 200 единиц на 960 единиц (среду) и получим 0,208333333. Переместим десятичный разделитель на две
позиции вправо: 20,8333333 %. Именно так целевое значение описывается в процентном отношении к исходному.

Преобразование фиксированного пиксельного дизайна в пропорциональный резиновый макет

87

Рис. 4.1. Базовый десктопный макет

Проверим формулу на средней части? Целевое значение 660 единиц разделим
на среду, равную 960 единицам, и получим 0,6875. Переместим десятичный разделитель на две позиции вправо и получим 68,75 %. И наконец, взглянем на правую
сторону: цель, равную 100 единицам, разделим на среду, равную 960 единицам,
и получим 0,104166667. После перемещения десятичного разделителя получим
10,41 66667 %. Как видите, ничего сложного. Повторяйте за мной: цель, разделенная на среду, дает результат.

В CSS вы можете использовать значения с длинными десятичными дробями без
проблем. Чтобы видеть в коде более приятные числа, округлите их до двух знаков
после запятой — это будет работать в браузере.

Рассмотрим простой макет в виде блоков в браузере. Для наглядности я добавил к различным элементам класс, который описывает, на какую часть графической составляющей они ссылаются. Обычно не рекомендуется обращаться
к атрибутам в зависимости от их расположения. Местоположение может измениться, особенно с отзывчивым веб-дизайном. Короче, делайте, как я вам говорю,
а не как я здесь делаю!

88

Глава 4. Fluid Layout, Flexbox и отзывчивые изображения

Код можно увидеть в файле каталога example_04-01. Вот как выглядит код HTML:










А вот как выглядит код CSS:
html,
body {
margin: 0;
padding: 0;
}
.Wrap {
max-width: 1400px;
margin: 0 auto;
}
.Header {
width: 100%;
height: 130px;
background-color: #038c5a;
}
.WrapMiddle {
width: 100%;
font-size: 0;
}
.Left {
height: 625px;
width: 20.83%;
background-color: #03a66a;
display: inline-block;
}
.Middle {
height: 625px;
width: 68.75%;
background-color: #bbbf90;
display: inline-block;
}
.Right {
height: 625px;

Преобразование фиксированного пиксельного дизайна в пропорциональный резиновый макет

}

89

width: 10.41%;
background-color: #03a66a;
display: inline-block;

.Footer {
height: 200px;
width: 100%;
background-color: #025059;
}

Открыв пример кода в браузере и изменив размер страницы, вы увидите, что
размеры контейнеров классов .Left, .Middle и .Right остались пропорциональными по отношению к другим частям. Можно также изменять значение свойства
max-width для класса .Wrap, чтобы сделать окружающие размеры для разметки
больше или меньше (в примере установлено значение 1400 px).
Теперь посмотрим, каким будет то же самое содержимое на экранах меньших
размеров. Сначала оно динамически подстроится под брейкпоинт, затем — под
среду, а после этого — под тот макет, который мы уже видели. Окончательный
вариант кода этой разметки есть в файле каталога example_04-02.
Суть в том, что для экранов меньшего размера мы создадим одну «колонку»
содержимого. Левая часть будет видна как область, выходящая за пределы холста,
поскольку обычно эта область отводится под меню, которое выплывает при нажатии кнопки. Основное содержимое разместится под заголовком, еще ниже —
правая часть и, наконец, область подвала. В нашем примере левую область меню
можно показать после щелчка в любом месте заголовка. Обычно в веб-дизайне
подобного рода есть кнопка «Меню».
Как вы, наверное, и ожидали, применив только что приобретенные навыки
создания медиазапросов, мы можем настроить окно просмотра, и веб-дизайн просто адаптируется под эту настройку, переходя от одной разметки к другой и растягиваясь в промежуточных позициях между двумя разметками. Не буду показывать здесь все свойства CSS, доступные в файле каталога example_04-02, и приведу
только пример, относящийся к левой части:
.Left {
height: 625px;
background-color: #03a66a;
display: inline-block;
position: absolute;
left: -200px;
width: 200px;
font-size: 0.9rem;
transition: transform 0.3s;
}
@media (min-width: 40rem) {
.Left {

90

Глава 4. Fluid Layout, Flexbox и отзывчивые изображения

}

}

width: 20.83%;
left: 0;
position: relative;

Как видите, сначала идет разметка без медиазапроса, предназначенная для небольшого экрана. Затем для более крупных экранов ширина задается в процентах,
позиционирование задается относительным, а left присваивается значение 0.
Значения таких свойств, как height, display или background-color, переписывать
не нужно, поскольку их мы не изменяем.
Дело сдвинулось с места. Мы объединили две уже рассмотренные основные
технологии отзывчивого веб-дизайна, преобразовав фиксированные размеры
в пропорциональные и воспользовавшись медиазапросами для создания целевых
CSS-правил, относящихся к размеру окна просмотра.

В реальном проекте необходимо предусмотреть некоторые возможности, если
использование JavaScript недоступно, но требуется просмотреть содержимое
меню. Мы подробно рассмотрим этот сценарий в главе 9.

Подведем итог: там, где это необходимо, указывайте размеры элементов в пропорциональном соотношении, а не в фиксированных величинах. Так веб-дизайн
будет адаптироваться к размеру контейнера. Запомните простую формулу
«цель/среда = результат» для вычислений.
Прежде чем перейти к отзывчивым медиаэлементам, рассмотрим механизм
разметки CSS Flexbox.

Зачем нужен Flexbox
Рассмотрим подробности использования модуля CSS Flexible Box Layouts, более
известного как Flexbox. Но перед этим рассмотрим недостатки существующих технологий разметки, таких как линейные блоки, плавающие элементы и таблицы.
Если вы раньше не использовали свойство float, CSS-таблицы или встроенные
блоки для создания макета, не беспокойтесь. Как мы увидим, сегодня есть более
совершенные технологии. Если же вы пользовались ими, вспомните их болевые
точки.

Линейные блоки и свободное пространство
Самой большой проблемой использования линейных блоков (inline-block) являются пробелы, или свободное пространство (white-space) между элементами
HTML, для удаления которых нужно прибегать к особым приемам, что, на мой
взгляд, отнимает около 95 % времени разработчика. Есть множество способов ре-

Преобразование фиксированного пиксельного дизайна в пропорциональный резиновый макет

91

шения этой проблемы. Их можно найти в статье неугомонного Криса Койера
(Chris Coyier): http://css-tricks.com/fighting-the-space-between-inline-block-elements/.
Замечу, что простого способа центрирования содержимого внутри линейного
блока по вертикали нет. Кроме того, при использовании линейных блоков нельзя
получить два одноуровневых элемента, один из которых имеет фиксированную
ширину, а другой подстраивается для заполнения оставшегося пространства.

Плавающие элементы
Ненавижу использовать плавающие элементы (floats) в макете. И этим все сказано. Их плюсом является устойчивая работа при любых обстоятельствах. Но есть
две неприятные особенности.
Во-первых, при указании ширины плавающих элементов в процентах вычисленная ширина не округляется всеми браузерами одинаково (некоторые округляют вверх, а некоторые — вниз). Это означает, что иногда разделы вопреки задуманному будут выпадать из общей картины, а иногда будут оставлять с одной из
сторон портящие внешний вид пробелы.
Во-вторых, плавающие элементы приходится «вычищать», поскольку в противном случае родительские блоки или элементы не свернутся. Конечно, особого
труда это не составляет, но все же служит постоянным напоминанием о том, что
плавающие элементы не следует использовать в качестве надежного механизма
разметки ни при каких условиях.

Свойства table и table-cell
Не путайте display: table и display: table-cell с одноименными элементами
HTML. Эти CSS-свойства просто имитируют разметку своих собратьев из HTML
и на структуру HTML не влияют.
За годы работы я пришел к выводу, что CSS-таблицы исключительно полезны
для разметки. Как минимум свойство display: table с включенным дочерним
свойством display: table-cell позволяет выполнять единообразное и надежное
выравнивание элементов по центру. Кроме того, элементы table-cell внутри
элементов table отлично справляются с расстановкой пустых пространств и не
страдают от проблем округления, как плавающие элементы. А поддержка этих
свойств браузерами начинается с Internet Explorer 7!
Но и здесь не обошлось без ограничений. Часто возникает необходимость заключать элемент в дополнительную оболочку: например, чтобы получить четкое
выравнивание по центру, ячейка таблицы (table-cell) должна находиться внутри
элемента, настроенного как таблица (table). Кроме того, элементы, имеющие настройку отображения display: table-cell, не могут переносить свое содержимое
с одной строки на другую.
В заключение отмечу, что ограничения есть у всех существующих методов
верстки. Но, к счастью, механизм Flexbox их преодолел.
Трубите в фанфары, бейте в литавры! К нам едет Flexbox.

92

Глава 4. Fluid Layout, Flexbox и отзывчивые изображения

Представляем Flexbox
Flexbox предназначен для устранения недостатков каждого из упомянутых ранее
механизмов отображения. Коротко перечислю его исключительные возможности:
y упрощает выравнивание содержимого по вертикали;
y меняет порядок визуального отображения элементов;
y автоматически заполняет пространство пробелами и выравнивает элементы
внутри блока, автоматически распределяя между ними доступное пустое
пространство;
y располагает элементы в строке в прямом и обратном направлении, а в столбце позволяет спускаться и подниматься;
y оказывает омолаживающий эффект (но это неточно).

Тернистый путь Flexbox
Прежде чем Flexbox обрел сегодняшнюю относительно стабильную версию, он
прошел через несколько основных стадий развития. Рассмотрим, к примеру, изменения, произошедшие со времени выхода версии 2009 года (http://www.w3.org/
TR/2009/WD-css3-flexbox-200 90723/), версии 2011 года (http://www.w3.org/TR/2011/
WD-css3-flexbox-201 11129/) и версии 2014 года, на которой основаны приводимые
здесь примеры (http://www.w3.org/TR/css-flexbox-1/). У этих версий есть существенные синтаксические различия.
Наличие различных спецификаций означает, что существовали три основные
версии реализации. Скольким версиям следует уделить внимание, зависит от необходимого вам уровня поддержки со стороны браузеров.
Но учитывая наличие различных версий, нужно сделать небольшое, но важное
отступление.

Кому-то все еще нужны префиксы
Вводить вручную весь код, необходимый для поддержки различных Flexboxспецификаций, — задача не из легких. Вот пример, в котором я задам три относящихся к Flexbox свойства и их значения:
.flex {
display: flex;
flex: 1;
justify-content: space-between;
}

Представляем Flexbox

93

Именно так свойства и значения будут выглядеть в официальной версии синтаксиса. Но чтобы получить поддержку со стороны Android-браузеров (v4 и ниже),
а также IE 10, нам потребуется следующий код:
.flex {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-flex: 1;
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
}

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

Выбор решения для автоматизации расстановки префиксов
Чтобы сберечь нервы и аккуратно, без особых усилий добавить к CSS префиксы
производителей, воспользуйтесь решением для автоматической расстановки префиксов. Лично я предпочитаю пользоваться средством Autoprefixer (https://github.
com/postcss/autoprefixer). Оно работает довольно быстро, легко настраивается и отличается высокой точностью работы.
Существуют разные версии Autoprefixer, и не обязательно пользоваться средством создания префиксов на основе командной строки (например, Gulp или
Grunt). К примеру, версия для Sublime работает непосредственно из его палитры
команд: https://github.com/sindresorhus/sublime-autoprefixer. Есть также версии Autoprefixer для Atom, Brackets, Visual Studio Code и другие.
Теперь префиксы производителей в примерах кода в основном использоваться
не будут.

Возможность динамического изменения
У Flexbox есть четыре основные характеристики: направление, выравнивание,
определение порядка и динамическое изменение. Рассмотрим эти характеристики
и их взаимоотношения на нескольких примерах.
Это намеренно простые примеры, касающиеся перемещения блоков и их содержимого, позволяющие понять принципы работы Flexbox.

94

Глава 4. Fluid Layout, Flexbox и отзывчивые изображения

Текст, безупречно выровненный по вертикали
Этот первый пример использования Flexbox можно найти в файле каталога
example_04-03.

Рис. 4.2. Благодаря Flexbox выравнивание по центру становится простой задачей

Разметка выглядит следующим образом:

Hello, I'm centered with Flexbox!


А вот полное CSS-правило, придающее стиль этой разметке:
.CenterMe {
background-color: indigo;
color: #ebebeb;
font-family: 'Oswald', sans-serif;
font-size: 2rem;
text-transform: uppercase;
height: 200px;
display: flex;
align-items: center;
justify-content: center;
}

Большинство пар свойство — значение в этом правиле просто устанавливают
цветовые решения и размер шрифта. Нам интересны только три свойства:
.CenterMe {
/* другие свойства */
display: flex;
align-items: center;
justify-content: center;
}

Если вы еще не пользовались Flexbox или какими-либо свойствами из родственной спецификации Box Alignment Specification (http://www.w3.org/TR/css3-

Представляем Flexbox

95

align/), эти свойства покажутся вам странными. Посмотрим, что делает каждое из

них.
y

display: flex — это простая настройка элемента на его принадлежность

к Flexbox (в противоположность блоку-контейнеру, линейному блоку и т. д.).
y align-items приводит к выравниванию элементов внутри Flexbox по поперечной оси (в нашем примере текст выравнивается по вертикали).
y justify-content задает выравнивание содержимого по центру главной оси.
Относительно строки Flexbox об этом свойстве можно думать как о кнопке
в текстовом процессоре, выравнивающей текст по левому или правому краю
или по центру (есть и другие значения justify-content, которые мы скоро
рассмотрим).
Итак, перед тем как продолжить изучение свойств Flexbox, рассмотрим еще
несколько примеров.

В некоторых примерах использован имеющийся у Google шрифт Oswald (с вариантом без засечек). В главе 6 мы рассмотрим использование правила @fontface для ссылки на файлы пользовательских шрифтов.

Смещение элементов
А как вам понравится простой список элементов перехода, в котором один из элементов смещен в другую сторону?
Вот как это выглядит:

Рис. 4.3. Flexbox упрощает смещение одной ссылки в списке

Вот разметка:

Home
About Us
Products
Policy
Contact Us


96

Глава 4. Fluid Layout, Flexbox и отзывчивые изображения

А вот код CSS:
.MenuWrap {
background-color: indigo;
font-family: 'Oswald', sans-serif;
font-size: 1rem;
min-height: 2.75rem;
display: flex;
align-items: center;
padding: 0 1rem;
}
.ListItem,
.LastItem {
color: #ebebeb;
text-decoration: none;
}
.ListItem {
margin-right: 1rem;
}
.LastItem {
margin-left: auto;
}

При настройке display: flex;, примененной в отношении элемента-контейнера, его дочерние элементы становятся подстраиваемыми и затем выводятся
с использованием резинового макета. Вся магия в свойстве margin-left: auto,
которое заставляет элемент-контейнер использовать все незаполненное место,
доступное с определенной стороны.

Изменение порядка следования элементов
Хотите изменить порядок следования элементов на обратный?

Рис. 4.4. Изменение визуального порядка с помощью Flexbox

Можно просто добавить к обертывающему элементу свойство flex-direction:
row-reverse;, а для смещенного элемента вместо margin-left: auto написать
margin-right: auto:

Представляем Flexbox

97

.MenuWrap {
background-color: indigo;
font-family: 'Oswald', sans-serif;
font-size: 1rem;
min-height: 2.75rem;
display: flex;
flex-direction: row-reverse;
align-items: center;
padding: 0 1rem;
}
.ListItem,
.LastItem {
color: #ebebeb;
text-decoration: none;
}
.ListItem {
margin-right: 1rem;
}
.LastItem {
margin-right: auto;
}

А как расположить элементы не горизонтально, а вертикально?
Очень просто. Измените свойство элемента-контейнера на flex-direction:
column; и удалите автоматическую установку полей:
.MenuWrap {
background-color: indigo;
font-family: 'Oswald', sans-serif;
font-size: 1rem;
min-height: 2.75rem;
display: flex;
flex-direction: column;
align-items: center;
padding: 0 1rem;
}
.ListItem,
.LastItem {
color: #ebebeb;
text-decoration: none;
}

Обратный порядок следования элементов в столбце
Хотите расположить элементы друг под другом в обратном порядке? Измените
настройку на flex-direction: column-reverse;, и все будет сделано, как надо.

98

Глава 4. Fluid Layout, Flexbox и отзывчивые изображения

Для установки в одной настройке значений сразу двух свойств: flex-direction
и flex-wrap, можно применить сокращение flex-flow. Например, настройка
flex-flow: row wrap; установит линейное направление и включит возможность размещения блоков в нескольких строках. Но я считаю, на первых порах
проще указывать эти два свойства по отдельности. Также свойство flex-wrap
отсутствует в более ранних реализациях, поэтому в некоторых браузерах его
объявление может игнорироваться.

Различные макеты Flexbox внутри разных
медиазапросов
Flexbox в соответствии со своим названием легко решает задачи резиновой верстки, в том числе влияя на поведение списка элементов в столбце на экранах меньшего размера и стиль разметки строки. Фактически мы уже использовали следую­
щую технику в предыдущей главе. Помните заголовок сайта https://rwd.education,
который мы запустили?
Вот снова соответствующий раздел:
.rwd-MastHead {
display: flex;
flex-direction: column;
}
@media (min-width: 1200px) {
.rwd-MastHead {
flex-direction: row;
justify-content: space-between;
max-width: 1000px;
margin: 0 auto;
}
}

Вначале мы установили поток содержимого в столбце вниз по странице, чтобы
логотип оказался наверху, а навигационные ссылки располагались одна под другой.
Затем при минимальной ширине области просмотра 1200 px мы заставили эти
элементы отображаться в виде строки, по одному с каждой стороны. Пространство
между ними обеспечило свойство justify-content. Вскоре мы рассмотрим это
более подробно.

Свойство inline-flex
Flexbox предлагает вариант дополнения линейных блоков (inline-block) и линейных таблиц (inline-table). Нетрудно догадаться, что это объявление display:

Различные макеты Flexbox внутри разных медиазапросов

99

inline-flex;. Благодаря его возможностям выравнивания по центру вы можете

легко добиться впечатляющих результатов.

Рис. 4.5. Свойство inline-flex

Разметка выглядит так:

Here is a sentence with a
inline-flex link.


И используя те же базовые стили, что и в предыдущих примерах, для стиля
шрифта, его размера и цвета, получаем CSS-код:
.InlineFlex {
display: inline-flex;
align-items: center;
height: 120px;
padding: 0 4px;
background-color: indigo;
text-decoration: none;
border-radius: 3px;
color: #ddd;
}

Когда свойство inline-flex передается элементам анонимно, если их родительский
элемент не имеет настройки display: flex;, они сохраняют пробелы между элементами точно так же, как это происходит при использовании линейных блоков или
линейных таблиц. Hо если элементы находятся внутри flex-контейнера, пробелы
в них удаляются, как в ячейках CSS-таблицы. Разумеется, никто вас не заставляет
всегда центрировать элементы внутри Flexbox. Рассмотрим другие варианты.

100

Глава 4. Fluid Layout, Flexbox и отзывчивые изображения

Свойства выравнивания, предоставляемые Flexbox
Если вы хотите попрактиковаться с этим примером, откройте файл каталога
example_04-07 и удалите код HTML внутри тега и все правила CSS, чтобы
создать их с нуля.
При изучении выравнивания средствами Flexbox важно разобраться с концепцией двух осей: главной (main axis) и поперечной (cross axis). Что представляет
собой каждая из них, зависит от направления, по которому распространяется flexконтейнер. Если направление настроено на строку, главная ось будет горизонтальной, а поперечная — вертикальной. И наоборот, если направление настроено на
столбец, главная ось будет вертикальной, а поперечная — горизонтальной.
В помощь веб-дизайнерам в спецификации (http://www.w3.org/TR/css-flexbox1/#justify-content-property) приводится такой рисунок:

Рис. 4.6. Главная ось всегда связана с направлением, по которому движется flex-контейнер

Вот базовая разметка нашего примера:

I am content in the inner Flexbox.


Зададим несколько основных стилей, относящихся к Flexbox:
.FlexWrapper {
background-color: indigo;
display: flex;
height: 200px;
width: 400px;
}
.FlexItem {
background-color: #34005b;
display: flex;
height: 100px;
width: 200px;
}

Различные макеты Flexbox внутри разных медиазапросов

101

Браузер выдаст следующее:

Рис. 4.7. Если свойства выравнивания не заданы, дочерние элементы по умолчанию
находятся в верхнем левом углу

Хорошо, а теперь проведем тесты свойств.

Свойство align-items
Свойство align-items позиционирует элементы относительно поперечной оси.
Если применить это свойство к нашему элементу-контейнеру следующим образом:
.FlexWrapper {
background-color: indigo;
display: flex;
height: 200px;
width: 400px;
align-items: center;
}

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

Рис. 4.8. Линейное выравнивание по центру оси

Такой же эффект будет применен к любому количеству дочерних элементов
внутри контейнера.

102

Глава 4. Fluid Layout, Flexbox и отзывчивые изображения

Свойство align-self
Иногда нужно применить необычную настройку выравнивания к одному из элементов. Для выравнивания отдельных flex-элементов можно использовать свойство align-self. Удалим прежние свойства выравнивания в CSS и добавим в разметку еще два элемента div, которые получат HTML-класс .FlexItem. К среднему
элементу добавим еще один HTML-класс .AlignSelf. Этот класс пригодится нам
в CSS для добавления свойства align-self.
Вот код HTML:

I am content in the inner Flexbox 1
I am content in the inner Flexbox 2
I am content in the inner Flexbox 3


Вот CSS-код:
.FlexWrapper {
background-color: indigo;
display: flex;
height: 200px;
width: 400px;
}
.FlexItem {
background-color: #34005b;
display: flex;
height: 100px;
width: 200px;
}
.AlignSelf {
align-self: flex-end;
}

А вот такой эффект будет на экране браузера.

Рис. 4.9. Отдельные элементы можно выравнивать по-разному

Различные макеты Flexbox внутри разных медиазапросов

103

Великолепно! Flexbox действительно с легкостью справился с этими изменениями. В данном примере свойству align-self было присвоено значение flex-end.
Определим возможные значения, которые можно применить относительно поперечной оси, а потом рассмотрим возможности выравнивания относительно
главной оси.

Возможные значения выравнивания
Для выравнивания относительно поперечной оси в модуле Flexbox есть следующие значения:
y flex-start — элемент начинается от начальной границы своего flex-кон­
тейнера;
y flex-end — элемент выровнен по конечной границе своего flex-контейнера;
y center — элемент расположен в центре flex-контейнера;
y baseline — все flex-элементы в контейнере выровнены по нижним строкам;
y stretch — элементы растянуты по размеру их flex-контейнера (по поперечной оси).
Если что-то не получается, обращайтесь к спецификации: http://www.w3.org/TR/
css-flexbox-1/.

Свойство justify-content
Выравнивание по главной оси управляется свойством justify-content, у которого могут быть такие значения:
y

flex-start;

y

flex-end;

y

center;

y

space-between;

y

space-around.

Действие первых трех предсказуемо. А что получается при использовании
space-between и space-around, мы сейчас увидим. Есть такой код:

I am content in the inner Flexbox 1.
I am content in the inner Flexbox 2.
I am content in the inner Flexbox 3.


и следующий код CSS, в котором мы настроили каждый из трех div-элементов
(FlexItem) на ширину 25 %, заключив их во flex-контейнер (FlexWrapper), настроенный на ширину 100 %:
.FlexWrapper {
background-color: indigo;
display: flex;
justify-content: space-between;

104

}

Глава 4. Fluid Layout, Flexbox и отзывчивые изображения

height: 200px;
width: 100%;

.FlexItem {
background-color: #34005b;
display: flex;
height: 100px;
width: 25%;
}

Все три элемента займут только 75 % доступного пространства, а свойство
justify-content сообщит браузеру, что делать с оставшемся пространством. Значение space-between распределит свободное пространство поровну между элементами, а space-around разместит его в равных долях вокруг элементов. Посмотрите
на скриншоты. Это работа значения space-between:

Рис. 4.10. Выравнивание по главной оси выполняется с помощью свойства
justify-content

А это результат использования значения space-around:

Рис. 4.11. Немного отличается, но обратите внимание на пространство вокруг, а не
только между элементами

Другое свойство выравнивания, которое я время от времени использую, — spaceevenly. Оно заставляет элементы занимать доступное пространство и создает
равные промежутки между ними.

Различные макеты Flexbox внутри разных медиазапросов

105

Свойства выравнивания Flexbox теперь приводятся в спецификации CSS Box
Alignment Module Level 3. Тем самым закладывается общая основа с эффектами
выравнивания других свойств отображения, такими как display: block;
и display: table;. Спецификация еще актуальна, поэтому проверяйте ее
состояние по адресу: http://www.w3.org/TR/css3-align/.

Свойство flex
Мы уже использовали в отношении flex-элементов свойство width, но свойство
flex тоже позволяет определить ширину (или гибкость, flexiness). В примере ниже
для элементов используется та же разметка, но с исправленным кодом CSS:
.FlexItem {
border: 1px solid #ebebeb;
background-color: #34005b;
display: flex;
height: 100px;
flex: 1;
}

Свойство flex является сокращенным определением трех свойств: flex-grow,
flex-shrink и flex-basis. Спецификацию, в которой дается развернутое описание
этих свойств, можно найти по адресу: http://www.w3.org/TR/css-flexbox-1/. В ней
рекомендована сокращенная форма flex, поэтому мы ее рассмотрим.

Рис. 4.12. Три возможных значения свойства flex

Свойство flex, примененное к элементам внутри flex-контейнера, указывает
размер элемента, а не значения ширины или высоты, если таковые имеются. Даже
если после свойства flex указано значение ширины или высоты, оно все равно не
будет действовать.
Если элемент, к которому добавлено свойство flex, не является flex-элементом,
то свойство не будет иметь никакого эффекта.
Теперь посмотрим, на что влияет каждое из его значений:
y flex-grow (первое значение, которое может быть передано свойству flex) —
величина, до которой может увеличиваться flex-элемент относительно
других flex-элементов при наличии свободного пространства.
y flex-shrink — величина, до которой может уменьшаться flex-элемент относительно других flex-элементов при дефиците пространства.
y flex-basis (последнее значение, которое может быть передано свойству
flex) — базовый размер, к которому приводится размер flex-элемента.

106

Глава 4. Fluid Layout, Flexbox и отзывчивые изображения

Хотя можно просто написать flex: 1 (что интерпретируется как flex: 1 1 0),
рекомендую записывать в свойство flex все три значения. Полагаю, вы понимаете, что может произойти. Например, flex: 1 1 auto означает, что элемент будет
увеличиваться на одну часть доступного пространства, он также станет уменьшаться до одной части, когда будет существовать дефицит пространства, и базовым
размером для динамического изменения послужит внутренняя ширина содержимого (размер, который был бы у содержимого, если бы динамическое изменение
не требовалось).
Рассмотрим еще один вариант: настройка flex: 0 0 50px означает, что элемент
не будет ни увеличиваться, ни уменьшаться и он будет иметь размер 50 px независимо от величины свободного пространства. А теперь разберем вариант flex: 2
0 50% — элемент будет стремиться занять два «лота» доступного пространства, он
не станет уменьшаться и его базовый размер будет определяться значением 50 %.
Надеюсь, эти небольшие примеры немного развеяли мистику вокруг свойства flex.
Если установить для свойства flex-shrink нулевое значение, то свойство
flex-basis поведет себя как задание минимальной ширины.

Свойство flex можно представлять в виде способа задания отношений. Если
для каждого flex-элемента этому свойству присвоено значение 1, то все они занимают одинаковое пространство.

Рис. 4.13. При одинаковых значениях гибкости все контейнеры имеют одинаковый
размер

Хорошо, но, чтобы проверить теорию на практике, внесем изменения в HTMLклассы разметки. Добавим классы FlexOne, FlexTwo и FlexThree к каждому элементу соответственно:

I am content in the inner Flexbox 1.
I am content in the inner Flexbox 2.
I am content in the inner Flexbox 3.


Различные макеты Flexbox внутри разных медиазапросов

107

Теперь удалим предыдущие стили, связанные с FlexItem, и вместо них добавим
этот код:
.FlexItem {
border: 1px solid #ebebeb;
background-color: #34005b;
display: flex;
height: 100px;
}
.FlexOne {
flex: 1.5 0 auto;
}
.FlexTwo,
.FlexThree {
flex: 1 0 auto;
}

В этом примере элемент с классом FlexOne занимает 1,5 пространства, занятого элементами с классами FlexTwo и FlexThree.

Рис. 4.14. Изменение количества свободного пространства, занимаемого
элементами, с помощью свойства flex-grow

Этот сокращенный синтаксис действительно полезен для быстрой установки
соизмеримости элементов. Например, свойство flex легко справляется с требованиями вроде «это должно быть в 1,8 раза шире всего остального».
Надеюсь, вы уже начинаете понимать эффективность свойства flex.
О Flexbox можно писать долго. Достойных примеров — великое множество.
Но перед тем, как перейти к другой теме — отзывчивым изображениям, хочу поделиться с вами еще двумя особенностями.

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

108

Глава 4. Fluid Layout, Flexbox и отзывчивые изображения



Here is a bunch of text up at the top. But there isn't enough content
to push the footer to the bottom of the page.


However, thanks to flexbox, I've been put in my place.



А вот так выглядит код CSS:
html,
body {
margin: 0;
padding: 0;
}
html {
height: 100%;
}
body {
font-family: 'Oswald', sans-serif;
color: #ebebeb;
display: flex;
flex-direction: column;
min-height: 100%;
}
.MainContent {
flex: 1 0 auto;
color: #333;
padding: 0.5rem;
}
.Footer {
background-color: violet;
padding: 0.5rem;
}

Посмотрите на окно браузера и попробуйте добавить содержимое в div контейнер с классом MainContent. При недостаточном объеме содержимого подвал
зафиксируется в нижней части окна просмотра. Когда содержимого хватит на
заполнения окна, подвал разместится ниже содержимого.
Все это потому, что свойство flex настроено на увеличение при наличии доступного пространства. Поскольку тело является flex-контейнером со 100 %-ной
минимальной высотой, основное содержимое может увеличиваться на все доступное пространство. Класс!

Различные макеты Flexbox внутри разных медиазапросов

109

Изменение порядка следования исходных элементов
В модуле Flexbox есть встроенная функция изменения порядка следования отображаемых элементов. Узнаем, как она работает.
Рассмотрим следующую разметку:

I am content in the Header.
I am content in the SideOne.
I am content in the Content.
I am content in the SideTwo.
I am content in the Footer.


Обратите внимание, что третий элемент внутри общего контейнера имеет
HTML-класс FlexContent, и представьте, что основное содержимое страницы
предполагается размещать в этом div-контейнере.
Не будем усложнять. Добавим несколько простых цветовых настроек, чтобы
различать разделы, и поместим эти разделы в том порядке, в котором они появляются в разметке:
.FlexWrapper {
background-color: indigo;
display: flex;
flex-direction: column;
}
.FlexItem {
display: flex;
align-items: center;
min-height: 6.25rem;
padding: 1rem;
}
.FlexHeader {
background-color: #105b63;
}
.FlexContent {
background-color: #fffad5;
}
.FlexSideOne {
background-color: #ffd34e;
}
.FlexSideTwo {
background-color: #db9e36;
}

110

Глава 4. Fluid Layout, Flexbox и отзывчивые изображения

.FlexFooter {
background-color: #bd4932;
}

В браузере это выглядит следующим образом:

Рис. 4.15. Здесь блоки отображаются в исходном порядке

Чтобы изменить порядок и сделать .FlexContent первым элементом без изменений в разметке, добавьте одну пару свойство —значение:
.FlexContent {
background-color: #fffad5;
order: -1;
}

Свойство order позволяет легко пересмотреть порядок следования элементов
внутри Flexbox. В данном примере значение -1 сообщает, что нужно поместить
элемент перед всеми остальными элементами.
Чтобы часто менять элементы местами, рекомендую расширить описание и присвоить каждому элементу порядковый номер. Это упростит понимание задачи
в сочетании с медиазапросами.

Различные макеты Flexbox внутри разных медиазапросов

111

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

I am content in the Content.
I am content in the SideOne.
I am content in the SideTwo.
I am content in the Header.
I am content in the Footer.


Сначала идет содержимое страницы, затем две боковые области, после этого
заголовок и, наконец, подвал. Flexbox позволяет структурировать HTML в том
порядке, который имеет смысл для документа независимо от того, как все должно
располагаться при отображении на экране.
После внесения небольших изменений в каждый FlexItem для самых мелких
экранов (вне каких-либо медиазапросов) порядок будет такой:
.FlexHeader {
background-color: #105b63;
order: 1;
}
.FlexContent {
background-color: #fffad5;
order: 2;
}
.FlexSideOne {
background-color: #ffd34e;
order: 3;
}
.FlexSideTwo {
background-color: #db9e36;
order: 4;
}
.FlexFooter {
background-color: #bd4932;
order: 5;
}

112

Глава 4. Fluid Layout, Flexbox и отзывчивые изображения

Соответственно, в браузере будет такая картина:

Рис. 4.16. Можно перемещать элементы в визуальном порядке с помощью одного
свойства

А затем в брейкпоинте произойдет переход к следующим настройкам:
@media (min-width: 30rem) {
.FlexWrapper {
flex-flow: row wrap;
}
.FlexHeader {
width: 100%;
}
.FlexContent {
flex: 1 0 auto;
order: 3;
}
.FlexSideOne {
width: 150px;
order: 2;
}
.FlexSideTwo {
width: 150px;
order: 4;
}

Различные макеты Flexbox внутри разных медиазапросов

}

113

.FlexFooter {
width: 100%;
}

В браузере это будет выглядеть таким образом:

Рис. 4.17. С помощью медиазапроса можно снова изменить визуальный порядок

В этом примере есть сокращение flex-flow: row wrap. Свойство flex-flow на
самом деле является сокращенным свойством, которое позволяет устанавливать
сразу два свойства в одном: flex-direction и flex-wrap.
Мы уже использовали flex-direction для переключения между строками и столбцами и для переворота элементов. Но еще не рассматривали свойство flex-wrap.

Свертка flex-элементов
По умолчанию элементы во flex-контейнере принимают форму контейнера, чтобы
уместиться в него, а иначе выходят за пределы контейнера. Рассмотрим код:

Item
Item
Item
Item


И CSS-код:
.container {
display: flex;
width: 500px;
background-color: #bbb;
align-items: center;
border: 1px solid #111;
}

1
2
3
4

114

Глава 4. Fluid Layout, Flexbox и отзывчивые изображения

.items {
color: #111;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 23px;
flex: 0 0 160px;
height: 40px;
border: 1px dashed #545454;
}

Вы спросите, почему внешний контейнер имеет свойство width, а не flex. Причина в том, что элемент не является flex-элементом (внутри самого Flexbox) и свойство flex для него не работает.

Поскольку ширина flex-контейнера составляет всего 500 px, эти четыре элемента не подходят по размеру:

Рис. 4.18. По умолчанию Flexbox всегда предотвращает свертку элементов

Эти элементы можно настроить на свертку с помощью flex-wrap: wrap. Это
свойство сворачивает элементы, когда они соприкасаются с краями контейнера.
Скорее всего, будут моменты, когда вы захотите свернуть flex-элементы, или
наоборот. Помните, что по умолчанию свертка не выполняется, но легко можно
внести изменения в одну строку.
Также помните, что вы можете установить свертку самостоятельно с помощью
свойства flex-wrap или как часть направления flex-flow и сокращения wrap.
Решим реальную проблему с помощью flex-wrap. Рассмотрим оглавление на
следующем изображении. При такой ширине их нелегко прочитать (рис. 4.19).
Изменим эту разметку с помощью медиазапроса и нескольких flex-свойств.
Сведем изменения в один медиазапрос здесь для краткости (помните, что вы можете использовать столько медиазапросов, сколько захотите). Мы подробно рассмотрели эти свойства в главе 3:
@media (min-width: 1000px) {
.rwd-Chapters_List {
display: flex;
flex-wrap: wrap;
}
.rwd-Chapter {
flex: 0 0 33.33%;
padding: 0 20px;

Различные макеты Flexbox внутри разных медиазапросов

}

115

}
.rwd-Chapter::before {
left: -20px;
}

Рис. 4.19. Это содержимое слишком растянуто при текущей ширине области просмотра

И это производит такой эффект в браузере:

Рис. 4.20. Настройка flex-контейнера для свертки располагает содержимое через
равные промежутки

Мы превратили контейнер оглавления во flex-контейнер. Затем, чтобы элементы не слипались друг с другом, установили контейнер для свертки. Для ограничения
ширины раздела главы до трети контейнера мы сократили отзывчивость, установив
значение 33,33 % для flex-basis и предотвратив рост или сжатие элемента. И добавили отступ, чтобы обеспечить небольшое пространство между элементами. Последняя небольшая поправка заключалась в добавлении нумерации глав.

116

Глава 4. Fluid Layout, Flexbox и отзывчивые изображения

Итоги по Flexbox
Благодаря возможности внесения динамических изменений Flexbox отлично подходит для создания отзывчивого веб-дизайна. Если раньше вы не работали с Flexbox, его новые свойства и значения покажутся вам странными, а предлагаемая им
простота формирования макета может поразить.
Другая современная система верстки — сетчатая (CSS Grid) будет рассмотрена
в главе 5. А сейчас мы займемся отзывчивыми изображениями и медиа.

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

Проблема, присущая отзывчивым изображениям
Разработчик не может заранее знать, с каких устройств пользователи будут заходить на его сайт сейчас или в будущем. Особенности просмотра веб-сайта, в том
числе размеры экрана и возможности устройства, известны только браузеру, который используется на этом устройстве.
И наоборот, только разработчики веб-сайта знают о версиях изображения.
Например, могут быть три версии изображения (малая, средняя и большая) для
разных размеров и плотностей экрана. Наша задача сообщить о них браузеру.
Таким образом, у веб-дизайнеров есть половина решения, т. е. информация об
изображениях, а второй половиной решения располагает браузер, знающий, с какого устройства зашли на сайт и какие размер и разрешение изображения будут
наиболее подходящими.
Как сообщить браузеру об имеющихся изображениях, чтобы он мог выбрать из
них самое подходящее для пользователя?
В первые несколько лет после появления отзывчивого веб-дизайна какого-либо способа сделать это просто не было. Но теперь есть спецификация встроенного
содержимого — Embedded Content: https://html.spec.whatwg.org/ multipage/embeddedcontent.html.
Там описаны способы переключения разрешения (вывода на экран с более высоким разрешением соответствующей версии изображения) и варианты «режиссуры», при которых разработчики предоставляют разные изображения в зависимости
от характеристик устройств (возникают мысли о медиазапросах). Примером режиссуры выступают изображение чего-либо крупным планом в меньших окнах просмотра и широкоугольное изображение того же объекта в больших окнах просмотра.

Отзывчивые изображения

117

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

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


Это почти так же просто, как и все, что касается отзывчивых изображений, поэтому давайте вникнем в смысл этого синтаксиса.
Сначала идет уже знакомый вам атрибут src, который здесь играет двойную
роль. Он указывает на самую простую версию изображения, а также служит указателем на изображение, выводимое в случае, если браузер не поддерживает атрибут srcset. С помощью атрибута src старые браузеры, игнорирующие информацию
в srcset, получат самое простое и, возможно, самое динамичное изображение.
Браузерам, понимающим атрибут srcset, предоставляется список изображений
на выбор, разделенных запятыми. За именем изображения (например, scones_
medium.jpg) следует указание на его разрешение. В данном примере использованы
указания 1,5x и 2x, но допускается применение любого целого числа. Например,
3x или 4x тоже будут работать, но только на экранах с высоким разрешением.
Я называю этот код подсказкой, а не инструкцией или командой, поскольку
в нем есть одна проблема: устройство с шириной экрана 1440 px и разрешением 1x
получит то же изображение, что и устройство с шириной экрана 480 px и разрешением 3x. Такой исход может оказаться нежелательным.

Более совершенный вариант переключения
с помощью srcset и sizes
Рассмотрим еще одну ситуацию. В отзывчивом веб-дизайне часто бывает, что
изображение занимает все пространство малого окна просмотра и только поло-

118

Глава 4. Fluid Layout, Flexbox и отзывчивые изображения

вину окна просмотра большего размера. Эту ситуацию иллюстрирует основной
пример из главы 1. Довести свои намерения до браузера можно следующим образом:


Внутри тега изображения снова используем srcset. Но на этот раз после указания изображений добавим значение с суффиксом w, сообщая таким образом
браузеру о ширине изображения. В нашем примере есть изображения с шириной 450 px (scones-small.jpg) и 900 px (scones-medium.jpg). Отмечу, что значение
с суффиксом w не является настоящим размером. Это указание браузеру на возможную ширину изображения в так называемых пикселах CSS.

Я задался вопросом, как определяется пиксел CSS? Затем нашел объяснение по
адресу: http://www.w3.org/TR/css3-values/#reference-pixel и понял, что лучше бы
я этим вопросом не задавался.

Значение с суффиксом w обретает больший смысл, если учитывается вместе
со значением атрибута sizes. Этот атрибут позволяет вам сообщать браузеру
о своих намерениях относительно изображений. В предыдущем примере первое
значение равноценно следующей установке: «Для устройств шириной не меньше 17 em показывай изображение с параметрами, близкими к 100 vw».

Если вы не можете разобраться в единицах измерения, таких как vh (1 vh является эквивалентом 1 % высоты окна просмотра) и vw (1 vw является эквивалентом
1 % ширины окна просмотра), обратитесь к главе 6.

Вторая часть указывает браузеру: «Для устройств шириной не меньше 40 em
показывай изображение шириной 50 vw». Пока учет ведется в dpi (или dpr (device
pixel ratio)), эта установка может показаться излишней. Например, для устройства
шириной 320 px с разрешением 2x (на полную ширину экрана которого выводится изображение шириной 640 px) браузер может решить, что изображение шириной 900 px подойдет больше, поскольку первый из имеющихся у него вариантов
касается изображения, которое будет достаточно большим для заполнения пространства требуемого размера.

Отзывчивые изображения

119

Браузер может предпочесть одно изображение другому?
Важно запомнить, что значения атрибута sizes всего лишь дают браузеру подсказку. Они не гарантируют повиновения со стороны браузера. И это, поверьте,
совсем неплохо и означает, что в будущем, если у браузеров появится надежный
способ выяснить возможности сети, он сможет предпочесть одно изображение
другому, понимая обстоятельства, не известные разработчикам. Возможно, пользователь настроит свое устройство на загрузку изображений с разрешением только 1х или только 2х и браузер сможет выбрать вызов подходящего кода.
Альтернативой решению браузера является использование элемента picture,
который гарантирует использование браузером конкретного запрошенного вами
изображения. Посмотрим на его работу.

Управление элементом picture
Последний сценарий, с которым вы можете столкнуться, предполагает наличие
разных изображений, применимых при разных размерах окон просмотра. Рассмотрим, к примеру, булочку из главы 1. Возможно, на самых маленьких экранах мы
захотим увидеть крупный план булочки, щедро политой вареньем и сливками. Для
более крупных экранов подойдет более широкое изображение: общий план стола
с разнообразной выпечкой. И наконец, в еще более крупных окнах просмотра можно показать кондитерскую на деревенской улице и людей за столиками, лакомящихся булочками и чаем (да, похоже на идиллию).
Нам нужны три разных изображения, наиболее подходящих к различным диапазонам окон просмотра. Решить эту задачу с помощью элемента picture можно
так:






Во-первых, имейте в виду, что элемент picture — это просто контейнер, помогающий другим изображениям попасть в тег img. Если нужно придать изображениям какое-то стилевое оформление, переключите свое внимание на тег img.
Во-вторых, атрибут srcset работает здесь так же, как и в предыдущем примере.
В-третьих, тег img предоставляет альтернативное изображение, а также изображение, которое будет показано, если браузер распознает изображение, но не
найдет его соответствия ни одному из медиаопределений. Запомните, что нельзя
убирать тег img из элемента picture, иначе это плохо кончится.
Особенностью picture является наличие в нем тега source, в котором можно
применять выражения в стиле медиазапросов, конкретно сообщая браузеру, какой
из ресурсов применять в той или иной ситуации. Например, в первом элементе из

120

Глава 4. Fluid Layout, Flexbox и отзывчивые изображения

предыдущего примера браузеру предписывается: «Если ширина экрана не меньше
30 em, загрузи изображение cake-table.jpg». При совпадении условий браузер подчинятся предписанию.

Продвижение новых форматов изображений
В качестве бонуса picture также помогает предоставлять альтернативные форматы изображений. WebP — это новый формат изображений, продвигаемый Google,
который не поддерживает браузер Safari (проверьте, так ли это до сих пор, по адресу: http://caniuse.com/#search=WebP). По качеству он не уступает JPG, но имеет
гораздо меньше полезной нагрузки. Поэтому если ваш браузер поддерживает этот
формат, то есть смысл предоставить ему этот формат изображения:





Надеюсь, теперь ситуация прояснилась. Вместо атрибута media используется
атрибут type, который хотя и применяется чаще всего для указания на видео­
источники (возможные типы видеоисточников можно найти на сайте https://html.
spec.whatwg.org/ multipage/embedded-content.html#attr-source-type), в данном случае
позволяет определить формат WebP как наиболее предпочтительный. Если брау­
зер в состоянии его отобразить, он это сделает, а если нет — возьмет исходный
формат изображения, указанный в теге img.

Итоги
Мы начали с создания fluid layout, изменяемого с помощью медиазапросов. Познакомились с Flexbox и достаточно простыми способами решения часто встре­
чающихся проблем верстки.
Рассмотрели способы обслуживания любого количества альтернативных изображений для разных экранов. Узнали, что благодаря применению srcset, sizes
и picture пользователи получают самые подходящие изображения, отвечающие
их потребностям.
К счастью, недавно в CSS появились два отличных механизма верстки. Сразу
за модулем Flexible Box Layout появился модуль Grid Layout Level 1: http://www.
w3.org/TR/css3-grid-layout/.
Как и Flexbox, Grid содержит новый синтаксис. Но пусть это вас не смущает.
Следующая глава полностью посвящена системе Grid, ее возможностям и вариантам использования.

5

CSS Grid

Вне всяких сомнений, появление сеток, или гридов (Grid), стало переломным моментом в истории CSS.
Теперь у нас есть система, способная достичь ожидаемого результата с меньшим
количеством кода и большей надежностью, значительно расширившая возможности!
Можно сказать, что система Grid является скорее революционной, нежели
эволюционной. В ней есть совершенно новые концепции, которые не имеют аналогов в CSS. Потребуется время, чтобы привыкнуть к ней, но поверьте — это того
стоит.
В этой главе разберем следующие темы:
y Что такое CSS Grid и какие проблемы она решает.
y Основные концепции CSS Grid.
y Терминология Grid.
y Настройка сетки.
y Размещение элементов в сетке.
y Создание мощных отзывчивых паттернов с минимумом кода.
y Сокращенный синтаксис сетки.
Ближе к концу главы я дам небольшое упражнение, чтобы вы могли применить
некоторые приемы рефакторинга к части веб-сайта https://rwd.education.

Что такое CSS Grid и какие проблемы она
решает
Grid — это система двухмерного макета. Модуль Flexbox, который мы рассмотрели в предыдущей главе, размещает элемент только в одном измерении/направлении: либо в строку, либо в столбец. Он не может разместить элемент одновременно вдоль и поперек, и для этих целей предназначена система Grid.
Не нужно выбирать между Flexbox и Grid при создании проектов. Они не исключают друг друга. Обычно я использую обе системы, даже в рамках одного
визуального компонента.

122

Глава 5. CSS Grid

Когда вы применяете Grid, не нужно отказываться от других макетов. Например, Flexbox вполне можно использовать внутри сетки. Точно так же часть интерфейса, закодированная с помощью Grid, вполне может находиться внутри Flexbox
либо стандартного или линейного блока.
В разных случаях уместны как сетки, так и Flexbox или другой макет.
По правде говоря, мы годами создавали макеты по типу сетки с помощью CSS.
У нас просто не было специального механизма верстки такого рода. Мы использовали блоки, числа с плавающей запятой, таблицы и многие другие гениальные
методы, чтобы обойти отсутствие в CSS надлежащей системы сеточной разметки.
Теперь такой механизм есть.
С помощью CSS Grid мы можем создавать сетки практически с бесконечным
числом перестановок и размещать дочерние элементы в любом месте независимо
от их исходного порядка. Более того, Grid даже предусматривает добавление дополнительных элементов и адаптируется к потребностям контента. Если вы думаете, что я преувеличиваю, значит, пора переходить к делу.

Базовый синтаксис Grid
Чтобы использовать Grid, нужно сообщить браузеру:
y количество строк и столбцов в сетке;
y размеры строк и столбцов;
y местоположение элементов в сетке;
y ответ на случай, если размер сетки изменится или в сетку будет добавлено
больше элементов.
То есть связь сетки с браузером — это вопрос понимания терминологии.

Терминология, специфичная для Grid
Первое, что нужно понять, — это «явное» и «неявное» размещение элементов. Сетка, которую вы определяете в своем CSS-коде со столбцами и строками, является
явной, поскольку представляет собой расположение элементов, которые определены явно. Неявным называется размещение в сетке новых элементов, появление
которых вы не предусматриваете, но разметка явной сетки допускает.
Следующие термины, которые часто сбивают с толку (меня они смутили),
связаны с тем, что линии сетки находятся по обе стороны от элементов. Пространство между двумя соседними линиями сетки называется дорожкой сетки
(track), а прямоугольная область, ограниченная четырьмя линиями сетки и состоящая из одной или нескольких соседних ячеек, называется «областью сетки» (grid area).
Запомните, что вы можете размещать элементы в сетке, ссылаясь на линии
сетки (которые подразумевают область сетки) или на сами области сетки, если они
названы.

Настройка сетки

123

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

Настройка сетки
Вот введение в раздел спецификации W3C о явных сетках (https://www.w3.org/TR/
css-grid-1/#explicit-grids). Его стоит перечитать несколько раз, так как оно содержит
важную информацию для понимания работы сетки:
Три свойства grid-template-rows, grid-template-columns и grid-templatesizes вместе определяют явную сетку grid-контейнера. Окончательная
сетка может оказаться больше, поскольку некоторые элементы могут быть
размещены за пределами явной сетки. В этом случае будут созданы неявные
дорожки, размер которых будет определяться свойствами grid-auto-rows
и grid-auto-columns.
Размер явной сетки определяется наибольшим числом строк/столбцов,
определенных свойством grid-template-areas, и количеством строк/столбцов, размер которых определяется свойствами grid-template-rows / gridtemplate-columns.
Любые строки/столбцы, определенные свойством grid-template-areas, но
размер которых не задан свойством grid-template-rows / grid-templatecolumns, получают свой размер из свойств grid-auto-rows / grid-autocolumns. Если эти свойства не определяют никаких явных дорожек, явная
сетка по-прежнему будет содержать одну линию сетки на каждой оси.
Числовые индексы в свойствах размещения отсчитываются от краев явной
сетки. Положительные индексы считаются с начальной стороны (от 1 для
самой начальной явной строки), а отрицательные индексы подсчитываются с конечной стороны (от –1 для самой конечной явной строки).
grid и grid-template — это свойства, которые позволяют использовать
сокращение для одновременной установки трех свойств явной сетки (gridtemplate-rows, grid-template-columns и grid-template-sizes). Сокращение
grid сбрасывает свойства, управляющие неявной сеткой, тогда как свойство
grid-template оставляет их неизменными.

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

124

Глава 5. CSS Grid

Начнем путешествие по коду Grid с примера самой простой в мире сетки из
четырех пронумерованных полей. В браузере она выглядит так:

Рис. 5.1. Самая простая сетка

Вот разметка:

1
2
3
4


Обратите внимание, что в Grid паттерн разметки — это элемент-контейнер,
которым является сетка, и его прямые потомки — элементы сетки. Напишите разметку для дочерних элементов сетки в порядке, наиболее подходящем для содержимого, и Grid позволит разместить их визуально там, где вам это нужно. Вот
соответствующий CSS-код:
.my-first-grid {
display: grid;
grid-gap: 10px;
grid-template-rows: 200px 200px;
grid-template-columns: 200px 200px;
background-color: #e4e4e4;
}
.grid-item-1 {
grid-row: 1;
grid-column: 1;
}
.grid-item-2 {
grid-row: 1;
grid-column: 2;

Настройка сетки

125

}
.grid-item-3 {
grid-row: 2;
grid-column: 1;
}
.grid-item-4 {
grid-row: 2;
grid-column: 2;
}
[class^='grid-item'] {
outline: 3px dashed #f90;
font-size: 30px;
color: #333;
}

Части, на которых следует сосредоточиться в этом CSS-коде, — это свойства,
специфичные для сетки. Я добавил несколько контуров и фон, чтобы было легче
увидеть, где находится сетка, а также размер и форму элементов сетки.
Используем свойство display: grid, чтобы установить контейнер как сетку,
а затем напишем grid-template-rows: 200px 200px, чтобы установить две строки
высотой по 200 px, и grid-template-columns: 200px 200px, чтобы установить два
столбца шириной по 200 px.
Добавим числа в свойства grid-row и grid-column, чтобы указать сетке, в какие
строку и столбец поместить элемент.
По умолчанию дочерние элементы сетки являются частью разметки стандартного типа. Хотя в этом примере элементы сетки находятся внутри нее, поскольку
все они являются элементами div, они по-прежнему вычисляются как display:
block. Это важно понимать при выравнивании элементов сетки.

Можете попрактиковаться с этим примером в файле example_05-01.

Воспользуемся свойствами выравнивания, о которых говорили в предыдущей
главе, чтобы выровнять элементы сетки по центру:
.my-first-grid {
display: grid;
grid-gap: 10px;
grid-template-rows: 200px 200px;
grid-template-columns: 200px 200px;
background-color: #e4e4e4;
align-items: center;
justify-content: center;
}

126

Глава 5. CSS Grid

Когда я начал работать с Grid и попробовал что-то подобное, я ожидал увидеть,
что числа будут идеально выровнены по центру на соответствующих дорожках
сетки. Но этого не произошло.

Рис. 5.2. Если вы не зададите ширину, сетка будет занимать доступное ей пространство

Мы создали сетку из двух столбцов и двух строк фиксированного размера и написали инструкцию, чтобы элементы были выровнены как по вертикали, так и по
горизонтали. Поскольку мы использовали свойство grid, а не inline-grid, сетка
заполнила всю ширину страницы, несмотря на то что ее элементам не требовалось
это пространство.
Настроим сетку таким образом, чтобы ее ширина была равна ширине ее содержимого. И выровняем элементы по центру внутри соответствующих элементов
сетки. Для этого можно сделать сами элементы Flexbox или Grid. В этой главе
попробуем использовать Grid:
.my-first-grid {
display: inline-grid;
grid-gap: 10px;
grid-template-rows: 200px 200px;
grid-template-columns: 200px 200px;
background-color: #e4e4e4;
}
[class^='grid-item'] {
display: grid;
align-items: center;
justify-content: center;
outline: 3px dashed #f90;
font-size: 30px;
color: #333;
}

Если селектор с каретом (^) вам не знаком, не беспокойтесь. Мы рассмотрим его
в главе 6.

Настройка сетки

127

Мы применили к контейнеру свойство inline-grid, установили для всех элементов сетки display: grid и использовали свойства выравнивания justifycontent и align-items.
Эти действия дали следующий результат:

Рис. 5.3. Превращая дочерние элементы во flex- или grid-элементы, мы получаем
возможность выравнивать их содержимое по центру

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

Хорошо, небольшой прогресс есть. Перейдем к теме явного и неявного размещения элементов.

Явное и неявное позиционирование элементов
Мы уже обсуждали разницу между явной и неявной сеткой. Явная сетка — это
структура, которую вы настраиваете в своем CSS-коде. Когда в эту сетку помещается больше содержимого, чем вы планировали, появляется «неявная»
сетка.
Расширим предыдущий пример.
Добавим еще один элемент и посмотрим, что произойдет:

1
2
3
4
5


128

Глава 5. CSS Grid

С учетом этого кода браузер покажет следующее:

Рис. 5.4. В сетке появился новый элемент, но не с теми пропорциями,
на которые мы рассчитывали

Сетка создала неявные линии и дорожку для нового элемента. Мы не давали
ей инструкций относительно дополнительного элемента, поэтому она сделала
предположение о его внешнем виде сама. Но мы можем управлять обработкой
неявных элементов с помощью свойств grid-auto-rows и grid-auto-columns.

Свойства grid-auto-rows и grid-auto-columns
Используем свойства grid-auto-rows и grid-auto-columns, чтобы сделать дополнительные элементы сетки того же размера, что и существующие:
.my-first-grid {
display: inline-grid;
grid-gap: 10px;
grid-template-rows: 200px 200px;
grid-template-columns: 200px 200px;
grid-auto-rows: 200px;
grid-auto-columns: 200px;
background-color: #e4e4e4;
}

Теперь, без лишнего CSS-кода, дополнительные элементы, помещаемые в сетку, получат заданный размер 200 px × 200 px. Кроме того, мы добавили еще один
элемент в DOM и теперь в сетке шесть элементов (рис. 5.5)
Вы даже можете создавать паттерны так, чтобы первый новый элемент был
одного размера, а следующий — другого. Паттерн будет повторяться:
.my-first-grid {
display: inline-grid;
grid-gap: 10px;
grid-template-rows: 200px 200px;
grid-template-columns: 200px 200px;

Настройка сетки

}

129

grid-auto-rows: 100px 150px;
grid-auto-columns: 100px 150px;
background-color: #e4e4e4;

Рис. 5.5. Если задать некоторые автоматические настройки, добавляемые элементы
будут получать более предпочтительные размеры

Рис. 5.6. Вы можете указать паттерн размера для любых автоматически добавленных
строк или столбцов

130

Глава 5. CSS Grid

Видите, как элемент 5 и последующие элементы используют паттерн, который
мы определили в значении свойства grid-auto-rows? Сначала высота составляла
100 px, затем 150 px и далее снова 100 px.
Сейчас элементы сетки перемещаются вертикально вниз по странице, но можно легко переключить это перемещение на горизонтальное! Попрактикуйтесь
с этим кодом в каталоге example_05-03.

Свойство grid-auto-flow
Свойство grid-auto-flow позволяет определять направление движения неявно
добавленных элементов внутри сетки. Используйте значение column, чтобы сетка
добавляла столбцы для размещения дополнительных элементов, или значение row,
чтобы сетка добавляла строки.
Добавим свойство grid-auto-flow: column, чтобы элементы добавлялись справа, а не снизу:

Рис. 5.7. Переключение ориентации сетки для добавления элементов
по горизонтали

Можно добавить ключевое слово dense к значению свойства и получить gridauto-flow: column dense или grid-auto-flow: row dense. Мы рассмотрим его
подробнее в ближайшее время.

Размещение и изменение размера
элементов сетки
До сих пор каждый элемент, который мы добавляли, занимал одну ячейку сетки.
Рассмотрим новый пример (код каталога example_05-04). В этой сетке есть 20 gridэлементов — продуктов питания и их исходный порядок в контейнере в виде числа. Взгляните на код и скриншот и попробуйте найти несколько новых свойств
CSS, прежде чем читать дальше.

Размещение и изменение размера элементов сетки

131

Я намеренно перепутал использование пробелов в значениях. Вы можете записать grid-row: 6 / span 2 или grid-row: 6/span 2 — и то и другое будет верно.
Просто выберите запись, которая вам больше нравится.
Вот разметка:

1. tofu
2. egg plant
3. onion
4. carrots
5. swede
6. scones
7. cucumber
8. carrot
9. yam
10. sweet potato
11. peas
12. beans
13. lentil
14. tomato
15. butternut squash
16. ham
17. pizza
18. pasta
19. cheese
20. milk


Вот CSS:
.container {
font-size: 28px;
font-family: sans-serif;
display: grid;
gap: 30px;
background-color: #ddd;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 100px;
grid-auto-flow: row;
}
[class^='grid-item'] {
outline: 1px #f90 dashed;
display: grid;
background-color: goldenrod;
align-items: center;
justify-content: center;
}
.grid-item3 {
grid-column: 2/-1;

132

Глава 5. CSS Grid

}
.grid-item6 {
grid-row: 3/6;
grid-column: 3 / 5;
}
.grid-item17 {
grid-row: 6 / span 2;
grid-column: 2/3;
}
.grid-item4 {
grid-row: 4 / 7;
}

И вот что мы получаем в браузере:

Рис. 5.8. Grid-элементы произвольного размера

Размещение и изменение размера элементов сетки

133

Мы использовали в этом коде несколько новых свойств. Рассмотрим каждое
из них.

Свойство gap
Я использовал свойство gap в некоторых предыдущих примерах кода, но не объяснил его. Исправляюсь. Свойство gap позволяет указывать промежутки между
дорожками сетки. На самом деле это сокращенный вариант свойств row-gap
и column-gap. В нем вы указываете два значения: первое значение применяется
к промежутку между верхней и нижней строками, а второе — к промежутку между левым и правым столбцами. Если вы укажете одно значение, как у нас, оно
применится в обоих направлениях.

Иногда встречается grid-gap вместо gap. Свойство называлось grid-gap до
того, как было пересмотрено, а многие браузеры изначально поддерживали
только grid-gap. Если вам нужна самая широкая поддержка браузеров, смело
используйте grid-gap вместо gap.

Функция repeat()
При создании сетки из 30 одинаковых столбцов утомительно писать auto 30 раз:
grid-template-columns: auto auto auto auto auto auto ... ; — мне уже скучно!
К счастью, авторы спецификации Grid подарили нам функцию repeat(). Как
вы, возможно, догадались, функция repeat() предоставляет удобный способ указывать инструкции для любого количества элементов. В нашем примере мы использовали его для создания четырех столбцов шириной 1 fr:
repeat(4, 1fr);

Первое значение в круглых скобках — это количество желаемых повторений,
второе значение — ширина каждого элемента.
Единицы fr мы обсудим совсем скоро. Пока просто знайте, что вы можете легко создавать несколько столбцов/строк. Хотите получить 15 столбцов шириной
100 px? Это так же просто, как repeat(15, 100px).

Единица fr
Единица fr является единицей «гибкой длины» и представляет собой «flex-дробь».
Она используется, чтобы сообщить браузеру, какую долю доступного свободного
пространства мы хотим использовать, во многом подобно свойству flex-grow Flexbox, которое мы рассмотрели в главе 4.

134

Глава 5. CSS Grid

Я представляю единицы fr как «свободную комнату», когда думаю о разметке.
В нашем примере мы создали четыре столбца, каждый из которых занимает свою
долю доступного свободного пространства.

Размещение элементов в сетке
До этого примера мы позиционировали каждый элемент в одной области сетки.
Однако есть grid-элементы, которым численно назначаются промежутки столбцов
или строк.
Возьмем пример grid-item3:
.grid-item3 {
grid-column: 2/-1;
}

Значение свойства grid-column начинается со второй линии сетки и заканчивается на линии сетки -1. Поначалу значение -1 выглядит странно, но это часть
очень умного синтаксиса.
Первое число — это начальная точка, которая отделена от конечной точки
слешем. Положительные числа считаются с начальной стороны — в данном случае левой, тогда как отрицательные числа начинаются с конечной стороны —
правой. Итак, значение -1 в основном означает последнюю линию сетки. Таким
образом, этот красивый краткий синтаксис сообщает: «Начни с линии 2 и иди до
конца».
Я намеренно не касался некоторых других примеров с большим количеством
свободного пространства вокруг чисел, чтобы показать, что вы можете оставить
свободное пространство или убрать его — ничего страшного не случится.
В указанном фрагменте кода также есть пример распределения по строкам.
Взгляните на него еще раз:
.grid-item4 {
grid-row: 4 / 7;
}

В этом коде содержится команда для размещения по строкам: «Начни с линии 4
и закончи на линии 7».

Ключевое слово span
Теперь взгляните на CSS-код .grid-item17:
.grid-item17 {
grid-row: 6 / span 2;
grid-column: 2/3;
}

Размещение и изменение размера элементов сетки

135

Заметили изменение в значении свойства grid-row?
Вместо того чтобы указывать начальную и конечную точки при размещении
элемента, можно указать одну или другую точку и количество строк или столбцов
от этой точки, которые он должен занять. В нашем примере мы сказали элементу
начинать размещение с линии 6 и занимать 2 строки.
Полагаю, возвращение вас немного запутает, но со мной только так! Чтобы
показать возможности ключевого слова span, напишем grid-row: span 2 / 8.
В этом случае определена конечная точка, поэтому элемент начнет размещение
с линии 8 и займет 2 строки.

Ключевое слово dense
Помните, когда мы рассматривали пример со свойством grid-auto-flow, я упоминал ключевое слово dense? Сейчас есть возможность показать, на что оно способно. Я изменю значение свойства grid-auto-flow на grid-auto-flow: row dense;.
И вот что оно делает в браузере:

Рис. 5.9. Ключевое слово dense переупорядочивает элементы сетки таким образом,
что отступы удаляются

136

Глава 5. CSS Grid

Видите, как заполнены отступы? Вот что делает dense. Но за это эстетичное
решение приходится платить. Я пронумеровал элементы, чтобы подчеркнуть, что
использование dense командует алгоритму сетки перемещать объекты визуально
из исходного порядка в любое доступное пространство.

Именованные линии сетки
Grid позволяет разработчикам по-разному работать с сетками. Например, если вы
предпочитаете работать со словами, а не с числами, то можете поименовать линии
сетки. Рассмотрим сетку из 3 столбцов и 3 строк.

Можете найти этот пример в каталоге example_05-05.

Рис. 5.10. Используем именованные линии сетки, чтобы переставить элементы

Вот наша разметка:

1
2
3

Именованные линии сетки

9

Мы устанавливаем правило для сетки. Обратите внимание на слова в квадратных скобках:
.my-first-grid {
display: inline-grid;
grid-gap: 10px;
grid-template-columns: [left-start] 200px [left-end center-start] 200px
[center-end right-start] 200px [right-end];
grid-template-rows: 200px 200px 200px;
background-color: #e4e4e4;
}

В квадратные скобки помещаем имена линий сетки. Первую линию столбцов
сетки мы назвали left-start, а следующую линию мы назвали left-end. Обратите внимание, что центральной линии сетки мы присвоили два имени: left-end
и center-start, разделив их пробелом, поскольку эта линия является концом левого столбца и началом центрального.
Изменим свойство grid-template-row и добавим в него несколько именованных
линий сетки:
grid-template-rows: [top-start] 200px [top-end middle-start] 200px
[middle-end bottom-start] 200px [bottom-end];

Вот пример того, как мы можем использовать эти имена для размещения gridэлементов вместо числовых значений. Это только первые три элемента, которые
мы увидим на следующей схеме:
.grid-item-1 {
grid-column: center-start / center-end;
grid-row: middle-start / middle-end;
}
.grid-item-2 {
grid-column: right-start / right-end;
grid-row: bottom-start / bottom-end;
}
.grid-item-3 {
grid-column: left-start / left-end;
grid-row: top-start / middle-start;
}

138

Глава 5. CSS Grid

Я установил каждый элемент сетки в случайное положение, используя эту
технику. Посмотрите, как эти три элемента размещены на схеме:

Рис. 5.11. С помощью именованных линий сетки можно легко перемещать объекты

В терминах спецификации имена, которые мы назначаем линиям сетки, известны как «пользовательские идентификаторы». Избегайте использования терминологии, которая может конфликтовать с ключевыми словами сетки. Например,
не давайте линиям сетки имена «dense», «auto-fit» или «span»!
Grid имеет дополнительную особенность, которую вы можете использовать
с помощью именованных линий сетки. Если вы добавите свои имена с помощью
«-start» и «-end», как в нашем примере, то сетка автомагически (знаю, нет такого
слова) создаст именованную область сетки. Стоп, что? Да, это означает, что после
того, как вы дали имена своим линиям сетки, то можете размещать элементы
в своей сетке с помощью однолинейной grid-area. В доказательство приведу первые три правила grid-элементов из ранее переписанных таким образом:
.grid-item-1 {
grid-area: middle / center;
}
.grid-item-2 {
grid-area: bottom / right;
}
.grid-item-3 {
grid-area: top / left;
}

Именованные линии сетки

139

Я немного забегаю вперед, так как ввел свойство grid-area без объяснений.
Рассмотрим его.

Свойство grid-template-areas
Еще один способ работы с Grid — создание шаблона сетки для определения областей. Изменим предыдущий пример и полностью удалим именованные линии
сетки, начав снова с базового кода CSS.
Вот код из example_05-06:
.my-first-grid {
display: inline-grid;
grid-gap: 10px;
grid-template-columns: 200px 200px 200px;
grid-template-rows: 200px 200px 200px;
background-color: #e4e4e4;
}
[class^='grid-item'] {
display: grid;
align-items: center;
justify-content: center;
outline: 3px dashed #f90;
font-size: 30px;
color: #333;
}

Теперь определим grid-области шаблона, которые добавим в правило .my-firstgrid:
grid-template-areas:
'one two three'
'four five six'
'seven eight nine';

С помощью grid-template-area можно очень просто определять строки и столбцы. Строка определяется в кавычках (двойных или одинарных) с именами каждого столбца, разделенными пробелами. То есть строка — это пара кавычек с настраиваемыми идентификаторами.

Вы можете использовать числа для начала каждой grid-области, но в ссылках их
придется «экранировать». Например, если одна из областей названа «9», на нее
нужно ссылаться следующим образом: grid-area: "\39;". Я считаю это слишком обременительным, поэтому предлагаю использовать строку для каждой области или, по крайней мере, начинать каждый пользовательский идентификатор
с буквенного символа.

140

Глава 5. CSS Grid

Это значит, что мы можем позиционировать элементы с помощью grid-area
следующим образом:
.grid-item-1 {
grid-area: five;
}
.grid-item-2 {
grid-area: nine;
}
.grid-item-3 {
grid-area: one;
}

Это, разумеется, упрощенный пример, но надеюсь, вы можете представить
более полезный сценарий, например макет блога с заголовком, областью левой
боковой панели, областью основного содержимого и нижним колонтитулом. Можно определить значения grid-template-area так:
grid-template-areas:
'header header header header header header'
'side side main main main main'
'side side footer footer footer footer';

Поскольку в спецификации (https://www.w3.org/TR/css-grid-1/#valdef-grid-templateareas-string) сказано, что пробельный символ не может создать токен, вы можете
выбрать разделение столбцов с помощью символов табуляции, если хотите визуально выровнять столбцы.

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

Применение ваших знаний на практике
Рассмотрим в качестве упражнения следующий раздел веб-сайта https://rwd.
education (рис. 5.12).
Если вы посмотрите в папку Start с кодом к этой главе, то увидите, что блоки
находятся друг над другом. Попробуйте изменить код этой страницы с помощью
Grid. Подумайте, как отобразить один или два блока, если пространство на экране
ограничено, и вывести блоки на экран так, как показано на предыдущем скриншоте, если позволяет свободное пространство.

Применение ваших знаний на практике

141

Рис. 5.12. Можете ли вы использовать свои знания о Grid, чтобы расположить
элементы в этом разделе?

Уже существует рабочий проект CSS Grid Layout Module Level 2. Основное его
преимущество заключается в возможности формировать подсетки — одни сетки
внутри других, которые способны наследовать размеры дорожек родительских
сеток. Вы можете ознакомиться с его текущей спецификацией по адресу: https://
www.w3.org/TR/css-grid-2/.

Теперь перейдем к еще более продвинутым методам Grid.

Ключевые слова auto-fit и auto-fill
Auto-fit и auto-fill — это ключевые слова, осуществляющие принцип «повторе-

ние до заполнения», которые используются для описания повторения в сетке.
Эти ключевые слова похожи и почти гарантированно сбивают с толку так же,
как cover и contain при изменении размера фонового изображения (мы рассмотрим
их в главе 7).

142

Глава 5. CSS Grid

В результате мне часто приходится проверять, какой из них какую задачу выполняет. К счастью, мы собираемся прояснить, что каждый из них делает и почему
они полезны.
Начнем с вопроса «почему», поскольку он касается обоих ключевых слов. Что,
если я скажу, что с помощью auto-fill или auto-fit можно создавать полностью
отзывчивую сетку, которая добавляет и удаляет столбцы в зависимости от доступного размера области просмотра без необходимости в медиазапросах?
Убедительно, правда?
Рассмотрим сетку из 9 столбцов шириной не менее 300 px каждый. Сразу покажу решение:
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));

И вот что отобразится в браузере на малой области просмотра:

Рис. 5.13. Одна линия с сеткой дает в результате разметку для областей просмотра
мобильных устройств…

А это — на более широкомэкране:

Рис. 5.14. …а также разметку для более широких областей просмотра!

Применение ваших знаний на практике

143

Удобно, правда?
Разберемся с магией в этом однострочнике.
Используем, как и раньше, свойство grid-template-columns для настройки
столбцов сетки. Далее применяем функцию repeat() для настройки повторяющегося паттерна столбцов. Но вместо того, чтобы заниматься каждым столбцом, мы
сообщаем сетке ключевое слово auto-fit, чтобы произвести автоподгонку. Здесь
можно использовать и auto-fill, и скоро мы его рассмотрим. Сейчас мы сказали
браузеру многократно создавать столбцы с автоподгонкой и определили ширину
этих столбцов, используя функцию minmax().

Функция minmax()
Если вы не так давно знакомы с системой Grid, возможно, вы раньше не использовали minmax(). Это функция CSS, которая позволяет настраивать диапазон
размеров для браузера. Если указать в ней минимальный и максимальный размеры, то она вычислит их среднее значение на основе доступного пространства.
В нашем примере мы передадим minmax() минимальный размер 300 px и максимальный размер 1 fr (помните, что единицы fr можно представить как «свободную
комнату»).

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

Сетка автоматически подгонится под столбцы шириной не менее 300 px и не
более суммы размера ее содержимого и части оставшегося пространства величиной
в 1 fr.
На практике это обеспечивает отзывчивость разметки, которая позволяет сетке изменять размер в зависимости от доступной ширины области просмотра.
Чтобы показать разницу между auto-fit и auto-fill, я изменю минимальную
ширину столбца на 100 px:
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));

В результате мы получим следующую разметку в широкой области просмотра:

Рис. 5.15. С помощью auto-fit браузер распределяет содержимое по доступному
пространству

144

Глава 5. CSS Grid

Обратите внимание, что столбцы занимают всю ширину страницы. Теперь заменим ключевое слово auto-fit на auto-fill:
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));

Вот что получится:

Рис. 5.16. При использовании auto-fill свободное пространство заполняется
невидимыми столбцами

Обратите внимание на пустое пространство в конце. Что там произошло?
Чтобы понять разницу, посмотрите, свернуты ли лишние столбцы.
Когда браузер создает сетку как с auto-fit, так и с auto-fill, он изначально
размещает элементы одинаково. Однако при использовании auto-fit лишние
столбцы, оставшиеся после размещения содержимого, сворачиваются, оставляя
свободное пространство, равномерно распределенное между элементами в строке.
В нашем примере элементы имеют максимальную ширину 1 fr каждый и занимают равные части свободного пространства. В результате столбцы занимают всю
ширину страницы.
При использовании auto-fill ненужные пустые столбцы не сворачиваются.
Они остаются на месте заполненными и не дают элементам отобрать их пространство, которое видно в конце строки.
Будут ситуации, когда одно ключевое слово более уместно, чем другое. Просто
знайте, какого результата с их помощью вы можете добиться.

На некоторых скриншотах видны индикаторы расположения линий сетки. Они
взяты из инструментов разработчика Firefox Grid, которые я считаю лучшими
в своем роде.

Сокращения в синтаксисе
Есть несколько сокращений в синтаксисе, которые можно использовать с Grid:
одно относительно простое, другое — сложнее. Вероятно, больше пользы вы найдете в grid-template.
Хотя сокращения синтаксиса могут быть удобными, я бы посоветовал для начала писать в сетки по одному свойству за раз. Когда вы будете достаточно уверены, что составление каждого свойства по отдельности становится рутиной, найдите время, чтобы изучить их сокращенные варианты.
А пока отойдем от этого совета и рассмотрим два метода сокращения.

Сокращения в синтаксисе

145

Сокращение grid-template
Это сокращение позволяет задавать значения для свойств grid-template-rows,
grid-template-columns и grid-template-areas в одной строке.
Так, например, для сетки с двумя строками по 200 px и тремя столбцами по
300 px можно написать:
grid-template: 200px 200px / 300px 300px 300px;

Или, если вы хотите применить функцию repeat(), можете написать:
grid-template: repeat(2, 200px) / repeat(3, 300px);

Часть перед слешем касается строк и пространства после столбцов. Можете
добавить в нее grid-template-area, если хотите:
grid-template:
[rows-top] 'a a a' 200px
'b b b' 200px [rows-bottom]
/ 300px 300px 300px;

Браузер вычисляет эти инструкции следующим образом:
grid-template-rows: [rows-top] 200px 200px [rows-bottom];
grid-template-columns: 300px 300px 300px;
grid-template-areas: 'a a a' 'b b b';

Мне кажется, что, как только вы начинаете вставлять шаблонные области
в значения, все становится непросто. Но некоторым нравятся сокращения, и вы
должны знать о них.
А сейчас поднимемся еще на одну ступеньку и займемся сокращением grid.

Сокращение grid
Другое сокращение — grid — позволяет определять всю сетку в одной строке
кода.
Используя это свойство, вы можете устанавливать свойства, управляющие как
явной частью сетки: grid-template-rows, grid-template-columns и grid-templatearea, так и неявной частью сетки: grid-auto-rows, grid-auto-columns и grid-autoflow.
Сокращение grid опирается на факт, что сетка может неявно расти посредством
только строк или только столбцов, но не с помощью тех и других одновременно.
Поначалу это может показаться странным, но задумайтесь, как может сетка, способная добавлять как строки, так и столбцы, неявно размещать элементы? Как она
решит, куда их добавить — в строки или в столбцы?
Сокращение grid — инструмент не для слабонервных, поэтому не расстраивайтесь, если сначала будет сложно. Я считаю, что хорошо разбираюсь в CSS (вы же

146

Глава 5. CSS Grid

на это надеялись, верно?), но даже мне потребовались часы, а не минуты, чтобы
понять, как работает сокращение grid.
Надеюсь, вы знаете форму Бэкуса — Наура, потому что на ее примере сокращение grid описано в спецификации:
/ [ auto-flow && dense? ] ?
[ auto-flow && dense? ] ? /

Это просто!
Шучу, конечно. Пытаясь понять спецификацию, я нашел эту статью: https://
www.smashingmagazine.com/2016/05/understanding-the-css-property-value-syntax/.
Нужно преобразовать эту часть спецификации во что-то более понятное для
человека. Итак, сокращение grid может принимать в качестве значения любой из
трех различных наборов синтаксиса.

Значение сокращения grid — вариант 1
Это значение, которое подошло бы для свойства grid-template. Например, вот
сетка с двумя строками по 100 px и тремя столбцами по 200 px:
grid: 100px 100px / 200px 200px 200px;

Как и в предыдущих примерах grid-template, вы также можете использовать
grid-template-areas, если захотите.

Значение сокращения grid — вариант 2
В этом значении заключены набор длин явных строк сетки, слеш и указание способа обработки неявных столбцов. Это может быть значение auto-flow, позволяю­
щее установить grid-auto-rows, с возможностью настройки grid-auto-flow путем
добавления ключевого слова dense. Или, в качестве альтернативы, значение ширины столбцов, если вы хотите установить grid-template-columns.
Да, вычислить это сложно. Взгляните на несколько примеров.
Для сетки с двумя явными строками по 100 px и любым количеством явных
столбцов шириной 75 px код будет выглядеть следующим образом:
grid: 100px 100px / repeat(auto-fill, 75px);

Если в такой сетке окажется слишком много элементов, они будут перетекать
в неявные строки с размером по умолчанию auto.
В браузере это сокращение будет вычислять следующее:
grid-template-rows: 100px 100px;
grid-template-columns: repeat(auto-fill, 75px);
grid-template-areas: none;
grid-auto-flow: initial;
grid-auto-rows: initial;
grid-auto-columns: initial;

Сокращения в синтаксисе

147

Попробуем по-другому. Представим сетку, содержащую только одну строку
высотой 100 px, но с любым количеством столбцов, потенциально выходящих за
пределы контейнера:
grid: 100px / auto-flow;

Это сокращение сводится к следующему:
grid-template-rows: 100px;
grid-template-columns: initial;
grid-template-areas: initial;
grid-auto-flow: column;
grid-auto-rows: initial;
grid-auto-columns: initial;

Обратите внимание, что, используя сокращение grid, вы сбрасываете все значения, с которыми оно работает, обратно в их исходное состояние. Чтобы убедиться в этом, посмотрите на вычисленные значения стилей в инструментах разработчика браузера.

Значение сокращения grid — вариант 3
Последний синтаксис, который можно сократить с помощью grid, противоположен второму варианту. На этот раз мы устанавливаем свойство grid-auto-flow
для обработки неявных строк (здесь необязательно использовать ключевое слово
dense) с необязательным значением grid-auto-rows для размера строк. Затем, после слеша, мы устанавливаем grid-template-columns.
Используя это значение, мы заставляем элементы располагаться в строках,
когда это необходимо, а не в столбцах, как в предыдущем варианте. Вот несколько
примеров.
Это сетка, которая создает столько строк по 100 px, сколько нужно, и 5 столбцов
занимают по 1 fr каждый:
grid: auto-flow 100px / repeat(5, 1fr);

Этот код вычисляет следующее:
grid-template-rows: initial;
grid-template-columns: repeat(5, 1fr);
grid-template-areas: initial;
grid-auto-flow: row;
grid-auto-rows: 100px;
grid-auto-columns: initial;

А это сетка, которая создает один столбец с таким количеством строк по 100 px,
которое необходимо для содержимого:
grid: auto-flow 100px / auto;

148

Глава 5. CSS Grid

Этот код вычисляет следующее:
grid-template-rows: initial;
grid-template-columns: auto;
grid-template-areas: initial;
grid-auto-flow: row;
grid-auto-rows: 100px;
grid-auto-columns: initial;

Как видите, сокращение grid очень мощное, но не интуитивное. Некоторые
любят сокращения. Некоторых они сводят с ума. Нет правильного или неправильного подхода — выбирайте любой.

Итоги
Если вы новичок в веб-разработке, то в каком-то смысле имеете преимущество
в изучении CSS Grid, свежий взгляд, если хотите. Многоопытным верстальщикам,
которые использовали другие методы, сложно отказываться от привычных подходов к CSS.
Прочитав эту главу, вы получили некоторое представление о возможностях
Grid и о том, как использовать эту систему на практике.
Если вы успешно справились с упражнениями, поздравьте себя. Чтобы начать
использовать Grid, нужно учесть множество нюансов. Если у вас получилось понять концепции Grid с первого раза, это превосходно.
Повторюсь, система Grid поначалу кажется сложной. В ней много возможностей,
но есть и немало новых терминов и понятий. Будьте готовы к тому, что придется
хорошенько повторить весь материал этой главы при первом использовании Grid.
Но обещаю, что эти знания вам пригодятся.
Предыдущие две главы охватывают широкие темы: как создавать разметку
с помощью самых современных методов и как работать с отзывчивыми изображениями. Следующая глава будет более подробной. CSS делает возможными множество трюков и приемов, это настоящая кладовая полезных инструментов. Переверните страницу, и перейдем к главе 6.

6

CSS-селекторы,
типографика, цветовые
режимы и многое другое

За последние несколько лет в CSS-технологию введено множество новых функций. Одни позволяют анимировать и преобразовывать элементы, другие дают возможность создавать фоновые изображения, эффекты градиентов, масок и фильтров, а третьи оживляют SVG-элементы.
Все эти возможности будут рассмотрены в следующих главах. Считаю, что
в первую очередь лучше изучить последние нововведения в CSS.
Абсолютным знанием всех нюансов, возможностей и синтаксиса CSS не обладает никто. Я работаю с CSS уже 20 лет и каждую неделю открываю для себя
что-то новое (или хорошо забытое старое). И не думаю, что стоит гнаться за усвоением каждого возможного сочетания свойств и значений CSS. Разумнее выработать общее представление о возможностях, помогающих решить основные проблемы.
В этой главе я сосредоточусь на технологиях, единицах измерения и селекторах,
которые, на мой взгляд, наиболее полезны при создании отзывчивых вебконструкций. Надеюсь, после изучения главы вы получите необходимый объем
знаний для решения большинства проблем при разработке отзывчивого вебдизайна.
Темы этой главы сгруппированы следующим образом:
Селекторы, единицы измерения и возможности:
y псевдоэлементы ::before и ::after;
y селекторы атрибутов и сопоставление подстрок;
y структурные псевдоклассы, в том числе :last-child, :nth-child, :empty
и :not;
y селекторы-комбинаторы: дочерние, следующего соседнего элемента, всех
соседних элементов;
y единицы длины, связанные с окном просмотра: vh, vw, vmax и vmin;
y функция calc();

150

Глава 6. CSS-селекторы, типографика, цветовые режимы и многое другое

пользовательские свойства CSS и переменные среды;
использование @supports для работы с CSS.
Веб-типографика:
y правило @font-face;
y форматы шрифта, в том числе .woff и .woff2;
y управление загрузкой шрифтов с помощью свойства font-display;
y различные шрифты и их особенности.
Цветовые режимы:
y RGB;
y HSL;
y RGBA и HSLA.
y
y

Как видите, предстоит многое изучить. Приступим.

Селекторы, единицы измерения
и возможности
Хотя они и могут казаться скучными, селекторы, единицы измерения и возможности — это основа CSS. Освоив их, вы научитесь справляться с проблемами с помощью CSS. Так что не пропускайте эту главу!

Анатомия правила CSS
Перед исследованием последних дополнений CSS и во избежание путаницы установим терминологию, которой будем придерживаться для описания правила CSS.
Рассмотрим следующий пример:
.round {
/* селектор */
border-radius: 10px; /* объявление */
}

Это правило состоит из селектора (.round), после которого следует объявление (border-radius: 10px ). В свою очередь, объявление определяется свойством (border-radius) и значением (10px). Согласны? Отлично, теперь ускоримся.

На момент написания этих строк рабочий проект Selectors Level 4 подробно описывает множество новых селекторов, таких как is(), has() и nth-col. К сожалению, ни в одном из распространенных браузеров пока нет их реализации.
Чтобы узнать, что их ждет в будущем, перейдите по ссылке на страницу проекта:
https://www.w3.org/TR/selectors-4/.

Селекторы, единицы измерения и возможности

151

Псевдоэлементы и псевдоклассы
Когда мы говорим о словах с приставкой «псевдо-», может возникать путаница.
В CSS есть псевдоклассы и псевдоэлементы. Поэтому определимся с отличиями.
«Псевдо» в данном контексте означает «похож на что-то, но этим не является».
Итак, псевдоэлемент похож на элемент, но не является им, а псевдокласс выбирает что-то, что нельзя выбрать селектором.
Ух ты, я говорю, как Загадочник из DC. Код нам в помощь.
Вот как создается псевдоэлемент в CSS:
.thing::before {
content: "Spooky";
}

Эта инструкция вставляет псевдоэлемент ::before в элемент .thing с содержимым "Spooky". Псевдоэлемент ::before ведет себя как первый дочерний элемент,
а ::after — как последний.
На рис. 6.1 представлен элемент из инструментов разработчика Firefox, который
содержит текст с псевдоэлементами ::before и ::after, добавленными в CSS:

Рис. 6.1. Инструменты разработчика Firefox: расположение псевдоэлементов в DOM

Помните, что если вы не укажете значение для содержимого, то на странице
ничего не будет отображаться. Заметили двойное двоеточие перед before? Официально именно так следует кодировать псевдоэлементы, поскольку это помогает
отличить их от псевдоклассов с одним двоеточием. Однако одинарное двоеточие
работало в первых реализациях ::before и ::after, и вы все еще можете обозначать
их таким образом.
Но нельзя сделать то же самое с псевдоклассами, поскольку они всегда обозначаются только одним двоеточием, например :hover, :active и :focus.
Для удобства представьте, что псевдокласс работает только с частью выбранного селектором элемента.
Надеюсь, теперь разница между псевдоклассами и псевдоэлементами вам понятна.
Обозначив данное различие, рассмотрим некоторые из мощных селекторов,
доступных сегодня в CSS.

152

Глава 6. CSS-селекторы, типографика, цветовые режимы и многое другое

Селекторы CSS Level 3 и как их использовать
CSS содержит эффективные средства выбора элементов внутри страницы. Может,
это прозвучит слишком оптимистично, но поверьте, они смогут облегчить вашу
жизнь и заставят полюбить CSS! Готов ответить за это смелое утверждение.

Селекторы атрибутов
Возможно, вы уже пользовались селекторами атрибутов CSS для создания правил.
Рассмотрим такой код:


И код CSS:
img[alt] {
border: 3px dashed #e15f5f;
}

Этот селектор выбирает элемент img в предыдущем HTML-коде и любые другие элементы на странице при условии, что они имеют атрибут alt.

Чтобы сделать этот код более полезным, можно объединить его с селектором
отрицания :not (рассмотрим его подробно позже в этой главе), чтобы добавить
красную рамку вокруг изображений, у которых нет атрибута alt или у этого
атрибута нет значения:
img:not([alt]),
img[alt=""] {
border: 3px solid red;
}

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

Или предположим, что нам нужно выбрать все элементы с атрибутом datasausage:
[data-sausage] {
/* стили */

}

Для указания атрибута понадобятся всего лишь квадратные скобки.

Атрибут типа data-* введен в HTML5 для предоставления места пользовательским данным, которые не могут быть должным образом сохранены с помощью
других механизмов. Спецификацию можно найти по адресу: http://www.w3.org/

TR/2010/WDhtml5-20101019/elements.html#embedding-custom-nonvisible-data-with-thedata-attributes.

Селекторы, единицы измерения и возможности

153

Можно сузить область выбора, указав значение атрибута. Рассмотрим такое
правило:
img[alt="Sausages cooking"] {
/* стили */
}

Оно нацелено только на те изображения, которые имеют атрибут alt со значением sausages cooking, например:


До сих пор мы довольствовались тем, что предоставила спецификация CSS2.
Интересно, а что же нового появилось с выходом спецификации CSS3?

Селекторы, соответствующие подстрокам значений атрибутов
CSS позволяет выбирать элементы на основе подстрок значений их атрибутов.
Хотя эта формулировка воспринимается с трудом, ничего сложного здесь нет.
Вариантов соответствия подстроке значения атрибута всего три:
y подстрока находится в начале значения;
y значение содержит экземпляр подстроки;
y значение заканчивается подстрокой.
Посмотрим, как они выглядят.
Селектор значения атрибута по подстроке, находящейся в его начале
Рассмотрим такую разметку:
Empty the bins
Play football

Представим, что данная разметка представляет два пункта в приложении «Список дел». Даже несмотря на то, что они имеют разные значения атрибута data-type,
оба указанных изображения можно выбрать по подстроке, находящейся в начале
значения их атрибута:
[data-type^="todo"] {
/* стили */

}

Ключевым здесь выступает символ ^ (который называется «карет», также его
часто называют колпаком), означающий «начинается с». Поскольку оба атрибута
data-type начинаются с todo, селектор выбирает оба эти атрибута.
Селектор значения атрибута по имеющемуся в нем экземпляру подстроки
Селектор значения атрибута по имеющемуся в нем экземпляру подстроки имеет
следующий синтаксис:

}

[attribute*="value"] {
/* стили */

154

Глава 6. CSS-селекторы, типографика, цветовые режимы и многое другое

Если нужно, этот селектор, как и все селекторы атрибутов, может использоваться в сочетании с селектором типа (который ссылается на фактически используемый элемент HTML), но я поступлю так только в случае крайней необходимости (если понадобится сменить тип используемого элемента).
Обратимся к примеру и рассмотрим следующую разметку:
Will I get selected?

Этот элемент можно выбрать следующим образом:
[data-ingredients*="cream"] {
color: red;
}

Ключевым здесь выступает символ *, который в данном контексте означает
«содержит».
Селектор «начинается с» с этой разметкой работать не будет, поскольку строка,
являющаяся значением атрибута, не начинается с "cream". Но в ней содержится
"cream", следовательно, селектор значения атрибута, работающий по принципу
«содержит», данный элемент обязательно найдет.
Селектор значения атрибута по подстроке, находящейся в его конце
Селектор значения атрибута по подстроке, находящейся в его конце, имеет синтаксис:
[attribute$="value"] {
/* стили */

}

Разобраться в нем поможет пример. Рассмотрим код:
Will I get selected?
Will I get selected?
Will I get selected?

Допустим, нужно выбрать тот элемент, значение атрибута data-ingredients
которого заканчивается словом jam (то есть первый элемент из трех).
Мы не можем воспользоваться селектором подстроки значения атрибута, работающим по принципу «содержит» (он выберет все три варианта) или «начинается с» (он выберет только последний элемент). Но мы можем воспользоваться
селектором подстроки значения атрибута, работающим по принципу «заканчивается подстрокой»:
[data-ingredients$="jam"] {
color: red;
}

Ключевым символом здесь является знак доллара ($), означающий «заканчивается подстрокой».

Селекторы, единицы измерения и возможности

155

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

Связывание селекторов атрибутов
Вы получите еще больше возможностей для выбора элементов, группируя селекторы атрибутов.
Рассмотрим такую разметку:

Running


Swimming


Cycling


Swimming


Чтобы выбрать, например, только «indoor swimming», мы не можем просто использовать селектор data-location="indoor", поскольку тогда мы выберем и первый
элемент тоже. Нельзя также использовать запись data-activity-name="swimming",
поскольку будут выбраны первый и третий элементы. Но можно сделать следующее:
[data-activity-name="swimming"][data-location="indoor"] {
/* стили */
}

Так будут выбраны элементы с названием "swimming" в качестве занятия при
условии, что в них указано "indoor" в качестве местоположения.

156

Глава 6. CSS-селекторы, типографика, цветовые режимы и многое другое

Селекторы атрибутов позволяют выбрать элементы, чьи идентификаторы и имена
классов начинаются с цифр. До появления HTML5 такие идентификаторы и имена
классов были недопустимы. Сейчас в идентификаторе не должно быть пробелов,
и для страницы он должен быть уникальным. Дополнительные сведения можно найти по адресу: http://www.w3.org/html/wg/drafts/html/master/dom.html#the-idattribute.

Спецификация CSS по-прежнему не позволяет использовать селекторы идентификаторов и имен классов, начинающиеся с цифр (http://www.w3.org/TR/CSS21/
syndata.html#characters).
К счастью, этот запрет легко обойти с помощью селектора атрибутов, например
[id="10"].
Отлично, думаю, ваши навыки по выбору атрибутов заметно улучшились.
Теперь перейдем к выбору элементов на основе их расположения в документе.

Структурные псевдоклассы
CSS предоставляет эффективный механизм выбора элементов на основе их местоположения в DOM. Рассмотрим обработку конструкции для адаптации панели
навигации для более широкого окна просмотра, при которой в левой стороне экрана должны разместиться все ссылки, кроме последней. Согласно сложившейся
практике, эта задача решается добавлением к последней ссылке имени класса и последующим выбором этой ссылки:

Home
About
Films
Forum
Contact Us


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

Селектор :last-child
В CSS 2.1 уже был селектор, применяемый для выбора первого элемента списка:
div:first-child {
/* стили */
}

А в CSS3 добавился селектор, который также может соответствовать последнему элементу:

Селекторы, единицы измерения и возможности

157

div:last-child {
/* стили */
}

Посмотрим, как с помощью этого селектора решается предыдущая задача:
.nav-Wrapper {
display: flex;
}
.nav-Link:last-child {
margin-left: auto;
}

Есть также селекторы для выбора только одного элемента (:only-child) и только одного элемента заданного типа (:only-of-type).

Селекторы nth-child
Селекторы nth-child решают более трудные задачи, например позволяют выбрать
любую ссылку (или ссылки) внутри списка.
Прежде всего попробуем выбрать каждый второй элемент списка:
.nav-Link:nth-child(odd) {
/* стили */
}

А так можно выбрать каждый первый элемент:
.nav-Link:nth-child(even) {
/* стили */
}

Порядок работы nth-правил
Непосвященные могут настороженно отнестись к селекторам на nth-основе.
Но как только вы усвоите их логику и синтаксис, то будете удивлены их мощи.
Взглянем на их возможности.
Эти правила на nth-основе обеспечивают невероятную гибкость:
y nth-child(n)
y nth-last-child(n)
y nth-of-type(n)
y nth-last-of-type(n)
Мы уже видели, как в выражениях на nth-основе можно использовать значения (odd) или (even), а вот параметр (n) может использоваться следующими
двумя способами:
y в виде целого числа, например :nth-child(2), что приведет к выбору второго элемента;
y в виде числового выражения, например :nth-child(3n+1), благодаря чему
выбор начнется с первого элемента и продолжится выбором каждого третьего элемента.

158

Глава 6. CSS-селекторы, типографика, цветовые режимы и многое другое

Версия селектора с числовым выражением может немного озадачить неискушенных. Итак, разберемся.
Разбираемся с математикой
Рассмотрим десять линейных блоков span на странице (пример из каталога
example_06-05):











Изначально им будет задан следующий стиль:
span {
height: 2rem;
width: 2rem;
background-color: blue;
display: inline-block;
}

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

Рис. 6.2. Проверим свои навыки выбора селекторов nth-child на десяти одинаковых
элементах

А теперь посмотрим, как можно выбрать различные элементы с помощью nthправил.
Разбор выражения в скобках лучше начинать с правого края. К примеру, в выражении (2n+3) крайнее правое число 3 указывает на третий элемент слева, и начиная с его позиции, будет выбран каждый второй элемент. Поэтому добавление
правила:
span:nth-child(2n+3) {
background-color: #f90;
border-radius: 50%;
}

даст на экране браузера следующий результат:

Селекторы, единицы измерения и возможности

159

Рис. 6.3. Все элементы, попадающие под nth-отбор,
становятся кругами оранжевого цвета

Как видите, nth-селектор нацелен на третий элемент списка, а также на каждый
последующий второй элемент после него. Если бы в списке было 100 элементов,
то продолжался бы выбор каждого второго из них.
А как выбрать каждый следующий элемент, начиная со второго? Можно воспользоваться кодом :nth-child(1n+2), но первая цифра не нужна, поскольку, если
не утверждается иное, переменная n равна единице. Поэтому напишем :nthchild(n+2). По аналогии, если нужно выбрать каждый третий элемент, вместо
записи :nth-child(3n+3) можно указать :nth-child(3n), поскольку «каждый
третий элемент» в любом случае начинается с третьего элемента и нет необходимости указывать на него.
В выражении могут применяться также отрицательные числа. Например, в выражении :nth-child(3n-2) выбор начинается с -2, после чего выбирается каждый
третий элемент.
Можно также изменить направление. По умолчанию, как только найдена первая часть заданного выбора, последующие части ищутся вниз по элементам в DOMдереве (и поэтому выбор в нашем примере идет слева направо). Но направление
можно изменить на обратное с помощью минуса, например:
span:nth-child(-2n+3) {
background-color: #f90;
border-radius: 50%;
}

В этом примере тоже ищется третий элемент, но затем в обратном направлении
ведется поиск каждого второго элемента (вверх по DOM-дереву, то есть в нашем
примере — справа налево).

Рис. 6.4. С помощью знака минус мы можем производить
выбор в обратном направлении

Надеюсь, вы усвоили логику выражений на nth-основе?
Разница между nth-child и nth-last-child заключается в том, что вариант
nth-last-child работает «в противоход» распространению дерева документа. Например, :nth-last-child(-n+3) выбирает третий элемент с конца, а затем выбирает все элементы после него. Результат применения данного правила выглядит на
экране браузера так:

160

Глава 6. CSS-селекторы, типографика, цветовые режимы и многое другое

Рис. 6.5. С помощью селектора nth-last-child можно вести
выбор с конца в обратном направлении

И в заключение рассмотрим селекторы :nth-of-type и :nth-last-of-type.
В предыду­щих примерах вычисление шло в отношении всех дочерних элементов
независимо от их типа (запомните, что селектор nth-child нацеливается на все дочерние элементы одного и того же DOM-уровня независимо от их классов), а вот
селекторы :nth-of-type и :nth-last-of-type позволяют указывать тип выбираемых
элементов. Рассмотрим следующую разметку (файл в каталоге example_06-06), представляющую собой смешение элементов div и span, имеющих один и тот же класс:


Если использовать следующий селектор:
.span-class:nth-of-type(-2n+3) {
background-color: #f90;
border-radius: 50%;
}

то независимо от наличия у всех элементов одного и того же класса span-class
будут выбраны только span-элементы (поскольку они относятся к выбираемому
типу).

Рис. 6.6. Селекторы nth-of-type работают для каждого элемента установленного типа

CSS считает не так, как JavaScript и jQuery. Если вы привыкли пользоваться Java­
Script и jQuery, то в курсе, что подсчет (индексация) в них начинается с нуля. Например, при выборе элемента в JavaScript или jQuery целочисленное значение
1 будет фактически указывать на второй по счету элемент. Но в CSS счет начинается с 1, поэтому значение 1 соответствует первому элементу.

Селекторы, единицы измерения и возможности

161

Выбор на nth-основе в отзывчивых веб-конструкциях
Чтобы завершить этот небольшой раздел, хочу показать реальную проблему отзывчивого веб-дизайна и применение nth для ее решения. Представьте, что мы
создаем страницу, на которой должен быть список самых кассовых фильмов
определенного года. Система управления содержимым может просто поместить
все элементы в список, но мы хотим, чтобы они размещались в сетке. Для малых
окон просмотра ширина сетки должна составить два элемента, для средних — три
элемента, а для более крупных — четыре элемента. Причем независимо от размера окна просмотра мы не хотим, чтобы у нижних строк элементов была нижняя
граница. Файл с соответствующим кодом можно найти в каталоге example_06-09.
Результат при ширине, составляющей четыре элемента, можно увидеть на
рис. 6.7.

Рис. 6.7. Нужно удалить нижнюю границу в нижней строке независимо от того,
как много элементов отображено на странице

Видите эту ненужную границу под последними двумя элементами? Именно ее
нужно удалить. Но нужно получить надежное решение, чтобы граница удалялась
и при другом составе элементов последней строки (мы пойдем дальше других
сайтов и покажем топ-11 самых кассовых фильмов!).
Теперь, поскольку при разных окнах просмотра в каждой строке содержится
разное количество элементов, нам нужны соответствующие выборы на nth-основе.
И для этого мы можем использовать медиазапросы. Для краткости я не буду показывать вам выбор для каждого медиазапроса, а покажу выбор, соответствующий

162

Глава 6. CSS-селекторы, типографика, цветовые режимы и многое другое

четырем элементам в строке, который показан на предыдущем скриншоте. Выбор
для различных окон просмотра выглядит так:
@media (min-width: 55rem) {
.Item {
width: 25%;
}
/* Получить каждый четвертый элемент, а из них взять только тот, который находится в составе последних четырех элементов */
.Item:nth-child(4n+1):nth-last-child(-n+4),
/* Теперь получить каждый элемент, следующий за той же самой коллекцией */
.Item:nth-child(4n+1):nth-last-child(-n+4) ~ .Item {
border-bottom: 0;
}
}

Как видите, здесь выстроена цепочка из селекторов псевдоклассов на nth-основе.
Схожим образом мы связывали селекторы атрибутов ранее в этой главе. Важно
понимать, что предыдущие селекторы не фильтруют выбор для следующих, а элемент должен соответствовать каждому из выборов.
Итак, в следующей строке:
.Item:nth-child(4n+1):nth-last-child(-n+4),

Элемент .Item должен быть первым из четырех и одним из четырех последних.

Рис. 6.8. Получено достижение — использованы селекторы nth-child на уровне
волшебника!

Селекторы, единицы измерения и возможности

163

Отлично! Благодаря выбору на nth-основе у нас получился стойкий набор
правил для удаления самой нижней границы независимо от размера окна просмотра или количества показываемых на экране элементов.
Теперь перейдем к одному элегантному селектору, выбирающему следующий
родственный элемент. Мы не рассматривали такого рода селекторы ранее, поэтому рассмотрим их сейчас.

Комбинаторы: дочерние, следующего соседнего элемента, всех соседних
элементов
Думаю, сейчас вы понимаете базовый паттерн селектора, в котором один класс
следует за другим и который выбирает соответствующих потомков. Например,
селектор .parent .descendant {} выберет любой элемент, являющийся потомком
элемента .parent с классом .descendant, независимо от уровня его расположения.
Дочерний комбинатор
Этот комбинатор выбирает только прямых потомков. Рассмотрим следующую
разметку:






Мы можем выбрать только прямого потомка родительского элемента, например:
.parent > .descendant {
/* стили */
}

Обратите внимание на правую угловую скобку между двумя именами классов
в селекторе — это символ дочернего комбинатора.
Комбинатор следующего соседнего элемента
Рассмотрим другой пример:
six

Чтобы выбрать элемент .one и его следующего родственника, используем такую
разметку:
.one + .item {
border: 3px dashed #f90;
}

Знак + означает «следующий соседний элемент».

164

Глава 6. CSS-селекторы, типографика, цветовые режимы и многое другое

Комбинатор всех соседних элементов
Чтобы в разметке из предыдущего примера выбрать все элементы после третьего,
можно сделать следующее:
.item:nth-child(3) ~ .item {
border: 3px dashed #f90;
}

Символ ~ называется «тильда» и означает «все соседние элементы».

Селектор отрицания (:not)
Еще одним полезным селектором является селектор псевдокласса отрицания. Он
пригодится для выбора всего, что не попадает под определенный выбор. Рассмотрим следующий код:


И вот эти стили:
div {
display: inline-block;
height: 2rem;
width: 2rem;
background-color: blue;
}
.a-div:not(.not-me) {
background-color: orange;
border-radius: 50%;
}

Последнее правило предписывает каждому элементу, имеющему класс .a-div,
быть оранжевого цвета и иметь скругление, за исключением div-контейнера, у которого тоже есть класс .not-me . Файл с этим кодом находится в каталоге
example_06-07 (напоминаю, что все примеры к книге доступны на сайте rwd.
education).

Рис. 6.9. Селектор отрицания позволяет исключать
элементы из выбора

Селекторы, единицы измерения и возможности

165

До сих пор мы рассматривали в основном то, что называется структурными псевдоклассами (вся информация о них доступна по адресу: http://www.w3.org/TR/
selectors/#structural-pseudos). Но в CSS есть гораздо больше селекторов. При работе над веб-приложением просмотрите полный перечень элементов пользовательского интерфейса, относящихся к псевдоклассам (http://www.w3.org/TR/
selectors/#UIstates), поскольку они могут, к примеру, нацеливать правила на основе того, выбраны некоторые элементы или нет.

Селектор пустого элемента (:empty)
Мне приходилось сталкиваться с ситуациями, когда элемент, включающий внутренние дополнительные пробелы, получал динамически вставляемое в него содержимое. Проблема в том, что, даже когда он не получает содержимое, пробелы
все равно видно. Рассмотрим код HTML из файла в каталоге example_06-08:


А также CSS-код:
.thing {
padding: 1rem;
background-color: violet;
}

При отсутствии содержимого в div-контейнере все равно виден его фоновый
цвет, задаваемый свойством background-color. К счастью, его нетрудно спрятать:
.thing:empty {
display: none;
}

Но все же селектор :empty нужно применять осторожно. Например, можно
подумать, что данный контейнер пуст:


Но это не так! Обратите внимание на пробел в контейнере. Пробельный символ
не означает пустоту!
И, чтобы не запутаться, помните, что комментарий не влияет на наличие или
отсутствие пробельного символа в элементе. Например, этот элемент-контейнер
все равно будет считаться пустым:


Сменим направление. Мы рассматривали тему выбора элементов в контексте
отзывчивости. А как насчет задания их размеров?

166

Глава 6. CSS-селекторы, типографика, цветовые режимы и многое другое

Помните о необходимости проверять поддержку браузером. Изучая CSS, посетите
сайт http://caniuse.com, чтобы узнать, каков текущий уровень поддержки браузером
той или иной функции CSS или HTML5. Помимо отображения поддержки версией
браузера (с возможностью поиска по функциям) он также предоставляет самый последний набор глобальной статистики использования с сайта http://gs.statcounter.com.

Отзывчивые меры длины, выражаемые в процентных
отношениях, применительно к окнам
просмотра (vmax, vmin, vh, vw)
В разделе CSS Values and Units Module Level 3 (http://www.w3.org/TR/css3values/#viewport-relative-lengths) введены очень полезные единицы измерения, выражаемые относительно размеров окна просмотра:
y vw — равна 1 % ширины окна просмотра;
y vh — равна 1 % высоты окна просмотра;
y vmin — для минимального размера окна просмотра, равна самому малому
значению — либо vw, либо vh;
y vmax — для максимального размера окна просмотра, равна самому большому значению — либо vw, либо vh.
Хотите окно, высота которого задается как 90 % от высоты окна браузера? Проще некуда:
.modal {
height: 90vh;
}

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

Наверное, более полезно применять эти единицы измерения в сочетании
с шрифтовыми настройками. К примеру, создать текст, масштабирующийся в зависимости от размеров окна просмотра.
Например:
.Hero-text {
font-size: 25vw;
}

Такой размер текста будет изменяться в указанном процентном отношении
к ширине окна просмотра.

Селекторы, единицы измерения и возможности

167

В CSS появилось новое математическое выражение clamp(), которое позволяет указывать минимальный, максимальный и переменный размеры. Например,
если выбрать заголовок: .headline {font-size: clamp (20px, 40vw,
80px)}, его размер может быть разным в зависимости от области просмотра,
он никогда не будет меньше 20 px или больше 80 px. Можете изучить спецификацию для clamp() по адресу: https://www.w3.org/TR/css-values-4/#calc-notation.

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

Функция calc()
Раньше при написании разметки приходилось думать о чем-нибудь вроде:
«Нужно от половины ширины родительского элемента отнять точно 10 px».
Возможность выполнять подобные вычисления важна при разработке отзывчивого веб-дизайна, поскольку размер экрана, на котором будут просматриваться
веб-страницы, заранее не известен. К счастью, в CSS появился способ решения
этой задачи — функция calc(). Рассмотрим пример CSS-кода:
.thing {
width: calc(50% - 10px);
}

Только будьте осторожны, добавляя пробелы вокруг символов. Если бы я написал, например, calc (50% -10px), пропустив пробелы вокруг знака минус, объявление не сработало бы.
В этой функции поддерживаются сложение, вычитание, деление и умножение,
что позволяет решить множество проблем, которые ранее решались только с применением JavaScript.
Вы также можете применить пользовательские свойства CSS в этой функции.
Если вы ничего не знаете о пользовательских свойствах CSS, то вы счастливчик,
поскольку о них мы и собираемся поговорить.

Пользовательские свойства CSS
Они больше известны как переменные, хотя это не является их обязательным
и единственным назначением.

Их полную спецификацию можно найти по адресу: http://dev.w3.org/csswg/cssvariables/.

168

Глава 6. CSS-селекторы, типографика, цветовые режимы и многое другое

Пользовательские свойства CSS позволяют хранить в таблицах стилей информацию, которая затем может использоваться в таблице стилей или, возможно,
оказывать влияние на сценарий JavaScript.
Начнем с простого примера — хранения имени семейства шрифтов с после­
дующей ссылкой на него:
:root {
--MainFont: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

Здесь для хранения пользовательского свойства в корне документа используется псевдокласс :root (хотя эти свойства можно хранить в любом правиле).
В структуре документа псевдокласс :root всегда ссылается на самый верхний
родительский элемент: в HTML-документе это HTML-элемент, а в SVGдокументе (глава 8) это будет другой элемент.

Пользовательское свойство всегда начинается с двух дефисов, за которыми
следует выбранное пользователем имя, а его окончание обозначается, как и любое
другое свойство в CSS, точкой с запятой.
Сослаться на значение этого свойства можно с помощью записи var():
.Title {
font-family: var(--MainFont);
}

Очевидно, так вы можете хранить любое количество пользовательских свойств.
Основным преимуществом такого хранения является возможность изменения
значения внутри переменной, и каждое использующее эту переменную правило
получает новое значение без его непосредственного изменения.
Позвольте показать вам очень простой пример применения пользовательских
свойств CSS с JavaScript. Вы можете найти его в каталоге example_06-11. Мы сделаем страницу со стихотворением «Если…» Редьярда Киплинга. И внизу разместим
кнопку переключения светлого/темного режима. Все, что будет делать кнопка, —
это переключать значение двух пользовательских свойств CSS: --background
и --foreground.
Вот CSS-код:
body {
background-color: var(--background);
color: var(--foreground);
}

Для любопытных приведу фрагмент кода JavaScript, который мы используем.
Если переменная переднего плана имеет цвет #eee (почти белая), то необходимо
придать ей цвет #333 (темно-серый); в противном случае придать ей цвет #eee.

Селекторы, единицы измерения и возможности

169

А если фоновая переменная имеет цвет #333, необходимо придать ей цвет #eee
и в противном случае придать ей цвет #333:
var root = document.documentElement;
var btn = document.getElementById("colorToggle");
btn.addEventListener("click", e => {
root.style.setProperty("--background", getComputedStyle(root).
getPropertyValue('--background') === "#333" ? "#eee" : "#333");
root.style.setProperty("--foreground", getComputedStyle(root).
getPropertyValue('--foreground') === "#eee" ? "#333" : "#eee");
})

Вот скриншот, показывающий оба состояния:

Рис. 6.10. Пример обоих состояний: цвета легко меняются с помощью
пользовательских свойств

Код примера можно найти в каталоге example_06-12.

170

Глава 6. CSS-селекторы, типографика, цветовые режимы и многое другое

Пользовательские свойства ведут себя так же, как и другие свойства, с точки
зрения специфичности. Например, мы устанавливаем пользовательские свойства
на корневом уровне, но если они повторно объявлены ближе к рассматриваемому
элементу, более конкретное значение переопределит первое.
Рассмотрим этот код CSS:
:root {
--backgroundColor: red;
}
header {
--backgroundColor: goldenrod;
}

Заголовок и любые элементы в нем,использующие настраиваемое свойство
--backgroundColor, будут иметь цвет фона «золотарник», тогда как другие элементы будут иметь красный фон.

Установка резервного значения
Бывают ситуации, когда надо защититься от недоступности пользовательского
свойства. Вы можете сделать это, указав резервное значение. Синтаксис прост:
укажите резервное значение после имени пользовательского свойства и запятой.
Например, я хочу применить пользовательское свойство --backgroundColor, но по
умолчанию используется темно-серый цвет, если эта переменная недоступна.
Я мог бы написать:
.my-Item {
background-color: var(--backgroundColor, #555);
}

На всякий случай имеет смысл выработать привычку указывать резервные
значения при каждом пользовательском свойстве.

Переменные среды и функция env()
В дополнение к пользовательским свойствам, которые мы можем создать для себя,
есть свойства, которые могут быть считаны из среды, в которой мы работаем. Они
называются переменными среды. Единственный известный мне убедительный
пример — это свойства safe-area-inset, применимые к смартфонам с «челками».
«Безопасные зоны», ставшие известными благодаря iPhone X, относятся к разделам в верхней и нижней частях экрана, где области пользовательского интерфейса или физических кнопок сталкиваются с областью просмотра.
Переменные среды определяются с помощью функции env(). Значения передаются в эту функцию так же, как и в любую другую функцию CSS. Например,
чтобы добавить отступ к верхней части элемента, равный высоте «безопасной
области сверху», можно сделать следующее:
padding-top: env(safe-area-inset-top);

Селекторы, единицы измерения и возможности

171

Если в браузере доступно это значение и он понимает функцию env(), он применит это значение; в противном случае он перейдет к следующему объявлению.
Спецификацию переменных среды можно найти по адресу: https://drafts.csswg.
org/css-env-1/#env-function.

У экранов iPhone с выемками есть несколько дополнительных особенностей. Пошаговое руководство по работе с выемками iPhone описано в статье: https://
benfrain.com/css-environment-variables-iphonex/.

Я постоянно нахожу новые варианты использования пользовательских свойств
CSS. Тот факт, что они могут обновляться «на лету», означает, что они полезны
во всех сценариях. Их легко читать и записывать из сценария, поэтому по своим
возможностям они превосходят переменные, ставшие популярными благодаря
препроцессорам CSS, таким как Sass, Less и пр.
Пользовательские свойства наряду со многими функциями, которые мы рассмотрели и которые рассмотрим далее, не могут гарантировать работу в каждом
браузере. К счастью, CSS имеет элегантный синтаксис для инкапсуляции кода,
относящегося к последним функциям. Рассмотрим его.

Использование @supports для создания
альтернативных вариантов
При создании отзывчивых веб-конструкций часто приходится сталкиваться с ситуациями, когда те или иные функции или технологии не поддерживаются устройствами. В таких случаях вам, скорее всего, захочется создать в коде CSS соответствующее ветвление: если браузер поддерживает функцию, предоставить один
фрагмент кода, а если не поддерживает — другой.
В JavaScript такие ситуации разрешаются с помощью инструкций if — else
или switch. В CSS мы используем at-правило @supports.

Запросы возможностей
Разветвление кода в CSS проводится с помощью запросов возможностей (feature
queries), представляющих собой составную часть условных правил — CSS Conditional Rules Module Level 3 (http://www.w3.org/TR/css3-conditional/). Их поддержка
представлена в iOS и Safari 9, Firefox 22, Edge 12 и Chrome 28.
Синтаксис у запросов возможностей такой же, как и у медиазапросов. Рассмотрим следующий код:
@supports (flashing-sausages: lincolnshire) {
body {
sausage-sound: sizzling;

172

}

Глава 6. CSS-селекторы, типографика, цветовые режимы и многое другое

}

sausage-color: slighty-burnt;
background-color: brown;

Здесь стили будут применены только в том случае, если браузер поддерживает
свойство flashing-sausages в комбинации со значением lincolnshire. Абсолютно
уверен, что ни один браузер никогда не будет поддерживать пару свойство — значение flashing-sausages: lincolnshire, поэтому ни один из стилей внутри блока
@supports применяться не будет.
Рассмотрим более практичный пример. Зададим использование Flexbox в случае его поддержки браузером и предусмотрим резервную технологию разметки на
случай, если Flexbox не поддерживается:
@supports (display: grid) {
.Item {
display: inline-grid;
}
}
@supports not (display: grid) {
.Item {
display: inline-flex;
}
}

Здесь один блок кода определяется на случай поддержки возможности, а другой — на случай отсутствия такой поддержки. Эта модель подойдет в том случае,
если браузер поддерживает @supports (понимаю, что в этом довольно легко запутаться), но если он не обеспечивает такой поддержки, не будет применен ни
один из этих стилей.
Чтобы обеспечить работу на устройствах, не поддерживающих @supports, сначала напишите исходное объявление и уже после него — то объявление, которое
обусловлено запросом @supports. Так, первое правило будет отменяться в случае
поддержки @supports, а блок @supports будет игнорироваться, если его поддержка
отсутствует. Предыдущий пример требует следующих изменений:
.Item {
display: inline-flex;
}
@supports (display: grid) {
.Item {
display: inline-grid;
}
}

Веб-типографика

173

Комбинирование условий
Условия также можно комбинировать. Предположим, нужно применить некоторые правила только при одновременной поддержке Flexbox и pointer: coarse (медиафункция pointer рассматривалась в главе 3). Комбинированное условие может
иметь следующий вид:
@supports ((display: flex) and (pointer: coarse)) {
.Item {
display: inline-flex;
}
}

Здесь мы применили ключевое слово and, но вместо него можно использовать
or. Попробуем применить стили при условии поддержки двух предыдущих пар
свойство — значение или при поддержке 3D-преобразований:
@supports ((display: flex) and (pointer: coarse)) or
(transform: translate3d(0, 0, 0)) {
.Item {
display: inline-flex;
}
}

Обратите внимание на дополнительные круглые скобки, отделяющие условия
для display и pointer от условия для transform.
И это действительно все, что нужно для создания запросов возможностей. Как
и в случае с медиазапросами, напишите сначала стили «по умолчанию», а затем
усложнения внутри функционального запроса @supports. Помните, что вы можете комбинировать запросы, а также предлагать различные возможности применения прилагаемого кода.

Веб-типографика
Веб-типографика за последние несколько лет сильно развилась. Там, где раньше
нужно было учитывать множество различных форматов файлов, теперь применяется формат .woff и более новый формат .woff2. Кроме того, мы получили контроль
над особенностями шрифтов в CSS, а новые шрифты появляются каждый месяц.
Попробуем разобраться в современном состоянии веб-типографики.
Но сначала поговорим о системных шрифтах, поскольку они представляют
собой наиболее эффективный вариант веб-типографики, который можно выбрать.

Системные шрифты
Каждая операционная система имеет собственный набор предварительно установленных шрифтов. Но в целом не так много шрифтов работает на всех устройствах.

174

Глава 6. CSS-селекторы, типографика, цветовые режимы и многое другое

Разработчики уже привыкли писать «стеки шрифтов», которые позволяют составлять «списки предпочтительных шрифтов» для браузера. Например:
font-family: -apple-system, BlinkMacSystemFont, Roboto, Ubuntu, 'Segoe
UI', 'Helvetica Neue', Arial, sans-serif;

Браузер читает это объявление и движется слева направо, пока не найдет доступный шрифт, а затем выбирает его для отображения связанного текста.
В нашем примере системного стека шрифтов macOS получит шрифты San
Francisco или Helvetica (-apple-system указывает Safari выбрать San Francisco,
а BlinkMacSystemFont сообщает Chrome использовать Helvetica), Android получит
Roboto, популярный дистрибутив Ubuntu Linux получит Ubuntu, пользователи
Windows увидят Segoe UI, и у нас останется несколько попыток что-то сделать
с Helvetica Neue или Arial. Если ничего не поможет, мы дадим инструкцию браузеру использовать любой шрифт без засечек.

Имена некоторых шрифтов содержат пробелы, поэтому необходимо заключить
эти строки в одинарные или двойные кавычки. В предыдущем примере и Segoe
UI, и Helvetica Neue написаны таким образом.

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

CSS-правило @font-face
CSS-правило @font-face появилось еще в CSS2 (но из CSS 2.1 было удалено). Оно
даже пользовалось частичной поддержкой Internet Explorer 4 (кроме шуток!). Есть
ли оно в последней версии CSS?
Как выясняется, правило @font-face снова введено для модуля шрифтов CSS
Fonts Module (http://www.w3.org/TR/css3-fonts). Из-за правовой тяжбы, касающейся использования шрифтов в веб-приложениях, серьезные подвижки в признании
данного решения для шрифтового оформления начались только в последние
годы.
Как обычно, когда в веб-мире речь идет о привлечении ресурсов, поначалу
единого формата файлов шрифтов нет. Для Internet Explorer (и никакого другого
браузера) в качестве наиболее предпочтительных были выбраны шрифты формата Embedded OpenType с расширениями имен файлов .eot. Для других браузеров

Веб-типографика

175

предпочтение отдавалось более распространенным шрифтам формата TrueType
с расширениями имен файлов .ttf. В то же время существуют шрифты форматов
SVG-графики и Web Open Font Format (формат открытых веб-шрифтов) с расширениями имен файлов .woff или .woff2.
К счастью, с 2020 года вам действительно нужно рассматривать только форматы .woff или .woff2. По возможности используйте .woff2 — более эффективный
способ сжатия информации о шрифте.
Добавление пользовательского шрифта для любого браузера теперь не составляет особого труда. Посмотрим, как это делается!

Реализация веб-шрифтов с помощью @font-face
Есть много хороших онлайн-сервисов, позволяющих просматривать и получать
веб-шрифты. У каждого из них есть свой вариант необходимого синтаксиса для
размещения шрифтов на веб-сайтах. Однако, поскольку использование онлайнпоставщика шрифтов не всегда возможно или предпочтительно, мы рассмотрим
другой вариант.
Для этого упражнения я собираюсь загрузить шрифт Inter от Rasmus Andersson,
используемый сайтом https://rwd.education. Этот шрифт еще называют «переменным».
Прежде чем мы рассмотрим различные шрифты, определимся, с какими вебшрифтами вы будете работать чаще всего. Если вы возьмете шрифт Inter с https://
rsms.me/inter/, в вашем распоряжении будут как стандартные, так и вариативные
шрифты.

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

После загрузки шрифта Inter загляните в ZIP-файл и найдите там папки различных шрифтов. Для нашего примера я выберу Inter-Regular.woff2 и Inter-Regular.
woff.
Чтобы сделать веб-шрифт доступным в коде CSS, используем так называемое
эт-правило (по названию символа @ — «эт») @font-face, позволяющее ссылаться
на онлайн-шрифты, а также сообщим браузеру, где получить нужные файлы. Посмотрим на синтаксис:
@font-face {
font-family: 'InterRegular';

176

Глава 6. CSS-селекторы, типографика, цветовые режимы и многое другое

src: url('Inter-Regular.woff2') format('woff2'), url('Inter-Regular.woff')
format('woff');
font-weight: normal;
font-style: normal;
font-display: fallback;
}

Внутри фигурных скобок @font-face даем шрифту имя 'InterRegular'. Можно назвать его хоть 'FlyingBanana' — это не повлияет ни на что, но потом не ошибитесь, когда будете ссылаться на шрифт с выбранным именем. Например:
.hero-Image {
font-family: 'FlyingBanana', sans-serif;
}

Итак, знайте, что имеет смысл использовать название, похожее на имя шрифта,
который вы ожидаете увидеть!
В свойстве src две пары url() и format() разделены запятой. Отдавая предпочтение .woff2, мы указываем этот формат в первую очередь. Если браузер понимает .woff2, он загрузит соответствующий файл. В противном случае он загрузит файл
с расширением .woff.
Теперь, несмотря на то что этот блок кода вполне достоин копирования и вставки, обратите внимание на пути, по которым можно найти сохраненные шрифты.
Если бы мы поместили шрифты в папку с незатейливым именем fonts, находящую­
ся на том же уровне, что и папка css, мне нужно было бы изменить пути. И тогда
правило приобрело бы следующий вид:
@font-face {
font-family: 'InterRegular';
src: url('../fonts/Inter-Regular.woff2') format('woff2'), url('../fonts/
Inter-Regular.woff') format('woff');
font-weight: normal;
font-style: normal;
font-display: fallback;
}

Оптимизация загрузки шрифтов с помощью @font-face
Если ваш основной шрифт является веб-шрифтом, рекомендуется запросить его
файл заранее, загрузив его со ссылкой в разделе заголовка HTML-кода со значением атрибута rel — предварительная загрузка:


Веб-типографика

177

Прочитайте больше о данном методе оптимизации по адресу: https://developers.
google.com/web/fundamentals/ performance/resource-prioritization.

Такое добавление ссылки с атрибутом rel = "preload" запускает запрос вебшрифта на ранней стадии критического пути рендеринга, не дожидаясь создания
CSSOM. Хотя этот метод рекомендуется Google, другим браузерам он тоже вряд
ли причинит вред. Его стоит применять только для файла .woff2, поскольку браузеры, поддерживающие .woff2, поддерживают значение предварительной загрузки
в атрибуте rel.
Проведем дальнейшую оптимизацию веб-шрифтов, используя свойство fontdisplay.

Свойство font-display
Для браузеров, которые его поддерживают, можно использовать относительно
новое свойство CSS font-display (старые браузеры его игнорируют):
font-display: fallback;

Это свойство использовалось и в предыдущих примерах. Оно обеспечивает
определенный уровень контроля над отображением шрифтов.
Указанное нами значение fallback устанавливает чрезвычайно короткие периоды «блокировки» и «замены».
Чтобы понять, что в данном контексте означают термины «блокировка»
и «замена», рассмотрим в общих чертах, что делает браузер для отображения
шрифтов.
Представьте, что браузер загружает веб-страницу, в которой указан веб-шрифт
для текста. В браузере уже есть разметка HTML, он анализирует CSS-код и узнает, что необходимо загрузить шрифт, чтобы отобразить текст, как задумано. Перед
отображением текста на экране он зависает в ожидании веб-шрифта. Эта задержка называется FOIT (flash of invisible text — вспышка невидимого текста).
Как только шрифт поступает, браузер анализирует его и рендерит текст на
экране.
Надеюсь, что эта задержка незаметна. Там, где это не так, можно решить проблему двумя способами.
Первый способ — дождаться загрузки шрифта, обычно до нескольких секунд,
но иногда до бесконечности; Safari — самый известный сторонник этого варианта.
Второй способ — сначала отобразить текст системным шрифтом, а затем заменить его правильным шрифтом, если таковой есть в браузере.
Эта перерисовка текста с системного шрифта на предполагаемый шрифт известна как FOUT (flash of unstyled text — вспышка нестилизованного текста).
Настройки font-display позволяют нам в некоторой степени контролировать
то, что мы хотели бы видеть.

178

Глава 6. CSS-селекторы, типографика, цветовые режимы и многое другое

Его возможные значения:
y auto: все, что браузер считает подходящим.
y block: белый экран на срок до 3 с (но задержка остается на усмотрение брау­
зера), а затем указанный шрифт может заменить отображаемое изображение
в любой момент в будущем.
y swap: короткий период блокировки (рекомендуется 100 мс) для загрузки
веб-шрифта или в противном случае отображение системного шрифта, который может быть заменен доступным веб-шрифтом.
y fallback: предотвращение замены системного шрифта веб-шрифтом по
прошествии определенного времени (рекомендуется 3 с). Это блокировка
примерно на 100 мс, за которой следует замена в течение 3 с; если веб-шрифт
появится позже, он не будет применен.
y optional: загрузка веб-шрифта в течение очень короткого времени (100 мс),
но без периода подкачки. В результате браузер имеет возможность отменить
загрузку шрифта, если он не был доставлен, или использовать его для последующих загрузок страниц.

Спецификация для данного свойства здесь: here: https:// www.w3.org/TR/css-fonts4/#font-display-desc.

В спецификации CSS Font Module Level 4 есть много других свойств и значений,
связанных со шрифтами, но отображение шрифтов в настоящее время реализовано наиболее широко и имеет самое непосредственное отношение к отзывчивому
веб-дизайну и повышению производительности.
Мы рассмотрели, как добавить файлы шрифтов в проект, и даже подумали, как
лучше всего работать с ними с учетом производительности.
Но самая последняя и, вероятно, самая волнующая для большинства разработчиков тема, связанная с веб-шрифтами, — это вариативные шрифты. Что еще за
колдунство? Давайте выясним.

Вариативные шрифты
Когда я пишу эти строки в 2020 году, вариативные шрифты только набирают свою
популярность. Они есть в спецификации W3C и поддерживаются в последних
версиях браузеров. Однако, поскольку их поддержка ограничена, в ближайшие
несколько лет используйте альтернативные шрифты.
«Обычный» шрифт, например обычная версия Roboto, содержит информацию
и глифы для одного варианта гарнитуры. Для сравнения, вариативный шрифт
в одном файле содержит все нужное для всех размеров и начертаний Roboto: жирный, курсив, тонкий, черный, средний и другие!

Веб-типографика

179

Эта магия имеет свои последствия. Вариативная версия шрифта обычно занимает файл большего размера, чем его «обычная» версия. Тем не менее ее применение может быть оправдано, если вы активно используете один шрифт.
А теперь посмотрим, что можно сделать с вариативным шрифтом.

Изменение шрифта
Возьмем известный нам шрифт Inter, но его вариативную версию. Чтобы сообщить
браузеру, что мы работаем с вариативным шрифтом, используем синтаксис @fontface, но с некоторыми изменениями:
@font-face {
font-family: 'Inter-V';
src: url('fonts/inter.var.woff2') format('woff2-variations');
font-weight: 100 900;
font-style: oblique 0deg 10deg;
font-display: fallback;
}

Мы установили для свойства format значение woff2-variations, чтобы сообщить
браузеру, что это файл шрифта, в котором используются различные варианты
отображения.
В свойстве font-weight мы указали диапазон значений. Синтаксис значений
из двух слов понятен только браузерам, которые понимают вариативные шрифты.
Это способ сообщить браузеру, какие веса диапазона может использовать шрифт.
Хотя font-weight включает диапазон от 0 до 999, другие свойства могут иметь
другой диапазон. Некоторые свойства по-прежнему принимают значения 1 или 0.
Свойство font-style тоже имеет несколько значений. Ключевое слово oblique
сообщает браузеру, что следующие значения (диапазон) относятся к наклону
символов. В этом свойстве можно передавать отрицательные значения. Позже мы
рассмотрим их на практике.
Свойство font-display, как и в неизменяемых шрифтах, сообщает браузеру
способ загрузки и отображения шрифта.
Полный пример в каталоге example_06-13.

Использование вариативного шрифта
Вариативные шрифты используют так называемую ось вариаций (variation axis).
Ось вариации — это просто способ определения двух точек на обоих концах
шкалы. Затем можно выбрать любую точку вдоль шкалы для отображения шрифта. Диапазон значений не должен быть огромным, он может сводиться к простым
«включено» и «выключено» (знаю, не разгуляешься).
Оси вариации делятся на две группы: зарегистрированные и пользовательские.
Зарегистрированные оси
Зарегистрированные оси являются наиболее популярными, и спецификация со­чла
их достойными отдельных свойств в CSS:

180

Глава 6. CSS-селекторы, типографика, цветовые режимы и многое другое

Толщина (weight): насколько тяжелым выглядит текст; например, fontweight: 200.
y Ширина (width): насколько узким (сжатым) или разряженным выглядит
текст; например, font-stretch: 110%.
y Курсив (italic): отображается ли шрифт в курсивном начертании или нет;
например, font-style: italic.
y Наклон (slant): не путайте с курсивом. Он просто изменяет угол наклона
текста и не заменяет глифы. Например, font-style: oblique 4deg.
y Оптический размер (optical-size): это единственная из зарегистрированных
осей, для которой требуется дополнительное свойство шрифта. Свойство
font-optical-sizing, как вы уже догадались, связано с настройкой оптического размера. Но что это такое? Это изменение глифа в зависимости от его
размера для большей ясности. Это означает, например, что глиф, отображаемый в окне просмотра большого размера, может приобретать более тонкие
линии.
Значения, которые вы выбираете для этих свойств, должны соответствовать
возможностям вариативного шрифта. Например, нет смысла указывать толщину
шрифта 999, если этот шрифт может увеличиваться только до 600.
Существует также низкоуровневое свойство, которое позволяет объединить
настройки вариативного шрифта в одну пару свойство — значение:
y

font-variation-settings: 'wght' 300, 'slnt' -4;

В этом примере мы установили толщину шрифта 300 и угол наклона -4. Однако в спецификации есть предостережение:
По возможности следует использовать другие свойства, относящиеся к вариациям шрифтов (например, font-optical-sizing), и прибегать к этому
свойству только тогда, когда его применение является единственным способом доступа к редко используемому варианту шрифта. Например, предпочтительнее использовать font-weight: 700, а не font-variant settings:
"wght" 700.
Я не до конца понимаю, к чему этот совет. Спецификация не объясняет причины. Надеюсь, эта деталь будет добавлена, когда спецификация будет завершена.
Текущую версию спецификации можно посмотреть по адресу: https://drafts.csswg.
org/css-fonts-4/.

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

Теперь познакомимся с пользовательскими осями.

Веб-типографика

181

Пользовательские оси
Вариативные шрифты могут иметь свои оси. Например, шрифт FS Pimlico Glow
VF имеет ось «свечения». Вы можете изменять этот эффект следующим образом:
font-variation-settings: 'GLOW' 500;

Обратите внимание, что пользовательская ось записывается в верхнем регистре.
Это отличает ее от зарегистрированной оси в настройках вариативного шрифта.
Если ваша голова еще не болит из-за бесконечных, казалось бы, возможностей,
послушайте о расширенных свойствах шрифта, которые похожи на оси. Не волнуйтесь, эти сведения обретут для вас смысл в ближайшее время.
Расширенные свойства шрифтов
Вариативные шрифты могут включать расширенные свойства. Это может быть
буквально все, что веб-дизайнер шрифтов решит придумать! Взгляните на варианты для Inter:

Рис. 6.11. Справа от страницы настроек Inter в графе Features находится список
расширенных свойств шрифта

182

Глава 6. CSS-селекторы, типографика, цветовые режимы и многое другое

Такие свойства представляют собой настройки, которые можно включить с помощью CSS. Можно попрактиковаться в этом здесь: https://rsms.me/inter/
lab/?varfont=1.
Чтобы применить эти пользовательские свойства, мы используем свойство
font-feature-settings, которое работает аналогично font-variation-settings.
Например, чтобы нули отображались со слешем, мы можем сделать следующее:
font-feature-settings: 'zero';

Эта настройка «нулей со слешем» является двоичным выбором, поэтому нет
необходимости писать 'zero' 1. Однако, чтобы включить эту настройку в наши
стили, мы можем написать:
font-feature-settings: 'zero' 0;

Чтобы применить несколько настроек, разделите их запятыми. Чтобы получить
«L в нижнем регистре с хвостом» и «I в верхнем регистре с засечками», мы можем
написать следующее:
font-feature-settings: 'cv08', 'cv05';

Эти настройки активированы в завершенном примере в папке example_06-13.
В спецификации CSS Fonts Module Level 4 есть еще много настроек и свойств.
Чтобы быть в курсе событий, смотрите актуальную спецификацию здесь: https://
drafts.csswg.org/css-fonts-4/#introduction.

Упражнение
Взгляните на код CSS из нашего примера:
:root {
--MainFont: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
@font-face {
font-family: 'Inter-V';
src: url('fonts/inter.var.woff2') format('woff2-variations');
font-weight: 100 900;
font-display: fallback;
font-style: oblique 0deg 10deg;
}
body {
background-color: var(--background);
color: var(--foreground);
transition: all 0.35s;
font-size: 1.2em;
font-family: 'sans-serif';
font-family: var(--MainFont);
font-weight: 400;
}

Форматы цвета в CSS и альфа‑прозрачность

183

@supports (font-variation-settings: 'wdth' 200) {
body {
font-family: 'Inter-V';
font-variation-settings: 'wght' 300, 'slnt' -4;
font-feature-settings: 'cv08', 'cv05';
}
}

Что из этого вы теперь понимаете? Есть пользовательское свойство CSS, определенное для системного стека шрифтов, правило @font-face, загружающее вариативный шрифт в комплекте с диапазонами значений толщины и наклона. Есть
базовые шрифты без засечек в качестве стека шрифтов по умолчанию, который
мы заменяем на стек шрифтов, определенный в пользовательском свойстве для
браузеров, которые его понимают. Наконец, тесты, определяющие настройки вариативных шрифтов, а также возможность добавить расширенные свойства.
На этом мы подошли к концу нашего обсуждения веб-типографики.
До сих пор в этой главе рассматривались вопросы предоставляемых CSS новых
эффективных возможностей выбора элементов и добавления к конструкциям
пользовательского шрифтового оформления. Теперь мы рассмотрим обеспечиваемые CSS способы работы с цветом.

Форматы цвета в CSS
и альфа‑прозрачность
Когда мы только начинаем использовать CSS, то первым делом задаем цвет в формате шестнадцатеричного значения. Однако CSS предоставляет более интересные
способы объявления цвета. Мы изучим два из них: RGB и HSL. Кроме того, эти два
формата позволяют использовать вместе с ними альфа-канал (RGBA и HSLA соответственно). В оставшейся части этой главы мы рассмотрим, как они работают.

Цвет в формате RGB
RGB (red, green, blue) — это система задания цвета, которая существует уже не
одно десятилетие. Она определяет значения для красного, зеленого и синего компонентов цвета. Например, красный цвет может быть определен в CSS в виде шестнадцатеричного значения (или HEX-значения) #fe0208:
.redness {
color: #fe0208;
}

Описание более интуитивно понятных значений, выраженных шестнадцатеричными числами, вы можете найти в следующей статье из Smashing Magazine:
http://www.smashingmagazine.com/2012/10/04/the-code-side-of-color/.

184

Глава 6. CSS-селекторы, типографика, цветовые режимы и многое другое

С помощью CSS этот цвет может быть указан в виде RGB-значения следующим
образом:
.redness {
color: rgb(254, 2, 8);
}

Большинство приложений редактирования изображений показывают цвета на
панели выбора в виде как HEX-, так и RGB-значений. На панели выбора цвета
программы Photoshop есть R-, G- и B-области, показывающие значения для каждого из этих каналов. Например, значение R может выражаться числом 254, G —
числом 2, а B — числом 8. Эти значения преобразуются в значение цвета для CSS.
В CSS после определения режима задания цвета (например, RGB) значения для
красного, зеленого и синего цветов отделяются друг от друга запятыми и записываются внутри скобок в порядке, показанном в коде выше.

Цвет в формате HSL
Кроме формата RGB CSS позволяет использовать для объявления значения цвета формат HSL (hue, saturation, lightness — тон, насыщенность и яркость).
Востребованность формата HSL объясняется относительной простотой понимания того, какой именно цвет будет представлен при заданных им значениях.
Если вы не обладаете сверхспособностями по подбору цвета, держу пари, что вам
не удастся с ходу сказать, какой цвет выражен значением rgb(255, 51, 204). Есть
желающие? Только не я. А вот покажите мне HSL-значение hsl(315, 100%, 60%),
и я могу высказать догадку, что это цвет между пурпурным и красным (хотя это
ярко выраженный розовый). Как я догадался? Очень просто, с помощью мнемонического правила «Young guys can be messy rascals». Оно поможет запомнить
порядок цветов на диске HSL.
HSL-формат основан на цветовом диске (360°). Вот как он выглядит:

Рис. 6.12. Цветовой диск HSL-формата

Форматы цвета в CSS и альфа‑прозрачность

185

Не путайте HSL и HSB (hue, saturation и brightness)! Формат HSB, предложенный
на панели выбора цвета в таких приложениях, как Photoshop, — это не то же
самое, что HSL. Нет!

Первая цифра в цветовом определении формата HSL представляет собой тон.
Желтый цвет (Yellow) находится на отметке 60°, зеленый (Green) — 120°, светлоголубой (Cyan) — 180°, синий (Blue) — 240°, малиновый (Magenta) — 300° и, наконец,
красный (Red) — 360°. Если цвет в формате HSL имеет тон 315, нетрудно понять,
что он будет располагаться между малиновым (Magenta, 300°) и красным (Red, 360°).
Следующие два значения в HSL-формате задают насыщенность и яркость
и указываются в процентах, выражающих изменение базовых характеристик. Для
более насыщенного, красочного оттенка во втором значении указывается более
высокий процент. Последнее значение управляет яркостью и может варьировать
от 0 для чистого черного цвета до 100 % — для абсолютно белого цвета.
Если цвет определен в виде HSL-значений, вы легко создадите его варианты,
изменяя процентные показатели его насыщенности и яркости. Например, красный
цвет может быть определен в HSL-значениях следующим образом:
.redness {
color: hsl(359, 99%, 50%);
}

Чтобы получить чуть более темный цвет, воспользуйтесь теми же HSLзначениями, изменив процентный показатель яркости:
.darker-red {
color: hsl(359, 99%, 40%);
}

Запомнив мнемоническое правило «Young guys can be messy rascals» (или другое удобное для вас выражение), вы сможете приблизительно задать значение
цвета в формате HSL и его оттенок, не обращаясь к панели выбора цвета. Покажите этот трюк на корпоративной вечеринке в обществе парней и девушек из компании разработчиков на Ruby, Node или .NET и сможете быстро набрать очки к своему авторитету!

Альфа-каналы
Все это время я терпел ваше плохо скрываемое удивление по поводу того, что вы
должны предпочесть HSL или RGB старому, годами проверенному формату с использованием шестнадцатеричных значений. Основное отличие HSL и RGB от
HEX заключается в том, что эти два формата позволяют использовать канал альфа-прозрачности, позволяющий увидеть, что находится под верхним элементом.
Объявление цвета в формате HSLA похоже по синтаксису на стандартное HSLправило, но требует дополнительного указания hsla вместо hsl и добавления

186

Глава 6. CSS-селекторы, типографика, цветовые режимы и многое другое

показателя прозрачности в пределах от 0 (полная прозрачность) до 1 (полная непрозрачность), например:
.redness-alpha {
color: hsla(359, 99%, 50%, 0.5);
}

Синтаксис RGBA следует тому же соглашению, что и его HSLA-эквивалент:
.redness-alpha-rgba {
color: rgba(255, 255, 255, 0.8);
}

Вы спросите, почему нельзя просто воспользоваться свойством opacity? В CSSэлементах можно установить уровень непрозрачности с помощью свойства opacity.
Когда применяется свойство opacity, значение непрозрачности устанавливается между 0 и 1 с десятичным шагом (например, .1 означает 10 %) для всего
элемента. А установка значения HSLA или RGBA позволяет задать разные уровни
альфа-прозрачности отдельным частям элемента, например фону и тексту на нем.
Что можно вынести из этого разговора о цветах? Во-первых, если даны значения в шестнадцатеричном формате, нет нужды преобразовывать их во что-то
другое. Точно так же синтаксис RGB может иметь для вас смысл и вы можете
легко добавить альфа-канал с синтаксисом RGBA. Но большинству из нас нужно
иметь представление о HSL. Считаю, что это самый удобный для человека способ
думать о цвете в CSS, в наши дни он поддерживается почти повсеместно, а также
поддерживает альфа-канал с HSLA.

Итоги
В этой главе вы изучили удобные способы выбора элементов для страницы с помощью новых мощных селекторов CSS. Кроме того, вы получили представление
о новом цветовом модуле CSS и о том, как применять цвета с RGB-, HSL- и альфаканалами для получения интересных эстетических эффектов.
Мы обсудили добавление к веб-конструкциям пользовательского шрифтового
оформления с помощью правила @font-face, которое освободило нас от рутинного выбора веб-безопасных шрифтов. Мы также погрузились в вариативные шрифты и рассмотрели возможности, которые они могут предложить.
Также мы нашли время взглянуть на пользовательские свойства CSS и atправило @supports для функциональных разветвлений в коде.
Несмотря на все эти впечатляющие новые технологии, мы едва прикоснулись
к возможностям CSS.
Увидимся в главе 7 совсем скоро. Из нее мы узнаем еще больше приемов CSS,
таких как текстовые и блочные тени, градиенты, возможности применения многочисленных фонов и многое-многое другое!

7

Потрясающая эстетика
с помощью CSS

Для создания впечатляющих эффектов в отзывчивой конструкции большое значение имеют средства CSS. Они экономят время разработчика, облегчают поддержку кода, а для конечного пользователя делают страницу легковеснее.
В данной главе будут рассмотрены следующие темы:
y создание теней для текста;
y создание теней для блоков;
y создание градиентных фонов;
y использование нескольких фонов;
y использование паттернов градиентных фонов;
y реализация фоновых изображений с высоким разрешением с помощью
медиазапросов;
y использование фильтров CSS и их влияние на производительность;
y создание фигур с помощью свойства clip-path;
y наложение маски с помощью свойства mask-image;
y смешение цветов с помощью свойства mix-blend-mode.
Приступим к изучению перечисленных тем.

ПРЕФИКСЫ ПРОИЗВОДИТЕЛЕЙ
При реализации экспериментальных возможностей CSS не забывайте добавлять
соответствующие префиксы производителей, но не вручную, а с использованием
специального инструмента. Так вы обеспечите самую широкую кросс-брау­зер­
ную совместимость, а также избавитесь от добавления ненужных префиксов.
На момент написания книги наилучшим инструментом я считаю Autoprefixer (https://github.com/postcss/autoprefixer).

188

Глава 7. Потрясающая эстетика с помощью CSS

Создание теней для текста средствами CSS
Начнем с создания теней для текста — самого простого способа изменить эстетику
текста. Поддержка свойства text-shadow в браузерах повсеместна. Рассмотрим
базовый синтаксис:
.element {
text-shadow: 1px 1px 1px #ccc;
}

Не забудьте, что значения в сокращенных правилах всегда идут сначала слева
направо, а затем сверху вниз (напоминает направление по часовой стрелке).
Первое значение задает объем тени справа, второе — объем тени снизу, третье —
протяженность размытия (расстояние, проходимое тенью до ее полного исчезновения), четвертое — цвет. Тени, направленные влево и вверх, выражаются отрицательными значениями, например:
.text {
text-shadow: -4px -4px 0px #dad7d7;
}

Цветовое значение не обязательно определять в hex-виде (то есть в шестна­
дцатеричных числах), с тем же успехом оно может быть определено в формате
HSL(A) или RGB(A):
text-shadow: 4px 4px 0px hsla(140, 3%, 26%, 0.4);

Значения, задающие тень, можно указывать в любых приемлемых для CSS
единицах длины, в том числе em, rem, ch и т. д. При задании значений для свойства
text-shadow я редко использую единицы em или rem. Поскольку значения всегда
небольшие, то при любых величинах окон просмотра неплохо выглядят тени, заданные как 1 px или 2 px.
С помощью медиазапросов и значения none мы можем без особого труда удалять
текстовые тени в различных окнах просмотра:
.text {
text-shadow: 2px 2px 0 #bfbfbf;
}
@media (min-width: 30rem) {
.text {
text-shadow: none;
}
}

Кстати, в CSS первый нуль в значении можно не ставить: например, вместо 0.14s
писать .14s.

Создание теней для блоков

189

Если размытие не нужно, его значение можно опустить
Если добавлять размытие к значениям свойства text-shadow не нужно, то его можно опустить, например:
.text {
text-shadow: -4px -4px #dad7d7;
}

Это значение будет вполне допустимым. Браузер поймет, что если не задано
третье значение, то первые два значения будут относиться к смещению тени.

Добавление нескольких теней к тексту
Если разделить задания теней запятыми, то к тексту можно добавить сразу несколько теней, например:
.multiple {
text-shadow: 0px 1px #fff, 4px 4px 0px #dad7d7;
}

Кроме того, поскольку в CSS на пробельные символы не обращается никакого
внимания, подобные значения можно разметить следующим образом, если, конечно, так их будет легче читать:
.text {
font-size: calc(100vmax / 40); /* 100 vh или vw, в зависимости от того,
что больше в результате деления на 40 */
text-shadow:
3px 3px #bbb,
/* справа и снизу */
-3px -3px #999; /* слева и сверху */
}

W3C-спецификацию, касающуюся свойства text-shadow , можно найти по
адресу: http://www.w3.org/TR/css3-text/.
Вот как создаются тени вокруг текста. А как создается тень для блока?

Создание теней для блоков
Свойство box-shadow позволяет создавать прямоугольные тени как снаружи, так
и внутри элемента, к которому они применяются. После того как вы разобрались
с тенями для текста, понять суть теней для блоков будет намного легче. В целом,
у них один синтаксис: смещение по горизонтали, смещение по вертикали, размытие, протяженность (о которой мы вскоре узнаем) и цвет. Из четырех возможных
значений длины обязательными являются только два. В отсутствие последних
двух значений цветовым значением считается цвет тени, а для радиуса размытия
используется нулевое значение. Рассмотрим простой пример:

190

Глава 7. Потрясающая эстетика с помощью CSS

.shadow {
box-shadow: 0px 3px 5px #444;
}

По умолчанию свойство box-shadow настроено на создание тени снаружи элемента. Чтобы создать тень внутри элемента, добавьте к box-shadow ключевое
слово inset.

Тень внутри элемента
Свойство box-shadow может также использоваться для создания внутренней тени.
Синтаксис при этом идентичен тому, который используется для задания наружной
тени, за исключением того, что значения начинаются с ключевого слова inset:
.inset {
box-shadow: inset 0 0 40px #000;
}

Оба примера можно увидеть, запустив код из каталога example_07-01.

наружная
тень

внутренняя
тень

Рис. 7.1. Как наружные, так и внутренние тени получаются довольно легко

Создание нескольких теней
Как и text-shadow, свойство box-shadow позволяет применить сразу несколько
теней. Разделите значения, задаваемые свойству box-shadow, запятой, и они будут
применены снизу вверх (от последнего к первому). Запомните этот порядок, при
котором чем выше значение расположено в правиле (коде), тем выше оно находится в порядке вывода браузером на экран. Как и с объявлениями text-shadow,
вы можете извлечь пользу от применения пробельных символов для выстраивания
«столбца» значений для свойства box-shadow:
box-shadow:
inset 0 0 30px hsl(0, 0%, 0%),
inset 0 0 70px hsla(0, 97%, 53%, 1);

191

Создание теней для блоков

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

Понятие протяженности
Если честно, я все никак не мог взять в толк, что для свойства box-shadow означает параметр spread. Не думаю, что название «spread» (распространение) отражает
истинный смысл этого параметра. Лучше думать о нем как о протяженности.
Посмотрите на блок, появляющийся слева на экране при запуске кода из каталога example_06-02. К нему применены стандартные значения свойства box-shadow
без параметра spread. А к блоку справа применено отрицательное значение spread.
Вот как выглядит соответствующий код:
.no-spread {
box-shadow: 0 10px 10px;
}
.spread {
box-shadow: 0 10px 10px -10px;
}

А вот эффект от этих настроек на экране (элемент с установленным значением
spread расположен справа).

без spread

со spread

Рис. 7.2. С помощью параметра spread можно контролировать протяженность тени

Значение spread позволяет расширить или сузить тень во всех направлениях
на указанную величину. В этом примере отрицательное значение «затягивает»
тень со всех сторон блока и мы видим тень только внизу.

192

Глава 7. Потрясающая эстетика с помощью CSS

W3C-спецификацию, касающуюся свойства box-shadow, можно найти по адресу: http://www.w3.org/TR/css3-background/.

Вот мы и познакомились с тенями. И продолжим работать с тенями, когда рассмотрим свойство drop-shadow как часть фильтров CSS. А пока перейдем к градиентам.

Градиентные фоны
Раньше, чтобы получить для элемента градиентный фон, нужно было выложить
плиткой тонкие графические фрагменты градиента. С точки зрения экономии
графических ресурсов это был компромисс. Изображение шириной 1–2 px не наносило ущерба пропускной способности сети и могло на одном и том же сайте
использоваться сразу для нескольких элементов.
Но, чтобы настроить градиент, приходилось возвращаться к графическому
редактору. Кроме того, иногда содержимое могло выходить за пределы градиентного фона и фиксированного размера изображений. В адаптируемой конструкции
эта проблема усложнялась, поскольку разделы страницы в различных окнах просмотра могли увеличиваться.
Являясь частью спецификации CSS Image Values and Replaced Content Module
Level 3, CSS позволяет создавать отзывчивые линейные и радиальные градиентные фоны с помощью свойства background-image . Посмотрим, как их можно
определить.

Спецификацию CSS Image Values and Replaced Content Module Level 3 можно
найти по адресу: http://www.w3.org/TR/css3-images/.

Запись линейного градиента
Запись linear-gradient в наипростейшей форме выглядит следующим образом:
.linear-gradient {
background: linear-gradient(red, blue);
}

Она приведет к созданию линейного градиента, начинающегося с красного (градиент по умолчанию начинается сверху) и постепенно переходящего
в синий цвет.

Градиентные фоны

193

Указание направления градиента
Чтобы указать направление градиента, есть два способа. Начинаться градиент
всегда будет с направления, противоположного указанному. Но когда направление
не указано, он всегда будет распространяться сверху вниз, например:
.linear-gradient {
background: linear-gradient(to top right, red, blue);
}

В данном примере градиент направляется в правый верхний угол. Он начинается с красного цвета в левом нижнем углу и постепенно переходит в синий цвет
в правом верхнем углу.
Если вам ближе математические представления, то можете поверить, что градиент допустимо записать в следующей форме:
.linear-gradient {
background: linear-gradient(45deg, red, blue);
}

Но имейте в виду, что в прямоугольном блоке градиент, направленный в правый
верхний угол (элемента, к которому он применяется), будет заканчиваться немного в другой позиции, чем градиент, заданный под углом 45° от его стартовой
позиции (45deg).
И учтите, что стартовую точку градиента можно назначать за пределами блока,
например:
.linear-gradient {
background: linear-gradient(red -50%, blue);
}

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

Цветовые остановки
Возможно, самыми удобнымисредствами задания градиентных фонов являются
цветовые остановки. Они позволяют устанавливать, какой цвет нужно использовать в каждой точке градиента. С помощью цветовых остановок можно задать
установки любой сложности. Рассмотрим следующий пример:
.linear-gradient {
margin: 1rem;
width: 400px;
height: 200px;
background: linear-gradient(

194

}

Глава 7. Потрясающая эстетика с помощью CSS

#f90
#f90
#555
#eee
#555
#f90
#f90
);

0,
2%,
2%,
50%,
98%,
98%,
100%

Вот вывод на экран таких значений свойства linear-gradient:

Рис. 7.3. Можно добавить любое количество опорных точек

В этом примере (из каталога example_07-03) направление не указано, поэтому
применено направление по умолчанию сверху вниз.
Цветовые остановки внутри градиента записаны через запятые, и в них указаны сначала цвет, а затем позиция остановки. Рекомендуется не смешивать единицы измерения в одной и той же записи, но делать это не запрещено. Цветовых
остановок может быть сколько угодно, а цвета в них могут быть заданы ключевыми словами, а также значениями в форматах HEX, RGBA или HSLA.
Есть много готовых синтаксисов градиентных фонов, поэтому сегодня трудно
записывать альтернативные варианты фонов вручную.
Не рискуйте получить эффект испорченной пластинки (если не знаете, что
такое пластинка, спросите об этом у родителей), упростите свою жизнь с помощью
средства Autoprefixer. Оно позволит записывать код, соответствующий текущему
стандарту синтаксиса W3C (как указывалось ранее), и автоматически создавать
для вас предыдущие версии.

Спецификацию W3C, относящуюся к линейным градиентным фонам, можно найти по адресу: http://www.w3.org/TR/css3-images/.

От линейных градиентных фонов перейдем к радиальным градиентным фонам.

Градиентные фоны

195

Радиальные градиентные фоны
Создавать радиальные градиенты в CSS ничуть не сложнее. Как правило, они начинаются в центральной точке и постепенно распространяются в форме эллипса
или круга.
Радиальный градиентный фон имеет следующий синтаксис (из каталога
example_06-04):
.radial-gradient {
margin: 1rem;
width: 400px;
height: 200px;
background: radial-gradient(12rem circle at bottom, yellow,
orange, red);
}

Рис. 7.4. Создание градиента можно начать из любой точки. На изображении
градиент «Восход солнца» начинается из центральной нижней точки

Анализ синтаксиса radial-gradient
За указанием свойства background: следует запись radial-gradient. В ней сначала определяются размер, форма и позиция градиента. В примере мы использовали
круг размером 12 rem, но обратите внимание на другие варианты:
y 5em задаст круг размером 5 em. Если задан только размер, то определение
формы 'circle' можно опустить.
y circle без указания размера задаст круг на весь размер контейнера.
y 40px 30px определит форму эллипса, как бы прорисованного внутри прямоугольника шириной 40 px и высотой 30 px.
y ellipse без указания размера задаст эллипс на весь размер элемента.
После размера и формы определяется позиция. По умолчанию позицией является центр, но рассмотрим другие варианты:
y at top right задает начало распространения радиального градиента из
правого верхнего угла.

196

Глава 7. Потрясающая эстетика с помощью CSS

y

at right 100px top 20px устанавливает начало распространения радиаль-

ного градиента на расстоянии 100 px от правого края объекта и 20 px от
верхнего края.
y at center left задает начало распространения градиента на середине пути
вниз по левой стороне элемента.
После запятой определяются цветовые остановки, работающие так же, как
в linear-gradient.
Упростим описание записи: размер, форма и позиция указываются перед первой запятой, после которой через запятую указывается любое количество цветовых
остановок.
Для определения размеров таких вещей, как градиенты, CSS предоставляет
ключевые слова, которые часто более удобны, чем жестко запрограммированные
значения, особенно при отзывчивом веб-дизайне.

Удобные ключевые слова «распространения»
для задания размеров отзывчивых конструкций
Чтобы добиться отзывчивости, лучше задавать размеры градиентов в пропорциях,
а не фиксированных величинах. Так вы защитите код от изменения размеров элементов. К градиентам можно применять ряд удобных ключевых слов, задающих
размеры. Их вместо любых значений размеров можно записывать следующим
образом:
background: radial-gradient(closest-side circle at center, #333,
blue);

Вот к чему приводит применение каждого из них:
y closest-side — круг распространяется до ближайшей к центру стороны
блока, а эллипс — до ближайших к центру горизонтальной и вертикальной
сторон.
y closest-corner — фигура распространяется от центра строго до ближайшего угла блока.
y farthest-side — круг распространяется из центра до самой дальней стороны, а эллипса — до самых дальних горизонтальной и вертикальной сторон.
y farthest-corner — фигура распространяется из центра до самого дальнего
угла блока.
y cover — результат идентичен применению farthest-corner.
y contain — результат идентичен применению closest-side.

Спецификацию W3C, относящуюся к радиальным градиентным фонам, можно
найти по адресу: http://www.w3.org/TR/css3-images/.

Повторяющиеся градиенты

197

ТРЮК ДЛЯ ПОЛУЧЕНИЯ ЛИНЕЙНЫХ И РАДИАЛЬНЫХ ГРАДИЕНТОВ
Существует несколько интерактивных генераторов градиентов. Я предпочитаю
пользоваться средством, которое можно найти по адресу: http://www.colorzilla.com/
gradient-editor/. В его графическом интерфейсе используется стиль графического
редактора, позволяющий выбирать цветовые остановки, стиль градиента (поддерживаются как линейные, так и радиальные градиенты) и работать в цветовом
пространстве (HEX, RGB(A), HSL(A)). Также он позволяет загружать и редактировать готовые градиенты. Если этого недостаточно, данное средство обеспечит вас
дополнительным кодом для исправления недостатков Internet Explorer 9, чтобы
показать градиент и создать альтернативный вариант со сплошным цветом для
устаревших браузеров. Все еще сомневаетесь? А как насчет его способности
генерировать CSS-градиент на основе градиентных значений в существующем
изображении? Возможно, именно этот аргумент станет для вас решающим.

Повторяющиеся градиенты
CSS также позволяет создавать повторяющиеся градиентные фоны. Посмотрим,
как это делается:
.repeating-radial-gradient {
background: repeating-radial-gradient(black 0px, orange 5px, red
10px);
}

А вот как это выглядит на экране (долго на это смотреть не стоит):

Рис. 7.5. Можно использовать повторяющиеся градиенты для создания практически
любых визуальных эффектов

Сначала для linear-gradient или radial-gradient укажите префикс repeating
и используйте тот же синтаксис, что и для обычного градиента. Здесь между черным, оранжевым и красным цветами (0, 5 и 10 px соответственно) я использовал
пиксельную дистанцию, но вы можете задать значения и в процентах.
Хочу поделиться еще одним способом использования градиентных фонов.

198

Глава 7. Потрясающая эстетика с помощью CSS

Информацию из W3C, касающуюся повторяющихся градиентов, можно получить
по адресу: http://www.w3.org/TR/css3-images/.

Паттерны градиентных фонов
В дизайне я часто использовал едва заметные линейные градиенты и считал, что
радиальные и повторяющиеся градиенты менее практичны. Но эффективность
градиентов для создания паттернов градиентных фонов уже заявила о себе. Рассмотрим примеры из CSS Ninja — коллекции фоновых паттернов CSS, доступной
на сайте http:// lea.verou.me/css3patterns/:
.carbon-fibre {
margin: 1rem;
width: 400px;
height: 200px;
background: radial-gradient(black 15%, transparent 16%) 0 0, radialgradient(
black 15%,
transparent 16%
) 8px 8px,
radial-gradient(rgba(255, 255, 255, 0.1) 15%, transparent 20%) 0 1px,
radial-gradient(
rgba(255, 255, 255, 0.1) 15%,
transparent 20%
) 8px 9px;
background-color: #282828;
background-size: 16px 16px;
}

После запуска кода в браузере на экране появится эффект фона carbon-fibre:

Рис. 7.6. Эффект углеродного волокна на чистом CSS-коде

Использование нескольких фоновых изображений

199

Понравилось? Всего лишь из нескольких строк кода CSS появился легко редактируемый отзывчивый и масштабируемый фоновый паттерн.
Чтобы разобраться в работе правил, попробуйте написать background-repeat:
no-repeat.
Благодаря медиазапросам для различных отзывчивых сценариев могут использоваться разные объявления. Например, несмотря на то что в малых окнах
просмотра вполне успешно могут работать градиентные паттерны, для более
крупных окон более уместно выводить простой фон:
@media (min-width: 45rem) {
.carbon-fibre {
background: #333;
}
}

Этот пример находится в каталоге example_07-05.
Мы рассмотрели множество способов создания фоновых изображений, используя только CSS. Однако будь то линейный, радиальный или повторяющийся
градиент, это всего лишь одно фоновое изображение. А как насчет того, чтобы
поработать с несколькими фоновыми изображениями одновременно?

Использование нескольких фоновых
изображений
Хотя это и вышло из моды, раньше были весьма распространены страницы, у которых верхнее фоновое изображение отличалось от нижнего. В CSS 2.1 для получения этого эффекта требовалась дополнительная разметка (один элемент нужен
был для фона заголовка, а другой — для фона подвала).
Теперь в одном элементе можно накладывать друг на друга любое количество
изображений.
Синтаксис имеет следующий вид:
.bg {
background: url('../img/1.png'), url('../img/2.png'), url('../
img/3.png');
}

Как и при наложении нескольких теней, изображение, стоящее в перечне первым, станет на экране браузера верхним. В том же объявлении можно добавить
общий цвет фона:
.bg {
background: url('../img/1.png'), url('../img/2.png'),
url('../img/3.png') left bottom, black;
}

200

Глава 7. Потрясающая эстетика с помощью CSS

Укажите цвет последним, чтобы он был показан под всеми изображениями,
заданными выше его.
Если фоновое изображение является PNG-файлом со свойством прозрачности,
то мы видим, что находится под ним. Но фоновые изображения не обязательно
должны наслаиваться друг на друга и быть одного размера.

Размер фона
Чтобы установить для изображений разные размеры, примените свойство back­
ground-size. При использовании нескольких изображений синтаксис работает
следующим образом:
.bg {
background-size: 100% 50%, 300px 400px, auto;
}

Здесь в том порядке, в котором изображения перечислены в свойстве background,
указаны значения размеров каждого изображения (сначала ширина, а затем высота) через запятую. Здесь тоже можно использовать разные единицы измерения,
а также ключевые слова:
y auto — задает естественный размер элемента;
y cover — расширяет изображение, сохраняя соотношение его сторон, чтобы
оно заняло всю площадь элемента;
y contain — расширяет изображение, сохраняя соотношение его сторон, чтобы оно заняло самую длинную сторону элемента.

Позиционирование фона
Для разных по размеру фоновых изображений может потребоваться указать
разные позиции. К счастью, с этой задачей справится свойство backgroundposition.
Объединим все возможности указания фоновых изображений и добавим установки для адаптируемых конструкций из предыдущих глав.
Создадим простую космическую сцену из одного элемента и трех фоновых
изображений, для которых установлены разные размеры и позиции:
.bg-multi {
height: 100vh;
width: 100vw;
background: url('rosetta.png'), url('moon.png'), url('stars.jpg');
background-size: 75vmax, 50vw, cover;
background-position: top 50px right 80px, 40px 40px, top center;
background-repeat: no-repeat;
}

Использование нескольких фоновых изображений

201

В браузере мы увидим картинку, похожую на эту:

Рис. 7.7. Несколько фоновых изображений в одном элементе

В нижнем слое оказалось звездное небо, поверх него — луна, и, наконец,
в верхнем слое — зонд «Розетта». Выведите картинку на экран из каталога
example_07-06. Обратите внимание, что при изменении размеров окна браузера
отзывчивые единицы измерения (vmax, vh и vw) помогают сохранить пропорции
изображений.

Если значения для свойства background-position не указаны, то по умолчанию применяется позиция в левом верхнем углу.

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

Документацию W3C, относящуюся к нескольким фоновым элементам, можно
найти по адресу: http://www.w3.org/TR/css3-background/.

202

Глава 7. Потрясающая эстетика с помощью CSS

Фоновые изображения с высоким разрешением
Медиазапросы позволяют загружать фоновые изображения не только для разных размеров, но и для разных разрешений окон просмотра. Рассмотрим официально утвержденный способ указания фонового изображения для нормального экрана и для экрана с высоким показателем dpi. Этот код находится в каталоге
example_07-07:
.bg {
background-image: url('bg.jpg');
}
@media (min-resolution: 1.5dppx) {
.bg {
background-image: url('bg@1_5x.jpg');
}
}

Медиазапрос, как и раньше, составляется с проверкой ширины, высоты или
других характеристик. В данном примере определен минимальный показатель
разрешения, при котором должно использоваться изображение bg@1_5x.jpg, составляющее 1,5 dppx (количество пикселов устройства, приходящихся на один
пиксел CSS). При желании можно применить единицы измерения dpi (количество
точек на дюйм) или dpcm (количество точек на сантиметр). Я считаю, что проще
осмыслить единицу измерения dppx, несмотря на ее слабую поддержку, поскольку, к примеру, 2 dppx означает удвоенное разрешение, а 3 dppx — утроенное.
Разобраться в разрешении, выраженном в dpi, намного сложнее. Стандартным
считается разрешение 96dpi, удвоенное разрешение выражается значением 192 dpi
и т. д.

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

CSS-фильтры
У свойства box-shadow есть одна очевидная проблема. В соответствии с названием
его работа ограничена принятой в CSS прямоугольной формой блока, к которому
оно применяется. Вот как выглядит на экране треугольник, полученный с помощью
CSS, с примененной к нему тенью блока (код можно найти в каталоге example_06-08).

203

CSS-фильтры

Рис. 7.8. Тени блоков не всегда выглядят так, как мы хотим

К счастью, этот недочет можно обойти с помощью CSS-фильтров, являющихся
частью спецификации Filter Effects Module Level 1 (http://www.w3.org/TR/filter-effects/).
Вот тот же элемент с CSS-фильтром drop-shadow, примененным вместо box-shadow.

Рис. 7.9. Эффект фильтра drop-shadow может применяться не только к блокам

Формат CSS-фильтров имеет следующий вид:
.filter-drop-shadow {
filter: drop-shadow(8px 8px 6px #333);
}

В свойстве filter указывается фильтр, например drop-shadow, а затем передаются аргументы для фильтра. Для drop-shadow используется такой же синтаксис,
как и для box-shadow, поэтому разобраться в нем довольно просто: смещение по
осям x и y, размытие и радиус протяженности (оба этих параметра являются необязательными) и, наконец, цвет (указывать его также не обязательно, хотя в целях
совместимости рекомендую от него не отказываться).
Фактически CSS-фильтры основаны на SVG-фильтрах (глава 8), обладающих
более широкой поддержкой.

Доступные CSS-фильтры
Далее будут показаны изображения после применения фильтров, и читателям
бумажной версии книги будет нелегко заметить разницу. Не забывайте, что работу фильтров можно увидеть в файле из каталога example_06-08. Рассмотрим эти
фильтры и подходящие для них значения. Чем больше значение, тем больше применение фильтра. Изображения следуют сразу после соответствующего определения фильтра.
y filter: url ('./img/filters.svg#filterRed') — позволяет указать используемый SVG-фильтр.
y filter: blur(3px) — используется единственное значение протяженности
размытия (не в процентном выражении).

204

Глава 7. Потрясающая эстетика с помощью CSS

Рис. 7.10. Изображение с фильтром blur
y

filter: brightness(2) — значение яркости 1 или 100% является нормой,
менее 0,5 или 50% — затемнением и более 200% — осветлением элемента.

Рис. 7.11. Изображение с фильтром brightness
y

filter: contrast(2) — значение контрастности 1 или 100% является нормой,
менее 0,5 или 50% — уменьшает контрастность и более 200% — существенно

увеличивает ее.

205

CSS-фильтры

Рис. 7.12. Изображение с фильтром contrast
y
y

filter: drop-shadow(4px 4px 6px #333) — фильтр drop-shadow был подробно рассмотрен выше.
filter: grayscale(.8) — значения от 0 до 1 или от 0% до 100% выражают степень обесцвечивания элемента. Значение 0 оставляет изображение полноцветным, а 1 его полностью обесцвечивает, превращая цвета в оттенки серого.

Рис. 7.13. Изображение с фильтром grayscale

206

Глава 7. Потрясающая эстетика с помощью CSS

y

filter: hue-rotate(25deg) — значения от 0° до 360° выражают коррекцию

цвета по цветовому кругу. Отрицательные значения корректируют цвет
в обратную сторону, а со значениями выше 360° круг начнется заново.

Рис. 7.14. Изображение с фильтром hue-rotate
y

filter: invert(75%) — значения от 0 до 1 или от 0% до 100% выражают раз-

личные степени цветового инвертирования элемента.

Рис. 7.15. Изображение с фильтром invert

207

CSS-фильтры

y

filter: opacity(50%) — значения от 0 до 1 или от 0% до 100% выражают
степень прозрачности элемента. Значения 1 или 100% означают полную непрозрачность, а 0 или 0% — полную прозрачность. Этот фильтр по своему
действию аналогичен уже знакомому вам свойству opacity. Но фильтры,

в чем мы вскоре убедимся, могут объединяться, позволяя применять прозрачность одновременно с другими фильтрами.

Рис. 7.16. Изображение с фильтром opacity
y

filter: saturate(15%) — значения от 0 до 1 или от 0% до 100% выражают
степень снижения насыщенности изображения, а значения, превышающие
1 или 100%, выражают степень ее повышения.

Рис. 7.17. Изображение с фильтром saturate

208

Глава 7. Потрясающая эстетика с помощью CSS

y

filter: sepia(.75) — значения от 0 до 1 или от 0% до 100% выражают до-

бавление в изображение коричневых оттенков.

Рис. 7.18. Изображение с фильтром sepia

Объединение CSS-фильтров
Фильтры можно легко объединять с помощью записи через пробелы. Например,
одновременного применения фильтров opacity, blur и sepia можно добиться с помощью следующего кода:
.MultipleFilters {
filter: opacity(10%) blur(2px) sepia(35%);
}

Отрицательные значения для фильтров, за исключением hue-rotate, применять
не разрешается.

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

Предупреждения, касающиеся CSS‑производительности

209

Предупреждения, касающиеся
CSS‑производительности
Когда речь заходит о CSS-производительности, хочется напомнить о следующем:
Архитектура находится за скобками, а производительность — в скобках.
Бен Фрэйн
Поясню. Разговор о том, насколько быстро или медленно работает селектор
CSS (который находится за скобками), не имеет смысла. Собранные мной доказательства я привел в статье: http://benfrain.com/css-performance-revisited-selectorsbloat-expensive-styles/.
Но есть то, что действительно может довести страницу до остановки, — это
использование в CSS затратных свойств (в скобках). Стиль называют «затратным»,
если он заставляет браузер претерпевать массу издержек. Это то, что браузер (точнее, аппаратное обеспечение) считает чрезмерно обременительным для выполнения.
Что, скорее всего, вызовет перегрузку браузера, подскажет здравый смысл.
В основном это все, что требует предварительных вычислений перед прорисовкой
на экране. Сравним, к примеру, стандартный div-контейнер со сплошным однотонным фоном с полупрозрачным изображением в верхнем слое, составленным
из нескольких градиентов, имеющим скругленные углы и тень, полученную с помощью фильтра drop-shadow. Второй вариант будет намного затратнее, вызовет
больший объем вычислительной работы для браузера и, соответственно, станет
причиной более серьезных издержек.
Поэтому при применении таких эффектов, как фильтры, нужно проявлять
расчетливость и по возможности проверять, где падает скорость работы страницы
на маломощных устройствах, для которых вы надеетесь сохранить поддержку.
В качестве крайней меры включите такие свойства, как постоянная перерисовка
страницы в Chrome, и выключите эффекты, которые, на ваш взгляд, могут вызвать
проблемы. Так вы получите данные в миллисекундах, позволяющие судить о продолжительности прорисовки в текущем окне просмотра, и сможете осознанно
выбрать эффекты. Чем ниже показания на графике, тем быстрее будет выполняться страница (но учтите широкое разнообразие браузеров и платформ, поэтому по
возможности проводите тестирование на реальных устройствах).
Для углубленного изучения этого вопроса рекомендую следующий ресурс:
https://developers.google.com/web/fundamentals/performance/rendering/.
Хорошо, взрослые разговоры на этом закончились. Давайте вернемся к интересным и мощным возможностям CSS. Следующей по списку идет обрезка.

210

Глава 7. Потрясающая эстетика с помощью CSS

Рис. 7.19. Убедитесь, что необычные эффекты не вызывают значительного снижения
производительности

CSS-свойство clip-path
Свойство clip-path позволяет «скрепить» элемент с формой. Можно представить
эту возможность CSS как рисование фигуры на листе бумаги, а затем ее вырезание
по контуру. Эта форма может быть, например, эллипсом, многоугольником или
даже формой, определяемой встроенным SVG-файлом. Отобразите такие формы
на странице с помощью загружаемого кода в каталоге example-07_09.

Свойство clip-path с URL-адресом
Можно использовать путь к встроенному SVG-файлу следующим образом:
clip-path: url(#myPath);

Если термин «встроенный SVG-файл» кажется вам бессмысленным, не беспокойтесь
об этом пока. Вернитесь сюда, когда прочтете следующую главу об SVG-графике.

Базовые формы CSS
Вы можете использовать свойство clip-path с любой из основных форм CSS:
вставка, круг, эллипс и многоугольник, как описано здесь: https://www.w3.org/TR/
css-shapes-1/#supported-basic-shapes.
Посмотрим, как писать каждый из них.

211

CSS-свойство clip-path

Свойство clip-path со значением circle
В записи clip-path: circle() первый аргумент, который вы передаете, — это размер, а второй, необязательный аргумент — это положение формы. Итак, если вы
хотите обрезать элемент до круга, составляющего 20 % высоты и ширины элемента, напишите:
clip-path: circle(20%);

Если вам нужна такая же маска в форме круга, но расположенная на 60 % по
горизонтали и 40 % по вертикали, то используйте следующий код:
.clip-circle {
clip-path: circle(35% at 60% 40%);
}

Рис. 7.20. Обрезка в форме круга

Заметили ключевое слово at? Оно сообщает браузеру, что значение после него
относится к позиционированию, а не к размеру.

Важно знать, что события указателя не происходят для отрезанных областей элемента! Следуя аналогии с листом бумаги, области за пределами маски — отрезанные и выброшенные кусочки бумаги.

Свойство clip-path со значением ellipse
В записи clip-path: ellipse() первый аргумент — это радиус по оси x, а второй —
радиус по оси y. Как и в случае со значением circle(), длина позиционирования
указана после ключевого слова at:
.clip-ellipse {
clip-path: ellipse(100px 50px at 60% 40%);
}

212

Глава 7. Потрясающая эстетика с помощью CSS

Рис. 7.21. Обрезка в форме эллипса

Свойство clip-path со значением inset()
Функция inset() — необычное значение для свойства clip-path. Для нее требуется четыре значения, обозначающих отступы маски от краев элемента. Как в случае с margin, можно использовать два значения: первое определяется сверху вниз,
а второе — слева направо (синтаксис с тремя значениями также работает).
Можно использовать необязательное ключевое слово round, за которым следует новое значение, устанавливающее степень закругления каждого из углов.
Вот пример с четырьмя указанными значениями вставки и четырьмя разными
значениями скругления углов:
.clip-inset {
clip-path: inset(40px 20px 40px 20px round 0 30px 15px 40px);
}

Рис. 7.22. Свойство clip-path с функцией inset()

CSS-свойство clip-path

213

Свойство clip-path со значением polygon()
Функция polygon() для свойства clip-path позволяет описать простую фигуру
серией координат x и y, разделенных запятыми. Вот как выглядит треугольник,
написанный с помощью функции polygon():
.clip-polygon {
clip-path: polygon(50% 60px, 100% calc(100% - 40px), 0% calc(100%
- 40px));
}

Рис. 7.23. Свойство clip-path с функцией polygon()

Представьте, что вы описываете, с чего начать обрезку (первый аргумент), куда
двигаться дальше (любые последующие аргументы) и где должна быть последняя
точка. Затем polygon() соединяет последнюю точку с первой, завершая путь.
Каждый аргумент состоит из координаты x, описанной в верхнем левом углу
контейнера (например, 50 % вдоль), а затем координаты y (например, 60 px сверху)
относительно верха контейнера.
Мой любимый способ начать работу с функцией polygon() свойства clip-path —
посетить веб-сайт https://bennettfeely.com/clippy/.
Там есть куча готовых форм на выбор, а также графические интерфейсы для
изменения формы. Настоятельно рекомендую!

Свойство clip-path с URL (источником обрезки)
Вы также можете указать для свойства clip-path «источник обрезки» через URLадрес. URL-адрес должен представлять собой SVG clipPath где-нибудь в документе.
Я сделал звезду на SVG и добавил идентификатор starSymbol к элементу
clipPath. После этого можно указать свойству clip-path использовать этот путь
следующим образом:

214

Глава 7. Потрясающая эстетика с помощью CSS

.clip-url {
clip-path: url(#starSymbol);
}

Рис. 7.24. Свойство clip-path с фигурой, описанной посредством SVG

Просмотрите каждый из этих примеров использования свойства clip-path
в каталоге example_07-09.

Анимация с помощью свойства clip-path
Если вся эта информация про обрезку была недостаточно интересна — предлагаю
анимировать элементы с помощью свойства clip-path, не меняя количества точек
фигуры. Да, вы можете анимировать треугольник в треугольник другой формы, но
без некоторых уловок вы не сможете преобразовать тот же треугольник в звезду. «Некоторыми уловками» я называю возможность скрыть несколько точек вдоль линий
многоугольника, чтобы у треугольника было достаточно точек для анимации в звезду.
Вот еще один пример, который я добавил в каталог example_07-10. Попытаемся
соединить несколько вещей, которые мы уже узнали и которые изучим в следующих главах:

Рис. 7.25. Свойство clip-path можно анимировать

Изображение в качестве маски

215

В данном примере показаны два элемента с одинаковым фоновым изображением, замаскированных с помощью clip-path. Вы также можете затемнять изображение с помощью наложения фигур:
background: linear-gradient(hsla(0, 0%, 0%, 0.4) 0, hsla(0, 0%, 0%, 0.4)
100%),
url('image.jpg');

При использовании нескольких фоновых элементов невозможно указать цвет
фона (background-color) над изображением. Однако мы можем создать фоновое изображение, используя свойство linear-gradient с тем же цветом
HSLA сверху и снизу, что создаст желаемый эффект.

Затем мы переместим основной элемент по странице с одним набором анимаций
keyframes (глава 9) и анимируем clip-path с другим набором.

Думаю, что как только вы начнете экспериментировать с этими техниками, то
удивитесь, как легко у вас все получится!
Чтобы не просто вырезать часть элемента, а наложить на нее маску, используем CSS.

Изображение в качестве маски
Вы также можете маскировать элементы изображениями из любого источника
с прозрачностью, такого как PNG-графика, линейный градиент или элемент mask
SVG. Ознакомьтесь со всеми предоставляемыми возможностями в спецификации
по адресу: https://www.w3.org/TR/css-masking-1/.
А пока мы рассмотрим простой пример, чтобы вы могли оценить возможный
эффект и синтаксис.

Пример изображения-маски
У меня есть снимок Марса, сделанный NASA. Я бы и сам софотографировал, но
ехать далековато.
И предположим, что у нас также есть изображение в формате PNG, полностью
прозрачное, за исключением слова «MARS». Мы можем использовать этот PNGфайл как маску поверх первого изображения.

216

Глава 7. Потрясающая эстетика с помощью CSS

Вот что мы увидим в браузере:

Рис. 7.26. Изображение-маска

Вот соответствующая HTML-разметка:


А вот CSS:

.mask-image-example {
display: block;
height: 1024px;
width: 1024px;
margin: 0 auto;
mask-image: url('mars-text-mask.png');
}

Самая важная часть маски — это свойство mask-image, которое сообщает браузеру, что мы хотим использовать в качестве маски для элемента.
Кто-то из вас скажет, что такой же эффект достижим только в графическом
редакторе. Да, но как вам такое?
.mask-image-example {
display: block;
height: 1024px;
width: 1024px;
margin: 0 auto;
mask-image: url('mars-text-mask.png');
animation: moveMask 6s infinite alternate;
}

Свойство mix-blend-mode

217

@keyframes moveMask {
0% {
object-position: 0px 0px;
}
100% {
object-position: 100px 100px;
}
}

Мы добавили анимацию, которая перемещает фоновое изображение за маской,
так что слово «MARS» остается на месте, пока планета движется позади. Попробуйте сделать это в Photoshop!
Если мы захотим поменять местами объекты, чтобы маска двигалась, а изображение планеты оставалось на месте, нужно будет всего лишь поменять местами
значения object-position и mask-position.
Вы можете попрактиковаться с этим примером в файлах каталога example_07-11.
Имейте в виду, что вам может потребоваться добавить префиксы поставщиков
к свойству mask-image, как в примере кода, и запустить этот пример с локального
сервера. Для этого можете использовать BrowserSync.
Есть довольно много связанных свойств для свойства mask-image, которые
могут изменить способ работы маски. Если вам нужно решить что-то, связанное
с маской, обязательно ознакомьтесь со спецификациями.
Не знаю, как вы, но я уже измотан этим визуальным «кардио», через которое
мы только что прошли. Прежде чем вы потянетесь за полотенцем и бутылкой
с водой, я расскажу о свойстве mix-blend-mode.

Свойство mix-blend-mode
Свойство mix-blend-mode позволяет решить, как элемент должен «сливаться»
с элементом, поверх которого он находится.
Вот возможные режимы наложения: normal, multiply, screen, overlay, darken,
lighten, color-dodge, color-burn, hard-light, soft-light, difference, exclusion,
hue, saturation, color и luminosity.
Статические изображения не передают это свойство должным образом, поэтому рекомендую открыть пример из папки example_07-12 в браузере.
Мы используем изображение Марса из последнего примера, но установим его
в качестве фиксированного фона для элемента body.
Затем добавим текст сверху, который можно прокрутить, чтобы увидеть, как
действует mix-blend-mode. Мы используем overlay, потому что оно работает лучше всего. Если вы откроете пример вместе со своими инструментами разработчика, то увидите другие возможности. Уточню, что сами параметры будут иметь
разные эффекты в зависимости от переднего плана и фона, к которым они применяются.

218

Глава 7. Потрясающая эстетика с помощью CSS

Спецификация свойства mix-blend-mode — это спецификация Compositing and
Blending Level 1: https://www.w3.org/TR/compositing-1/#mix-blend-mode.

Итоги
Мы рассмотрели CSS-свойства, наиболее полезные для создания эстетически привлекательных элементов в отзывчивых веб-конструкциях. Узнали, как можно преодолеть зависимость от изображений с помощью градиентных фонов CSS.
Рассмотрели паттерны градиентных фонов, изучили порядок применения
текстовых теней для простого повышения привлекательности текста, а также теней
для блоков, которые можно добавлять снаружи и внутри элементов.
Также мы рассмотрели CSS-фильтры, позволяющие получить еще более впечатляющие визуальные эффекты с применением только кода CSS, и смогли объединить их для получения удивительных результатов.
В последней части главы мы обсудили создание эффектов маски с помощью
как изображений, так и свойства clip-path.
Наш инструментарий пополнился! Мы вернемся к CSS в главе 9. Но пока…
В следующей главе я собираюсь обсудить с вами масштабируемую векторную
графику (SVG, scalable vector graphics). Несмотря на то что это развитая технология с большой историей, она приспособлена к современной обстановке высокопроизводительных отзывчивых сайтов, фактически вступающих в свое совершеннолетие.

8

SVG и независимость
от разрешения

Об SVG (масштабируемой векторной графике) были и еще будут написаны целые
книги. Для отзывчивого веб-дизайна она предоставляет графические ресурсы
с четкой поточечной прорисовкой для экранов всех разрешений.
У используемых в интернете изображений форматов JPEG, GIF или PNG визуальные данные сохраняются в виде набора пикселов. Если сохранить графику
в любом из этих форматов с установкой ширины и высоты и увеличить изображение так, чтобы его исходные размеры были превышены в два и более раза, то тут
же проявятся присущие этим форматам ограничения.
Скриншот с фрагментом изображения в формате PNG, увеличенного на экране браузера, имеет следующий вид:

Рис. 8.1. Недостатки растровых изображений легко увидеть на современных экранах
с высокой четкостью

220

Глава 8. SVG и независимость от разрешения

Заметили, что в изображении явно присутствует мозаичность? А вот точно
такая же картинка, сохраненная как векторное изображение в SVG-формате и выведенная на экран с той же степенью увеличения:

Рис. 8.2. Изображение в формате SVG не теряет резкость независимо от размера дисплея

Разница очевидна.
При использовании SVG вместо JPEG, GIF или PNG мы получим графику, не
зависимую от разрешения и, в отличие от растровых изображений, требующую
файлов намного меньших размеров.
В этой главе коснемся множества аспектов, присущих SVG-графике, причем
основное внимание уделим ее интеграции в рабочий процесс и осветим возможности SVG-технологии.
Вот что мы рассмотрим:
y краткая история и анатомия простого SVG-документа;
y создание SVG-графики с помощью популярных пакетов и сервисов редактирования изображений;
y вставка объектов SVG-графики в страницу с помощью тегов img и object;
y вставка объектов SVG-графики в качестве фоновых изображений;
y вставка объектов SVG-графики непосредственно в код HTML в качестве
линейных объектов;
y повторное использование SVG-символов;
y ссылка на внешние SVG-символы;
y возможности, предоставляемые каждым из методов вставки;
y анимация объектов SVG-графики с помощью SMIL;
y стилевое оформление объектов SVG-графики с помощью внешних стилей;
y стилевое оформление объектов SVG-графики с помощью внутренних стилей;
y изменение и анимация объектов SVG-графики с помощью CSS;
y медиазапросы и SVG-графика;

Краткая история SVG

221

оптимизация объектов SVG-графики;
использование объектов SVG-графики для определения CSS-фильтров;
y манипуляция объектами SVG-графики с помощью JavaScript-кода и Java­
Script-библиотек;
y советы по внедрению SVG-технологии;
y ресурсы для дальнейшего изучения.
SVG-технология — предмет непростой. Какие разделы этой главы в большей
степени отвечают вашим потребностям, решать вам. Постараюсь сразу предложить
вам кратчайший путь ее освоения.
Если вам просто нужно заменить статичные графические ресурсы на сайте их
SVG-версиями для повышения резкости изображений и/или уменьшения размеров файлов, тогда обратитесь к разделам по использованию SVG в качестве
фоновых изображений и внутри тегов img.
Если вы интересуетесь приложениями и сервисами по созданию SVG-ресурсов
и управлению ими, сразу переходите к разделу «Создание SVG-графики с помощью
популярных пакетов и сервисов редактирования изображений».
А если хотите разобраться с SVG получше или управлять этой графикой, в том
числе с применением анимации, то вам лучше усесться поудобнее и запастись
двойной порцией любимого напитка, поскольку разговор будет долгим.
Приступая к освоению этой технологии, для начала заглянем в 2001 год.
y
y

Краткая история SVG
Первый релиз SVG состоялся в 2001 году. И это не опечатка. SVG как технология
существует с 2001 года. С тех пор она постепенно развивалась, но интерес к ней
возник с появлением экранов высокого разрешения. Введение в SVG-технологию
изложено в ее спецификации версии 1.1 (http://www.w3.org/TR/SVG11/intro.html):
SVG — это язык описания двухмерной графики в XML [XML10]. SVG позволяет создавать три типа графических объектов: фигуры векторной графики (например, пути, состоящие из прямых и кривых линий), изображения
и текст.
Судя по названию технологии, SVG позволяет дать в коде описание двухмерных
изображений в виде векторных опорных точек. Это открывает для нее широкие
перспективы по созданию значков, прорисовке линий и схем.
Поскольку векторы задаются с помощью относительных величин, их можно
масштабировать без потери качества до любых размеров. Более того, так как данные SVG-графики представлены в виде векторных опорных точек, их объем получается мизерным по сравнению с объемами файлов форматов JPEG, GIF или PNG,
содержащих изображения сопоставимых размеров.

222

Глава 8. SVG и независимость от разрешения

Кроме того, в настоящее время SVG-графика пользуется широкой поддержкой
браузеров. Ее в числе прочих поддерживают Android, начиная с версии 2.3, и Internet Explorer версии 9 и выше (http://caniuse.com/#search=svg).

Изображение — считываемый
веб‑документ
При просмотре кода изображения в текстовом редакторе понять что-либо обычно
невозможно.
А вот SVG-графика записывается на XML (extensible markup language — расширяемом языке разметки) — близком родственнике HTML. Возможно, вы не
в курсе, но XML повсеместно используется в интернете. Приходилось ли вам
пользоваться RSS-каналом? А ведь в нем также используется XML. Именно в этом
языке заключается содержимое RSS-канала, обеспечивая его доступность для
разнообразных средств и сервисов.
Поэтому читать и понимать SVG-графику могут не только машины, но и мы
с вами.
Посмотрите на изображение звезды.

Рис. 8.3. Простое изображение в формате SVG

Это SVG-изображение можно найти в файле Star.svg в каталоге example_08-01.
Файл можно открыть как в браузере, на экране которого он появится в виде звезды, так и в текстовом редакторе, где виден код, формирующий эту звезду. Рассмотрим код:



223

xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"


Star 1
Created with Sketch.






И это все, что нужно для создания звезды в SVG.
Вы спросите: «Зачем все это нужно?» Если требуется всего лишь получить
отображение векторной графики на веб-странице, просматривать этот код действительно не имеет смысла. Нужно взять такой код из приложения, где сохранены результаты векторного творчества в формате SVG.
Список таких приложений дам чуть позже. Это, конечно, станет началом работы с SVG-графикой из графических редакторов. А вот понимание взаимодействия
SVG-компонентов и освоение способов вмешательства в их совместную работу,
несомненно, пригодится, когда вам нужно будет работать с SVG-графикой и получать на ее основе эффекты анимации.
Поэтому разберемся в SVG-разметке и постараемся понять, что происходит
при ее выводе на экран. Обратите внимание на ключевые моменты.

Корневой элемент SVG
У корневого SVG-элемента есть атрибуты ширины (width), высоты (height) и области просмотра (viewbox):



Свойства и значения SVG внутри CSS
Обратите внимание на свойство stroke в предыдущем блоке кода. Это свойство
не CSS, а SVG. Есть довольно много специализированных свойств SVG, которые
можно использовать в стилях (не важно, где они объявлены, во встроенном коде
или во внешней таблице стилей). Например, для SVG указывается не backgroundcolor, а fill, а вместо border указывается stroke-width.

Полный перечень специализированных свойств SVG можно найти в спецификации по адресу: http://www.w3.org/TR/SVG/styling.html.

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

Анимация SVG-графики с помощью CSS
Рассмотрим небольшой пример добавления в SVG CSS-анимации (эти стили могут так же легко оказаться во внешней таблице стилей). Возьмем пример со звездой и заставим ее вращаться. Полный код можно найти в каталоге example_08-07:


Star 1















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

Заметили, что SVG-элементу была назначена исходная точка преобразования
50% 50%? Дело в том, что, в отличие от CSS, по умолчанию исходная точка преобразования в SVG не устанавливается как 50% 50% (по центру обеих осей),
а имеет значение 0 0 (в левом верхнем углу). Если не установить это свойство,
звезда будет вращаться вокруг точки сверху слева.

244

Глава 8. SVG и независимость от разрешения

Используя CSS в анимации SVG-графики, вы можете зайти довольно далеко (если не волноваться о поддержке Internet Explorer). Но если вам нужно добавить интерактивность, поддержку Internet Explorer или синхронизировать ряд
событий, используйте JavaScript. Хорошей новостью является наличие большого
количества библиотек, существенно облегчающих анимацию SVG-графики. А теперь рассмотрим примеры.

Анимация SVG-графики с помощью
JavaScript
Когда SVG-графика вставлена в тег object или непосредственно в код страницы, появляется возможность работать с SVG-графикой через JavaScript. Средствами
JavaScript можно изменить класс самого SVG-элемента или элемента, в который заключена SVG-графика. Это должно инициировать запуск CSS-анимации, например:
svg {
/* нет анимации */
}
.added-with-js svg {
/* есть анимация */
}

Также можно применить эффект анимации к SVG-графике с помощью Java­
Script.
Если анимации подвергаются один или два элемента независимо друг от друга,
то написанный для этого вручную код JavaScript существенно облегчит задачу.
Но если нужно подвергнуть анимации большое количество элементов или синхронизировать анимацию элементов с применением шкалы времени, то реальную
помощь в этом могут оказать библиотеки JavaScript. Вам решать, насколько оправданным окажется утяжеление страницы за счет включения в нее библиотеки.
Для придания эффектов анимации SVG-графике посредством JavaScript хочу
порекомендовать вам анимационные платформы GreenSock (http://greensock.com),
Velocity.js (http://julian.com/research/velocity/) и Snap.svg (http://snapsvg.io/). Далее
мы рассмотрим очень простой пример использования GreenSock.

Простой пример анимации SVG-графики с помощью
GreenSock
Чтобы создать интерфейс с круглой шкалой и анимацией по щелчку на кнопке от
нулевой позиции до позиции, задаваемой вводимым значением, нужно не только
подвергнуть анимации продвижение по круглой шкале как по длине, так и по цвету, но и вывести число от нуля до вводимого значения. Полный код реализации
можно найти в каталоге example_08-08.

Анимация SVG-графики с помощью JavaScript

245

Если будет введено значение 75 и нажата кнопка Animate!!, круглая шкала будет
заполнена и возникнет следующая картина:

Рис. 8.10. Библиотеки анимации упрощают анимирование SVG-графики

Вместо демонстрации всего кода JavaScript-файла, в котором есть комментарии,
рассмотрим только ключевые моменты, чтобы побудить вас изучить его само­
стоятельно.
Окружность создана в виде SVG-тега , ане элемента . Путь можно подвергнуть анимации с помощью технологии stroke-dashoffset. Краткое изложение этой технологии представлено на следующей врезке. Используем JavaScript
для измерения длины пути, а затем применим атрибут stroke-dasharray для указания длины выводимой на экран части окружности и длины пустого промежутка.
Затем используем stroke-dashoffset для изменения места старта dasharray.
Так мы запустим вне пути и анимируем обводку пути по контуру. Это создаст
иллюзию, что путь прорисовывается.
Если бы значение для анимации dasharray было известным статичным значением, такого же эффекта можно было бы относительно легко достичь с помощью
CSS-анимации путем проб и ошибок (более подробно CSS-анимация будет рассмотрена в следующей главе). Но вдобавок к динамическому значению одновременно с прорисовкой линии нужны постепенное повышение яркости цвета от
одного значения к другому и визуальный подсчет до введенного значения, выполняемый в текстовом узле. Средство GreenSock существенно облегчает задачу —
в анимационной части оно не будет похлопывать вас по голове или поглаживать
по животу, хотя может при необходимости выполнить обратный отсчет от 10 000.
Вот строки кода JavaScript, необходимые, чтобы заставить GreenSock выполнить
все три задачи:
// Анимация прорисовки линии и изменения цвета
TweenLite.to(circlePath, 1.5, {
'stroke-dashoffset': '-' + amount,
stroke: strokeEndColour,
});
// Установка счетчика на нуль и его анимация до введенного значения
var counter = {var: 0};
TweenLite.to(counter, 1.5, {
var: inputValue,

246

Глава 8. SVG и независимость от разрешения

onUpdate: function() {
text.textContent = Math.ceil(counter.var) + '%';
},
ease: Circ.easeOut,
});

По сути, функции TweenLite.to() передают, что нужно подвергнуть анимации,
время, за которое эта анимация должна осуществиться, а затем значения, которые
нужно изменить (и то, что в них нужно изменить).
Сайт GreenSock содержит отличную документацию и поддерживает форумы,
и, если вам понадобится одновременно синхронизировать целый ряд анимаций,
выберите день в рабочем расписании и ознакомьтесь с GreenSock.

SVG-технология прорисовки линий была описана в доступной форме журналом
Polygon, когда Vox Media анимировала несколько прорисовок линий в игровых
консолях Xbox One и Playstation. Прочитать ее можно здесь: http://product.voxmedia.
com/2013/11/25/5426880/polygon-feature-design-svg-animations-for-fun-and-profit.
Более основательное объяснение этой технологии представил Джейк Арчибальд (Jake Archibald): http://jakearchibald.com/2013/animated-line-drawing-svg/.

Оптимизация SVG
Как добросовестные разработчики, мы хотим обеспечить наименьший объем своих
ресурсов. Проще всего это сделать с SVG-графикой и средствами анимации, оптимизирующими составляющие SVG-документов. Кроме удаления элементов (например, заголовков и описаний) они позволяют выполнять множество микрооптимизаций, которые в сумме делают SVG-активы компактнее. В настоящее время
для решения этих задач есть средство SVGO (https://github.com/svg/svgo).
Если вы еще не пользовались SVGO, рекомендую сначала познакомиться
с SVGOMG (https://jakearchibald.github.io/svgomg/). Это версия SVGO, основанная
на применении браузера, позволяющая переключать дополнительные модули
оптимизации и получать немедленную реакцию в виде сохраненного файла. По­
мните пример SVG-разметки звезды в начале главы? В исходном виде этот SVGдокумент занимает 489 байт. Пропустив его через SVGO, вы уменьшите его размер
до 218 байт, оставив на месте viewBox. И сэкономите 55,42 % объема документа.
При нескольких SVG-изображениях такая экономия может вылиться в солидный
результат. Оптимизированная SVG-разметка имеет следующий вид:


Использование SVG в качестве фильтров

247




Благодаря популярности SVGO этим средством пользуются и другие SVGсредства. Например, ранее упомянутое средство Iconizr (http://iconizr.com/) перед
созданием ресурсов по умолчанию прогоняет SVG-файлы через SVGO, избавляя
вас от ненужной двойной оптимизации.

Использование SVG в качестве фильтров
В главе 7 мы рассмотрели эффекты, создаваемые фильтрами CSS. Но в настоящее
время в старых браузерах, таких как Internet Explorer 10 и 11, они не поддерживаются. Если вы попытаетесь воспользоваться в этих браузерах эффектами фильтров, то ничего, кроме досады, не испытаете.
К счастью, с помощью SVG можно создавать фильтры, работающие в Internet
Explorer 10 и 11, но все не так просто. Например, в каталоге example_08-05 есть
страница, в теле которой содержится следующая разметка:


Это фотография королевы Великобритании. Изначально она имеет следующий
вид:

Рис. 8.11. Изображение без SVG-фильтров

248

Глава 8. SVG и независимость от разрешения

В этом же каталоге содержится SVG-документ с фильтром, определенным
в элементах defs. Разметка SVG имеет следующий вид:









Внутри фильтра сначала задается поворот тона на 90° с помощью feColorMatrix,
а затем этот эффект через атрибут result передается следующему фильтру
(feGaussianBlur) со значением размытия, равным 6. Сразу предупреждаю, что
задал слишком жесткие параметры в ущерб эстетическому восприятию намеренно, чтобы у нас не осталось сомнений, что эффект работает!
Теперь вместо добавления этой SVG-разметки к HTML мы можем сослаться
на нее, используя тот же синтаксис CSS-фильтра, который уже видели в предыду­
щей главе:
.HRH {
filter: url('filter.svg#myfilter');
}

В популярных браузерах (Chrome, Safari, Firefox) будет получен следующий эффект:

Рис. 8.12. Изображение с SVG-фильтром

Использование SVG в качестве фильтров

249

К сожалению, этот метод не работает в Internet Explorer 10 и 11. Но есть другой
способ достижения этой цели: используем собственный элемент image SVGдокумента, предназначенный для включения изображения в этот документ. В файле в каталоге example_07-06 содержится следующая разметка:










Здесь SVG-разметка очень похожа на внешний фильтр filter.svg из предыдущего примера, но с добавлением атрибутов height, width и viewbox. Кроме того,
изображение, к которому мы хотим применить фильтр, является единственным
содержимым SVG-документа за пределами элемента defs. Для ссылки на фильтр
используется атрибут filter и передается идентификатор того фильтра, который
мы хотим использовать (в данном случае из внутреннего содержимого расположенного выше элемента defs).
Хотя над этим подходом придется поработать, он дает множество разнообразных эффектов, предоставляемых SVG-технологией, даже в версиях 10 и 11 Internet Explorer.

250

Глава 8. SVG и независимость от разрешения

Медиазапросы внутри SVG
Все браузеры, понимающие SVG-документы, должны учитывать определяемые
внутри этих документов медиазапросы CSS. Но при работе с медиазапросами внутри SVG-документов следует помнить о некоторых особенностях.
Рассмотрим медиазапрос, вставленный в SVG-документ следующим образом:


Этот документ выводит на странице SVG-графику шириной 200 px, в то время
как окно просмотра имеет ширину 1200 px.
Предполагается, что обводка звезды по контуру будет лиловой (violet) при
ширине экрана не меньше 800 px. На это настроен медиазапрос. Но когда SVGграфика помещается на страницу посредством тегов img, object или в качестве
фонового изображения, то окружающий HTML-документ в расчет не берется.
В данной ситуации min-width означает минимальную ширину самой SVG-графики.
Поэтому SVG-фигура отобразится на странице шириной не менее 800 px, но без
лиловой обводки по контуру.
Если же SVG-документ вставляется непосредственно в код страницы, он «сливается» с окружающим HTML-документом. Медиазапрос с min-width принимает
решение о своем соответствии ситуации, ориентируясь на параметры окна просмотра (так же, как в HTML).
Чтобы заставить один и тот же медиазапрос вести себя всегда одинаково, можно придать ему следующий вид:
@media (min-device-width: 800px) {
#star_Path {
stroke: violet;
}
}

Тогда независимо от размера SVG-графики или способа ее вставки на страницу он будет брать в расчет ширину экрана устройства (точнее, окна просмотра).

Итоги

251

Советы по внедрению
Мы почти добрались до конца главы, хотя о технологии SVG можно говорить
долго. Поэтому сейчас будут не связанные друг с другом соображения. Им не обязательно давать развернутое толкование, но я перечислю их здесь в форме советов,
чтобы вы сэкономили час-другой на поиске в Stack Overflow:
y Если не требуется придавать SVG-графике эффект анимации, остановите
свой выбор на спрайте изображения или таблице стилей с указанием на URI
данных. Вам будет намного проще предоставить альтернативные ресурсы,
и они обеспечат лучшую производительность.
y Автоматизируйте как можно больше шагов по созданию ресурса, тем самым
вы уменьшите количество допускаемых ошибок и быстрее получите предсказуемый результат.
y Для вставки в проект статичных SVG-объектов постарайтесь выбрать единый способ (спрайт изображения, URI данных или включение непосредственно в код страницы). Получение одних активов одним способом, а других — другим может стать обременительным занятием, равно как
и дальнейшая поддержка различных реализаций.
y Универсального варианта SVG-анимации нет. Чтобы получить простые
эффекты анимации, используйте CSS. Для включения сложных интерактивных эффектов анимации, ход которых меняется по шкале времени и которые работают в Internet Explorer, освойте библиотеку, например GreenSock,
Velocity.js или Snap.svg.

Итоги
Это была насыщенная глава. Мы рассмотрели большой объем информации, важной для понимания SVG-графики и ее внедрения в отзывчивые веб-приложения.
Изучили различные графические приложения и онлайн-решения, доступные для
создания SVG-ресурсов, и подробно рассмотрели способы их вставки, а также
особенности браузеров, которые следует брать в расчет.
Узнали, как ссылаться на внешние таблицы стилей и повторно использовать
SVG-символы. Посмотрели, как создаются фильтры, использующие SVG, обладающие более широкой поддержкой по сравнению с фильтрами CSS. Узнали, как
на них сослаться и использовать их в CSS.
И наконец, рассмотрели способы использования библиотек JavaScript для
анимации SVG-графики, а также изучили методы оптимизации SVG-графики
с помощью средства SVGO.

252

Глава 8. SVG и независимость от разрешения

В следующей главе мы рассмотрим CSS-переходы, преобразования и анимацию.
Ее стоит изучить и в контексте SVG-графики, поскольку многие синтаксические
примеры и технологии могут использоваться применительно к SVG-документам.
Итак, запаситесь каким-нибудь горячим напитком (вы его заслужили) и продолжайте чтение.

Дополнительные ресурсы
В начале главы я сказал, что у меня нет ни места, ни достаточного объема знаний,
чтобы рассказать о SVG все. Поэтому покажу вам ресурсы, дающие более глубокий
и более широкий взгляд на эту тему:
y SVG Essentials, второе издание, Дж. Дэвида Эйсенберга (J. David Eisenberg)
и Амелии Беллами-Роудс (Amelia Bellamy-Royds) (http://shop.oreilly.com/
product/0636920032335.do);
y A Guide to SVG Animations (SMIL) Сары Сьюайден (Sara Soueidan) (http://
css-tricks.com/guide-svg-animations-smil/);
y Media Queries inside SVGs Test Жереми Патонье (Jeremie Patonnier) (http://
jeremie.patonnier.net/experiences/svg/media-queries/test.html);
y An SVG Primer for Today's Browsers (http://www.w3.org/Graphics/SVG/IG/resources/
svgprimer.html);
y Understanding SVG Coordinate Systems and Transformations (Part 1) Сары
Сьюайден (Sara Soueidan) (http://sarasoueidan.com/blog/svg-coordinate-systems/);
y Hands On: SVG Filter Effects (http://ie.microsoft.com/testdrive/graphics/hands-oncss3/hands-on_svg-filter-effects.htm);
y Full set of SVG tutorials Якоба Женкова (Jakob Jenkov) (http://tutorials.jenkov.
com/svg/index.html).

9

Переходы,
преобразование
и анимация

Исторически сложилось, что перемещение элементов по экрану или применение
к ним эффектов анимации было прерогативой JavaScript. Сегодня с основной частью задач по перемещению могут справиться CSS-переходы (transitions), CSSпреобразования (transforms) и CSS-анимации (animations).
Чтобы разобраться, за что отвечают переходы, преобразования и анимации,
рассмотрим их упрощенное описание:
y CSS-переход определяет, как одно визуальное состояние должно переходить
в другое.
y CSS-преобразование обеспечивает визуальное преобразование одного элемента, не оказывая влияния на другие элементы на странице. Например,
«сделать элемент вдвое больше» или «переместить элемент на 100 px вправо» — это простые текстовые описания задач, которые можно решить с помощью CSS-преобразований. Однако преобразование не контролирует, КАК
элемент меняет состояние, это работа CSS-перехода.
y CSS-анимация применяет к элементу серию изменений с различными ключевыми точками, которые определены единицами измерения времени.
Если пока различия между ними кажутся немного расплывчатыми, надеюсь,
к концу главы они станут более явными.
В этой главе будут рассмотрено:
y что такое CSS-переходы и как ими можно воспользоваться;
y как создать код CSS-перехода и что собой представляет его сокращенный
синтаксис;
y что такое функции развития процесса CSS-перехода во времени (ease, cubicbezier и т. д.);
y что такое CSS-преобразования и как ими можно воспользоваться;
y что представляют собой различные 2D-преобразования (scale, rotate, skew,
translate и т. д.);

254

Глава 9. Переходы, преобразование и анимация

что такое 3D-преобразования;
как средствами CSS осуществлять анимацию с помощью keyframes.
Начнем со знакомства с CSS-переходами.
y
y

Что такое CSS-переходы и как ими можно
воспользоваться
Переход между двумя состояниями является простейшим способом создания визуального эффекта с помощью CSS. Рассмотрим простой пример перехода элемента из одного состояния в другое при прохождении над ним указателя мыши.
При стилевом оформлении гиперссылок в CSS сложилась практика создания
состояния, при котором на элемент наведен указатель мыши, чтобы пользователь
знал, что с элементом можно взаимодействовать. Состояния наведения указателя,
конечно, не связаны с сенсорными экранами, но для тех, кто пользуется мышью,
они необходимы. Проиллюстрируем переходы на их примере.
Традиционно при использовании только кода CSS, если указатель мыши находится над элементом, CSS-правила могут только включаться или выключаться.
У элемента есть исходный набор свойств и значений, но, когда указатель проходит
над элементом, свойства и значения изменяются.
Должен предупредить вас о двух важных обстоятельствах. Во-первых, переход
от состояния display: none; невозможен. Если для элемента установлено состоя­
ние display: none;, то отсутствует не только его прорисовка на экране, но и реальное состояние, с которого можно осуществить переход.
Хотя нельзя осуществить переход от состояния display: none, можно запустить
анимацию для элемента одновременно с изменением его свойства display. Так,
например, вы можете с помощью анимации изменить прозрачность элемента
с 0 %, изменив его свойство display: none на другое. Мы рассмотрим анимацию позже в данной главе.

Чтобы создать процесс постепенного появления элемента, задайте переход
в отношении непрозрачности или позиции элемента. Во-вторых, не все свойства
подвергаются переходам. Убедитесь, что вы не пытаетесь добиться невозможного,
обратившись к перечню доступных для перехода свойств: https://developer.mozilla.
org/en-US/docs/Web/CSS/CSS_animated_properties.

Старые версии спецификаций включали список анимируемых свойств. Вы все
еще можете просмотреть старую версию спецификации по адресу: https://www.
w3.org/TR/2017/WD-css-transitions-1-20171130/#animatable-properties, но она, скорее
всего, будет неполной.

Что такое CSS-переходы и как ими можно воспользоваться

255

Откройте файл из каталога example_09-01. В контейнере nav есть несколько
ссылок. Разметка имеет такой вид:

link1
link2
link3
link4
link5


А вот соответствующий ей код CSS:
a {
font-family: sans-serif;
color: #fff;
text-indent: 1rem;
background-color: #ccc;
display: inline-flex;
flex: 1 1 20%;
align-self: stretch;
align-items: center;
text-decoration: none;
transition: box-shadow 1s;
}
a + a {
border-left: 1px solid #aaa;
}
a:hover {
box-shadow: inset 0 -3px 0 #cc3232;
}

И два состояния: первое — исходное:

Рис. 9.1. Две ссылки в исходном состоянии

И второе — hover:

Рис. 9.2. При наведении ссылка становится подчеркнутой

Обычно проведение указателя мыши над ссылкой переводит ее из первого состояния (без красной линии) во второе (с красной линией) по принципу включения-выключения. Но эта строка:
transition: box-shadow 1s;

256

Глава 9. Переходы, преобразование и анимация

добавит к box-shadow переход от обычного состояния к состоянию hover за одну
секунду.

В предыдущем примере кода CSS можно заметить соседний родственный комбинатор +. Такой селектор был изучен в главе 6. Заключенные в него стили будут
применены в том случае, если за одним выбранным элементом (в нашем случае
a) сразу следует другой выбранный элемент (еще один a). Здесь этот селектор
применяется, поскольку левая граница у первого элемента нам не нужна.

Свойство transition применяется в CSS к исходному состоянию элемента, а не
к тому состоянию, в котором он окажется. Мы добавили свойство transition и его
значения к элементу в его исходном состоянии, а не в состоянии hover. Мы могли
бы добавить transition к состоянию hover, если бы переход осуществлялся из
состояния hover к исходному состоянию. Различные состояния, такие как :active,
:focus, :hover и пр., также могут иметь различные стилевые установки и подвергаться переходу.

Свойства перехода
При объявлении перехода можно воспользоваться четырьмя свойствами:
y transition-property — CSS-свойство, подвергаемое переходу (например,
background-color, text-shadow или all для перехода всевозможных свойств);
y transition-duration — время, за которое должен произойти переход (определенное в секундах, например .3s, 2s или 1.5s);
y transition-timing-function — порядок изменения скорости в процессе
перехода (например, ease, linear, ease-in, ease-out, ease-in-out или cubicbezier);
y transition-delay — дополнительное значение для указания задержки перед
началом перехода. Отрицательное число выражает немедленное начало
перехода с того момента, до которого переход дошел бы за указанное время.
Определяется в секундах, например .3s, 1s или 2.5s.

Любую продолжительность, определенную в секундах с помощью единицы s
в CSS, можно указывать в миллисекундах, например вместо .5s писать 500ms.
Это вопрос предпочтений, но для предсказуемости советую вам выбрать один из
способов написания и придерживаться его на протяжении всего проекта.

Используемые по отдельности свойства могут быть задействованы для создания
следующего перехода:

Что такое CSS-переходы и как ими можно воспользоваться

257

.style {
/*...(дополнительные стилевые настройки)...*/
transition-property: all;
transition-duration: 1s;
transition-timing-function: ease;
transition-delay: 0s;
}

Краткая форма записи перехода с помощью
свойства transition
Показанные ранее отдельные объявления можно свести в одну краткую форму:
transition: all 1s ease 0s;

При записи краткой формы первое значение, связанное со временем, всегда
применяется для свойства transition-duration. Второе значение, также связанное
со временем, относится к свойству transition-delay. Я склоняюсь к использованию
именно сокращенной формы, поскольку обычно мне нужно лишь определить продолжительность перехода и те свойства, к которым он должен быть применен.
Более того, сокращенный синтаксис легче в написании, так как вы можете
обойтись без отдельного указания свойства, которое хотите передать, и продолжительности перехода. Чтобы проиллюстрировать это, покажу вам переход от
одного цвета фона к другому продолжительностью более 2 секунд:
transition: background-color 2s;

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

Переходы различных свойств за разные периоды
Когда в правиле содержатся несколько объявленных свойств, то не обязательно
реализовывать их переходы за одно и то же время. Рассмотрим следующее правило:
.style {
/* ... (дополнительные стилевые настройки)... */
transition-property: border, color, text-shadow;
transition-duration: 2s, 3s, 8s;
}

258

Глава 9. Переходы, преобразование и анимация

Здесь с помощью объявления transition-property указаны свойства, подвергаемые переходу: border, color и text-shadow. А затем с помощью объявления
transition-duration указано, что свойство border будет подвергнуто переходу за
две секунды, color — за три секунды, а text-shadow — за восемь секунд. Продолжительности переходов, разделенные запятыми, написаны в порядке указания
подвергаемых переходу свойств, при перечислении которых в качестве разделителей также использованы запятые.
Также можно использовать запись с сокращенным синтаксисом, что, по мне,
более предпочтительно:
.style {
transition: border 2s, color 3s, text-shadow 8s;
}

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

Функции развития процесса перехода
по времени
Понять при объявлении перехода, что такое свойства, продолжительность и задержка, нетрудно. Но вот понять, что делает каждая функция развития процесса
перехода по времени, намного труднее. Чем же занимаются ease, linear, ease-in,
ease-out, ease-in-out и cubic-bezier? Каждая из них фактически является пред­
определенной кривой Безье третьего порядка (cubic-bezier curve) и, по сути, аналогична функции плавности. То есть является математическим описанием того,
как должен выглядеть процесс перехода. Увидеть эти кривые можно здесь: http://
cubic-bezier.com/ и http://easings.net.
На обоих сайтах вы можете сравнить такие функции и определить различия,
вносимые каждой из них в процесс перехода. Вот скриншот сайта http://easings.net,
где можно навести указатель мыши на каждую линию для демонстрации функции
плавности (рис. 9.3).
Но даже если вы способны записать собственную cubic-bezier вслепую, на
практике это мало что изменит. Причина, как и в случае со многими другими
услож­нениями, заключается в том, что при применении эффектов переходов нужно проявлять сдержанность. Переходы, длящиеся слишком долго, создают впечатление заторможенности сайта. К примеру, навигационные ссылки с переходами
по пять секунд способны скорее навредить работе сайта, чем впечатлить пользо-

Функции развития процесса перехода по времени

259

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

Рис. 9.3. Сайт easings.net предоставляет удобную визуализацию функций развития
процесса перехода по времени

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

РАЗВЛЕЧЕНИЕ С ПЕРЕХОДАМИ НА ОТЗЫВЧИВЫХ САЙТАХ
Бывало ли у вас в детстве такое, что один из родителей куда-то уезжал на целый
день, а другой, чтобы завоевать ваше расположение, говорил что-нибудь вроде:
«Пока мамы (папы) нет дома, мы будем сыпать сахар во все сухие завтраки, но
ты должен пообещать, что не скажешь об этом, когда она (он) вернется»? Каюсь,
я тоже проделывал нечто подобное со своими малышами. Когда никто не видит,
можно немного порезвиться. Итак, не советую внедрять его в серьезные приложения, но попробуйте следующий код в своем проекте по разработке отзывчивого веб-приложения:
* {
transition: all 1s;
}

260

Глава 9. Переходы, преобразование и анимация

Универсальный CSS-селектор * выбирает абсолютно все, а затем устанавливается переход всех свойств за одну секунду (1s). Поскольку функция развития процесса перехода по времени не указана, то по умолчанию станет использоваться
ease, а задержки не будет, так как по умолчанию у нее нулевое значение. Каков
будет эффект? Попробуйте изменить размер окна вашего браузера, и почти все,
что в нем находится (ссылки, состояния прохода указателя мыши и т. п.), будет
вести себя вполне предсказуемо. Но, поскольку переходы касаются всего, в том
числе правил внутри медиазапросов, при изменении размеров окна элементы
перейдут из одного состояния в другое. Важно ли это? Конечно, нет! Смешно
наблюдать за этим и развлекаться? Конечно, да! А теперь уберите это правило,
пока мама не увидела.

Хорошо, надеюсь, с переходами разобрались. Теперь немного повеселимся
и научимся перемещать элементы по экрану с помощью преобразований. Это очень
легко. Сделаем преобразования в форматах 2D и 3D. Начнем с 2D, и если наш
пример станет немного плоским (видите, что я там делал? Нет? Я увижу себя со
стороны), тогда мы перейдем к 3D.

2D-преобразования в CSS
Несмотря на схожесть названий, CSS-преобразования (transforms) не имеют ничего общего с CSS-переходами (transitions). Как мы уже узнали, переходы отвечают за процесс перетекания одного состояния в другое. Преобразования же определяют, какое состояние приобретет элемент.
Лично я запоминаю разницу абсолютно по-детски: представляю себе роботатрансформера, например Оптимуса Прайма. Когда он превращается в грузовик —
это преобразование. Но фаза между роботом и грузовиком является переходом (переходит из одного состояния в другое). Если Оптимус Прайм вам незнаком,
забудьте, что я написал выше. Надеюсь, когда мы перейдем к примерам, все станет
ясно.
Доступны две группы CSS-преобразований: 2D и 3D. 2D-варианты проще, поэтому начнем с них. Модуль CSS 2D Transforms позволяет использовать следующие преобразования:
y scale — масштабирует элемент (увеличивает его или уменьшает);
y translate — перемещает элемент по экрану (вверх, вниз, влево и вправо);
y rotate — поворачивает элемент на определенную величину, указанную
в градусах или оборотах;
y skew — наклоняет элемент по его координатам x и y;
y matrix — позволяет выполнять перемещения и придавать форму преобразованиям различными способами.

2D-преобразования в CSS

261

Важно, что преобразования осуществляются вне процесса формирования документа. Преобразование одного элемента не влияет на позицию другого элемента, не являющегося ему дочерним. Это существенно отличает преобразование от
добавления перехода к элементу при изменении поля, высоты или другого свойства,
допускающего переход или анимацию.
В каталоге example_09-09 вы увидите два предложения. Первое имеет запись
margin-left: 10px, примененную к слову с полужирным начертанием «item» при
наведении, а второе имеет запись transform: translateX (10px), примененное к тому
же слову при наведении. Оба имеют переход продолжительностью в 1 секунду.
В исходном состоянии они выглядят так:

Рис. 9.4. Два предложения в исходном состоянии

Наведите курсор на «item» в первом абзаце. Заметили, как переместился текст?

Рис. 9.5. При наведении курсора на первое предложение к элементу «item»
применяется поле, и весь текст после него тоже перемещается

Теперь наведите курсор на «item» во втором абзаце. Заметили, как движется
это слово? Остальные слова не двигаются.

Рис. 9.6. Во втором предложении слово «item» преобразуется, перемещаясь вправо,
при этом преобразование не затрагивает другие слова

Таким образом, преобразования, будь то 2D или 3D, не влияют на поток документа.

262

Глава 9. Переходы, преобразование и анимация

Попробуем применить различные 2D-преобразования, которые можно посмотреть в действии, открыв в браузере файл из каталога example_09-02. Здесь, чтобы
вы могли лучше разобраться со всем, что происходит, ко всем преобразованиям
применяются переходы.

Масштабирование (scale)
Для масштабирования используется следующий синтаксис:
.scale:hover {
transform: scale(1.4);
}

Проход указателя мыши над ссылкой, имеющей класс scale, вызовет такой
эффект:

Рис. 9.7. Можно масштабировать элементы, уменьшая или увеличивая их размер

Мы указываем браузеру при наведении на элемент указателя мыши увеличить
этот элемент в 1,4 раза.
Использование значений меньше единицы приведет к сжатию элементов. Следующий код приведет к сжатию элемента до половины его размера:
transform: scale(0.5);

Перемещение (translate)
Для перемещения используется следующий синтаксис:
.translate:hover {
transform: translate(-20px, -20px);
}

В нашем примере это правило приведет к следующему эффекту:

Рис. 9.8. Свойство translate позволяет перемещать элемент куда угодно по осям x и y

2D-преобразования в CSS

263

Свойство translate дает команду браузеру перемеcтить элемент на расстояние,
определяемое длиной (например, vw, px, % и т. д.). Первое значение относится
к перемещению по оси x, второе — по оси y. Положительные значения, заданные
в скобках, приводят к перемещению элемента вправо или вниз, а отрицательные —
соответственно, влево или вверх.
Если передается только одно значение, то оно применяется к оси x.
Если нужно указать для перемещения элемента значение только для одной оси,
можно использовать объявления translateX(-20px), что в данном случае приведет
к перемещению элемента влево на 20 px, или translateY(-20px), что в данном
случае приведет к перемещению элемента вверх на 20 px.

Использование translate для центрирования элементов с абсолютным
позиционированием
translate предоставляет удобный способ центрирования элементов с абсолютным

позиционированием внутри контейнера с относительным позиционированием.
Пример кода находится в каталоге example_09-03.
Рассмотрим разметку:




И этот код CSS:
.outer {
position: relative;
height: 400px;
background-color: #f90;
}
.inner {
position: absolute;
height: 200px;
width: 200px;
margin-top: -100px;
margin-left: -100px;
top: 50%;
left: 50%;
}

Возможно, вам уже приходилось делать нечто подобное. Когда известны размеры элемента с абсолютным позиционированием (в данном случае 200 px × 200 px),
для «подталкивания» элемента обратно в центр можно воспользоваться отступами с отрицательными значениями. А как включить содержимое и насколько высоким оно окажется?
Добавим к внутреннему блоку произвольное содержимое.

264

Глава 9. Переходы, преобразование и анимация

Рис. 9.9. Текст, выходящий за пределы контейнера, можно исправить с помощью
преобразования

Очевидно, возникла проблема. Разберемся с этим беспорядком с помощью
transform:
.inner {
position: absolute;
width: 200px;
background-color: #999;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}

И вот результат:

Рис. 9.10. Интеллектуальное приложение преобразования позволяет избежать
проблем с выходом текста за границы отведенного пространства

2D-преобразования в CSS

265

Здесь top и left позиционируют блок внутри контейнера таким образом, что
вначале левый верхний угол внутреннего блока находится в точке 50 % длины
и 50 % высоты контейнера. Объявление transform работает в отношении внутреннего блока и позиционирует его в обратную сторону по этим осям на половину (-50%) его собственной ширины и высоты. Превосходно!

Поворот (rotate)
Преобразование rotate позволяет поворачивать элемент. Для него используется
следующий синтаксис:
.rotate:hover {
transform: rotate(30deg);
}

А в окне браузера произойдет следующее:

Рис. 9.11. Преобразования позволяют легко поворачивать элементы

Значение в скобках всегда представляет угол поворота. Угол может выражаться в градусах, градианах, радианах и оборотах. Я предпочитаю градусы (например,
90deg). Положительные значения задают поворот по часовой стрелке, а отрицательные — против часовой стрелки.
Задайте угол больше, чем полный оборот, и элемент будет продолжать поворачиваться, пока не достигнет нужного угла. Если задать элементу поворот на
следующее значение:
transform: rotate(3600deg);

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

Наклон (skew)
Если вам приходилось работать в программе Photoshop, то наклон элемента по какой-либо из его осей или двум осям сразу вы уже представляете. Вот код примера:
.skew:hover {
transform: skew(40deg, 12deg);
}

266

Глава 9. Переходы, преобразование и анимация

Установка этого правила для ссылки с псевдоклассом hover приведет при наведении указателя мыши на элемент к следующему эффекту:

Рис. 9.12. Наклон может создавать впечатляющие эффекты

Первое значение задает наклон по оси x (в нашем примере это 40deg), а второе
значение (12deg) предназначено для задания наклона по оси y. Если опустить
второе значение, то единственное имеющееся значение будет просто применено
к оси x (горизонтальной оси), например:
transform: skew(10deg);

Как и в случае с перемещением, вы можете применять наклон только к одной
оси с помощью функций skewX() и skewY().

Матрица (matrix)
Кто-нибудь вспомнил одноименный и весьма переоцененный фильм? Нет? Чточто? Вы хотите узнать о CSS-матрице, а не о фильме? Что ж...
Синтаксис преобразования matrix может показаться непостижимым. Рассмотрим пример кода:
.matrix:hover {
transform: matrix(1.178, -0.256, 1.122, 1.333, -41.533, -1.989);
}

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

Рис. 9.13. Не для слабонервных, значение матрицы

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

2D-преобразования в CSS

267

Теперь мне нравятся сложные задачи (кроме просмотра серии фильмов «Сумерки»), но я уверен, что этот синтаксис требует исследований. Спецификация не
совсем проясняет ситуацию: https://www.w3.org/TR/css-transforms-1/#mathematicaldescription.
Можно сосчитать на пальцах одной руки, сколько раз мне потребовалось написать или понять преобразование CSS, описанное как matrix, поэтому о нем,
пожалуй, не стоит беспокоиться.
Если понадобится создать матрицу, обратитесь по адресу: http://www.useragentman.
com/matrix/.
Этот сайт позволяет перетаскивать элемент, придавать ему вид, который вас
устраивает, после чего забирать код в свой файл CSS.

Свойство transform-origin
Обратите внимание, что при использовании CSS исходная точка преобразования,
которую браузер использует в качестве центра, находится посередине — на 50 %
протяженности элемента по оси x и на 50 % его протяженности по оси y. Это отличается от SVG-технологии, в которой такая точка по умолчанию находится
в левом верхнем углу с координатами (0; 0).
С помощью свойства transform-origin можно изменить точку начала преобразования.
Рассмотрим наше матричное преобразование. По умолчанию transform-origin
устанавливает точку начала преобразования в позицию '50% 50%' (в центре элемента). Средства разработчика Firefox показывают, как это преобразование применяется.

Рис. 9.14. Эффект свойства transform-origin по умолчанию

Если перенастроить значение transform-origin таким образом:
.matrix:hover {
transform: matrix(1.678, -0.256, 1.522, 2.333, -51.533, -1.989);
transform-origin: 270px 20px;
}

268

Глава 9. Переходы, преобразование и анимация

то можно увидеть следующий эффект:

Рис. 9.15. При необходимости вы можете изменить исходную точку преобразования

Первое значение задает смещение по горизонтали, а второе — по вертикали.
Можно использовать ключевые слова. Например, left задает 0 % по горизонтали,
right — 100 % по горизонтали, top — 0 % по вертикали и bottom — 100 % по вертикали. Или воспользуйтесь длиной, задавая для нее любые единицы измерения,
используемые в CSS.
Если для значений свойства transform-origin используются проценты, то горизонтальное и вертикальное смещения задаются относительно высоты и ширины
контейнера, содержащего элементы.
Если используется длина, то значения отмеряются от левого верхнего угла
контейнера, содержащего элементы.
Спецификация CSS 2D Transforms Module Level 1 находится по адресу: https://
www.w3.org/TR/css-transforms-1.

Более полно преимущества перемещения элементов с помощью преобразований рассмотрены в статье Пола Айриша (Paul Irish) (http://www.paulirish.com/2012/
why-moving-elements-with-translate-is-better-than-posabs-topleft/).
А в качестве просто фантастического обзора того, как браузеры справляются
с переходами и анимацией, и объяснения, почему преобразования могут быть
столь эффектными, настоятельно рекомендую следующую публикацию: http://
blogs.adobe.com/webplat-form/2014/03/18/css-animations-and-transitions-performance/.

Мы рассмотрели основы преобразований в двух измерениях, по осям x и y. Тем
временем CSS-код способен обрабатывать элементы в трехмерном пространстве.
Посмотрим, как можно получить еще больше удовольствия с помощью 3D-пре­
образований.

3D-преобразования в CSS
Как вы, наверное, уже поняли, 3D-преобразование позволяет манипулировать
элементом в воображаемом трехмерном пространстве. Рассмотрим первый при-

3D-преобразования в CSS

269

мер. У нас есть два элемента, которые поворачиваются в 3D при наведении указателя мыши. Состояние наведения указателя здесь инициирует изменения просто
в целях иллюстрации, но поворот может быть вызван другим изменением состояния, например сменой класса (через код JavaScript) или получением элементом
фокуса.
Один элемент поворачивается в горизонтальной плоскости, другой — в вертикальной. Полный пример можно найти в каталоге example_09-04. Изображения не
могут обеспечить полное восприятие сути этой технологии, для этого лучше подойдет поворот элемента со сменой лицевой стороны с зеленой на красную с полной иллюзией того, что это происходит в трехмерном пространстве с привлечением перспективы. Посмотрите на скриншот, сделанный на промежуточной фазе
перехода от зеленого к красному, который, надеюсь, передает суть эффекта.

Рис. 9.16. На полпути к 3D-преобразованию

Имейте в виду, что при абсолютном позиционировании элемента с заданием
значений top, left, bottom и right в пикселах промежуточные значения преобразований могут вычисляться по субпиксельным позициям.

Разметка для элемента, подвергаемого перевороту, имеет следующий вид:


The Front
The Back



Единственным отличием в разметке горизонтального поворота является использование вместо класса flipper-vertical класса flipper-horizontal.
Поскольку большинство стилевых настроек направлено на улучшение эстетического восприятия, мы рассмотрим только самые важные составляющие стилей,
влияющие на поворот. Все стили, задающие эстетическое восприятие, можно
увидеть в таблице стилей данного примера.
В начале работы с 3D-преобразованиями нужно определить трехмерное пространство.
Зададим объекту с классом .flipper, внутри которого будет происходить горизонтальный или вертикальный поворот, определенную перспективу. Для этого

270

Глава 9. Переходы, преобразование и анимация

зададим свойству perspective значение длины, имитирующее расстояние от экрана просмотра до края 3D-пространства. Мы установим этот край прямо на внешнем
элементе, чтобы обеспечить трехмерный контекст для поворота вложенных элементов.
Значение, которое прописывается в свойстве perspective, противоречит интуиции — если для перспективы задать небольшое значение, например 20 px,
3D-пространство элемента будет простираться только на эти 20 px от плоскости
экрана и в результате получится слишком явно выраженный 3D-эффект.
А слишком большое значение покажет, что край воображаемого 3D-пространства
находится намного дальше, и получится менее выраженный 3D-эффект. Рекомендую открыть пример в браузере и поиграть с перспективой в инструментах разработчика, чтобы ощутить разницу:
.flipper {
perspective: 400px;
position: relative;
}

Внешний элемент flipper включает position: relative (относительное позиционирование), чтобы указать flipper-object абсолютное позиционирование
внутри него:
.flipper-object {
position: absolute;
width: 100%;
height: 100%;
transition: transform 1s;
transform-style: preserve-3d;
}

Кроме абсолютного позиционирования контейнера .flipper-object мы задали
его свойствам height и width значения 100%, поэтому он будет занимать то же
пространство, что и внешний контейнер. Мы также задали позиционирование для
преобразования. Ранее из этой главы мы узнали, что для указания продолжительности перехода по умолчанию используется функция развития процесса перехода
по времени.
В данном случае ключевым объявлением, касающимся 3D-эффекта, является
transform-style: preserve-3d. Оно сообщает, что при преобразовании элемента
мы хотим, чтобы все 3D-эффекты сохранялись для всех дочерних элементов.
Если для .flipper-object не указать preserve-3d, обратную сторону (красную
часть), поворачиваемого элемента мы никогда не увидим.

Спецификацию для этого свойства можно найти по адресу: http://www.w3.org/
TR/2009/WD-css3-3d-transforms-20090320/#transform-style-property.

3D-преобразования в CSS

271

Мы хотим, чтобы каждая сторона поворачиваемого элемента получила позиционирование в верхней части своего контейнера и при повороте обратная сторона элемента была не видна (в противном случае мы никогда не увидим зеленую
панель, поскольку она располагается «позади» красной). Для этого используем
свойство backface-visibility. Его значение устанавливается в hidden, чтобы, как
вы догадались, скрыть обратную сторону элемента:
.panel {
top: 0;
position: absolute;
backface-visibility: hidden;
}

Заставим обратную сторону быть в исходном состоянии перевернутой, чтобы
при повороте всего элемента она оказалась в правильном положении. Для этого
применим преобразование поворота. Надеюсь, рассмотрев его в предыдущем разделе, вы поймете, что оно здесь делает:
.flipper-vertical .back {
transform: rotateX(180deg);
}
.flipper-horizontal .back {
transform: rotateY(180deg);
}

Теперь повернем весь внутренний элемент, наведя на внешний элемент указатель мыши:
.flipper:hover .flipper-vertical {
transform: rotateX(180deg);
}
.flipper:hover .flipper-horizontal {
transform: rotateY(180deg);
}

Есть несметное количество (кстати, это преувеличение, я проверял) способов
применения главных компонентов этой конструкции. Чтобы узнать с точки зрения
перспективы, как выглядит забавный навигационный эффект или меню, которое
оказывается за пределами основного холста, посетите сайт Codrops: http://tympanus.
net/Development/PerspectivePageViewNavigation/index.html.

Самые последние наработки консорциума W3C в отношении CSS Transforms
Module Level 1 можно найти по адресу: https://www.w3.org/TR/css-transforms-1/.

Оказывается, есть очень удобное свойство, которое может выполнять все перемещения по осям x, y и z одновременно. Рассмотрим его.

272

Глава 9. Переходы, преобразование и анимация

Свойство transform3d
Одна функция может перемещать элемент по осям x (влево-вправо), y (вверхвниз) и z (вперед-назад) сразу.
Внесем коррективы в предыдущий пример и воспользуемся функцией
translate3d. Код этого примера можно найти в каталоге example_09-06.
Кроме установки элементов с небольшим отступом, изменения в предыдущем
примере можно найти здесь:
.flipper:hover .flipper-vertical {
transform: rotateX(180deg) translate3d(0, 0, -120px);
animation: pulse 1s 1s infinite alternate both;
}
.flipper:hover .flipper-horizontal {
transform:rotateY(180deg) translate3d(0, 0, 120px);
animation: pulse 1s 1s infinite alternate both;
}

Мы по-прежнему применяем преобразование, но на этот раз добавили к повороту translate3d(). Синтаксис включает в себя помещаемые внутрь объявления
translate3d «аргументы», отделенные друг от друга запятыми и задающие перемещение по осям x, y и z.
В наших двух примерах я не перемещал элемент по осям x или y (слева направо или вверх и вниз), зато, с вашей точки зрения, перемещал его вперед и назад.
В примере выше поворот элемента происходит за нижней кнопкой и завершается в позиции, находящейся на 120 px ближе к плоскости экрана (отрицательные
значения приведут к отдалению элемента от вас):

Рис. 9.17. Элементы можно перемещать вперед и назад в плоскости z

В то же время нижняя кнопка поворачивается по горизонтали и в итоге удаляется от вас на 120 px:

Рис. 9.18. Здесь элемент находится «дальше»

3D-преобразования в CSS

273

Помимо того что функция translate3d() имеет высокий уровень поддержки,
теперь она является частью спецификации CSS Transforms Module Level 2. Вы
можете ознакомиться с ней по адресу: https://drafts.csswg.org/css-transforms-2/#threed-transform-functions.

Использование преобразований при постепенном
улучшении на примере функции translate3d
Область, в которой, на мой взгляд, функция transform3d себя проявила, — это
всплывающие панели, в частности модели, располагающие элементы навигации
за пределами холста. В файле из каталога example_09-07 вы найдете такую постепенно улучшаемую модель.
При создании системы взаимодействия с помощью JavaScript и CSS нужно
проверять компоненты, начиная с поддержки устройств с самыми скромными возможностями. Что делать тем, у кого нет JavaScript (да, попадаются и такие), или
тем, кто испытывает проблемы с загрузкой или выполнением кода JavaScript? А что
делать, если чьи-нибудь устройства не поддерживают translate3d()? Не волнуйтесь,
вы можете без особых усилий обеспечить работоспособный интерфейс для всех.
Сначала установим, что увидят те, у кого недоступен JavaScript. Как бы там ни
было, если метод для отображения меню зависит от наличия JavaScript, то при отсутствии JavaScript вывод меню за пределы экрана не используется. Тогда для
размещения области навигации в обычном потоке элементов документа мы полагаемся на разметку. В худшем случае независимо от ширины окна просмотра пользователи смогут просто прокрутить страницу до самого низа и щелкнуть по ссылке.

Рис. 9.19. Базовая, но удобная исходная разметка

274

Глава 9. Переходы, преобразование и анимация

Если JavaScript доступен, то при меньших экранах мы «прячем» меню влево.
При щелчке по кнопке меню мы добавляем класс к тегу body (с помощью JavaScript)
и используем его в качестве хука для возвращения навигационной панели в поле
зрения пользователя с помощью CSS:

Рис. 9.20. С помощью щелчка мыши мы перемещаемся по меню

Для более крупных окон просмотра мы «прячем» кнопку меню и просто располагаем панель навигации слева, а основное содержимое перемещаем так, чтобы
им было занято все остальное пространство:

Рис. 9.21. Если позволяет размер окна просмотра, отображаем меню по умолчанию

3D-преобразования в CSS

275

В данном случае код JavaScript отсутствует. А что насчет ситуации, когда
устройство не может обрабатывать translate3d?
Сначала для браузеров, поддерживающих только 2D-преобразования, связанные с перемещениями (например, очень старые телефоны на платформе Android),
использовалось простое свойство translateX. Вот соответствующий фрагмент
кода:
@supports (transform: translateX(-200px)) {
.js .navigation-menu {
left: auto;
transform: translateX(-200px);
}
/*там, где поддерживаются преобразования и нажата кнопка меню,
перевести навигацию в положение по умолчанию*/
.js .OffCanvas-Active .navigation-menu {
transform: translateX(0);
}
}

Для браузеров, поддерживающих трехмерные преобразования, используется
свойство translate3d. При этом там, где оно поддерживается, ожидается существенный прирост визуальной производительности, поскольку на большинстве
устройств выполнение решаемых при его объявлении задач возлагается на эффективные графические процессоры:
@supports (transform: translate3d(-200px, 0, 0)) {
/*Там, где поддерживается transform3d, сброс влево и вытягивание за
пределы экрана осуществляются с помощью translate3d*/
.js .navigation-menu {
left: auto;
transform: translate3d(-200px, 0, 0);
}
/*там, где поддерживается transform3d и нажата кнопка меню,
перевести навигацию в положение по умолчанию*/
.js .OffCanvas-Active .navigation-menu {
transform: translate3d(0, 0, 0);
}
}

Откройте пример в браузере и смоделируйте разные варианты с помощью
инструментов разработчика, изменив класс js в элементе html на no-js, чтобы
увидеть, как пример будет выглядеть без JavaScript. Кроме того, можно изменить
правила CSS @supports, связанные с translate3d() в CSS, на те, которые не поддерживает браузер, например @supports (scones: delicious).
Это упрощенный пример, но, надеюсь, вы поняли, что подход с постепенным
улучшением гарантирует положительное восприятие работоспособности дизайна
самой широкой аудиторией. Помните, что пользователи не нуждаются в визуальном равенстве, но могут оценить соответствие интерфейса функционалу.

276

Глава 9. Переходы, преобразование и анимация

Эффекты анимации с помощью CSS
Если вам приходилось работать с приложениями Final Cut Pro или After Effects,
то вы сразу почувствуете преимущества CSS-анимации. В ней применяется методика с использованием ключевых кадров, которые можно найти в приложениях,
построенных на основе шкалы времени.
Если вы никогда не работали с ключевыми кадрами или даже не сталкивались
с этим термином, остановимся на нем. Во время создания анимации вы выбираете
ключевые моменты, в которых элементы должны быть в определенном положении.
Представьте прыгающий мяч. Сначала он находится в воздухе — это первый «ключевой кадр», а затем он находится на полу — еще один ключевой кадр. Когда вы
указываете ключевые кадры, анимация заполняет пробелы между ними и движение анимируется.
CSS-анимация состоит из двух компонентов: набора ключевых кадров внутри
объявления эт-правила @keyframes и анимации этого набора со свойством animation
и соответствующими значениями. Посмотрим, как это работает.
В предыдущем примере создавался простой эффект поворота элементов путем
сочетания преобразований и переходов. Соберем воедино все технологии, изученные в этой главе, и добавим к этому примеру анимацию. В следующий пример из
каталога example_09-05 добавим анимационный эффект пульсации в процессе поворота элемента.
Сначала создадим правило @keyframes:
@keyframes pulse {
100% {
text-shadow: 0 0 5px #bbb;
box-shadow: 0 0 3px 4px #bbb;
}
}

Как видите, за написанием @keyframes следует имя конкретной анимации (в данном примере pulse). Эт-правило @keyframes описывает, что вы хотите сделать для
каждого цикла анимации.
Лучше использовать имя, представляющее действие, производимое анимацией,
а не место, к которому вы собираетесь ее применить, поскольку одно и то же правило @keyframes может использоваться по всему проекту несколько раз.
Здесь мы использовали только один «селектор ключевого кадра» — 100%. Но в этправиле @keyframes таких селекторов, выраженных в процентах, можно указать
сколько угодно. Эти величины в процентах нужно представлять на шкале времени.
Например, на 10 % следует сделать фон синим, на 30 % — лиловым, а на 60 % элемент должен стать полупрозрачным и т. д.
Есть также ключевые слова from, эквивалентное 0%, и to, эквивалентное 100%.
Их можно использовать следующим образом:

Эффекты анимации с помощью CSS

277

@keyframes pulse {
to {
text-shadow: 0 0 5px #bbb;
box-shadow: 0 0 3px 4px #bbb;
}
}

Но, поскольку браузеры, основанные на движке WebKit (iOS, Safari), не всегда
понимают значения from и to, рекомендую остановить свой выбор на процентном
обозначении селекторов ключевых кадров.
Мы не стали определять стартовое положение. Дело в том, что оно совпадает
с тем состоянием, в котором уже находится каждое свойство. В спецификации (http://www.w3.org/TR/css3-animations/#keyframes) сказано:
Если не определен ключевой кадр для 0 % или from, то агент пользователя
создает ключевой кадр для 0 %, используя вычисленные значения анимируемых свойств. Если не определен ключевой кадр для 100 % или to, то агент
пользователя создает ключевой кадр для 100 %, используя вычисленные
значения анимируемых свойств.
Добавляя к селектору 100% свойства text-shadow и box-shadow, мы ожидаем, что
ключевые кадры будут применены к элементу для анимации этих свойств до определенной величины. Но сколько будет длиться анимация? Как заставить ее повториться, пойти вспять или показать другие возможности? Вот как происходит
применение к элементу анимации на основе ключевых кадров:
.flipper:hover .flipper-horizontal {
transform: rotateY(180deg);
animation: pulse 1s 1s infinite alternate both;
}

Здесь для краткой формы записи ряда связанных с анимацией свойств используется свойство animation. В этом примере объявляются (по порядку):
1) имя используемого объявления ключевых кадров (pulse);
2) продолжительность анимации (animation-duration) — одна секунда;
3) задержка перед началом анимации (animation-delay) — одна секунда, чтобы
дать кнопке время на первый переворот;
4) количество запусков анимации — бесконечно;
5) направление анимации — чередование (alternate), то есть анимация сначала идет в одном направлении, а затем его меняет;
6) свойство animation-fill-mode, сохраняющее значения, определенные в ключевых кадрах, когда анимация собирается идти вперед или назад.
Сокращенная запись может фактически принять все семь свойств анимации.
В дополнение к предыдущему примеру можно указать значение свойства animationplay-state: для проигрывания анимации — running , а для ее остановки — paused.
Разумеется, использовать сокращенную запись не обязательно, иногда имеет смысл

278

Глава 9. Переходы, преобразование и анимация

установить каждое свойство по отдельности, чтобы упростить чтение кода. Далее
показаны отдельные свойства и значения. Там, где требуется, их альтернативные
значения перечислены в комментарии:
.animation-properties {
animation-name: warning;
animation-duration: 1.5s;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite;
animation-play-state: running; /* также может быть 'paused' */
animation-delay: 0s;
animation-fill-mode: none; /* также может быть 'forwards', 'backwards'
или 'both' */
animation-direction: normal; /* также может быть 'reverse',
'alternate' или 'alternate-reverse' */
}

Полное определение каждого из этих свойств анимации можно найти в специ­
фикации CSS Animations Level 1 по адресу: https://www.w3.org/TR/css-animations-1/.

Можно запускать несколько анимаций элемента с помощью сокращенной запи­
си свойств через запятую, например animation: animOne 1s alternate
both, animTwo 0.3s forwards.

Как мы уже сказали, использовать объявленные ключевые кадры в отношении
других элементов и с другими установками довольно просто:
.flipper:hover .flipper-vertical {
transform: rotateX(180deg);
animation: pulse 2s 1s cubic-bezier(0.68, -0.55, 0.265, 1.55) 5
alternate both;
}

Здесь pulse-анимация запустится на две секунды и будет использовать функцию
развития процесса перехода по времени ease-in-out-back, определенную в виде
кривой Безье третьего порядка. Анимация будет повторяться в обе стороны пять
раз. Это объявление применено в файле примера к вертикально поворачиваемому
элементу.

Свойство animation-fill-mode
Свойство animation-fill-mode заслуживает специального упоминания. Рассмотрим анимацию, начинающуюся с фона желтого цвета, который переходит в фон
красного цвета за три секунды. Код этого примера можно увидеть в каталоге
example_09-08.

Эффекты анимации с помощью CSS

279

Здесь применяется следующая анимация:
.background-change {
animation: fillBg 3s;
height: 200px;
width: 400px;
border: 1px solid #ccc;
}
@keyframes fillBg {
0% {
background-color: yellow;
}
100% {
background-color: red;
}
}

Но, как только анимация завершится, фон контейнера div вернется к бесцветному состоянию. По умолчанию при завершении анимации элемент возвращается
к тому виду, который он имел до запуска анимации. Чтобы изменить такое поведение, применим свойство animation-fill-mode. В данном примере мы можем
воспользоваться следующим кодом:
animation-fill-mode: forwards;

Тогда элемент сможет сохранить любые значения, примененные в конце анимации. В нашем случае в контейнере div сохранится фон красного цвета, которым
заканчивается анимация. Дополнительные сведения о свойстве animation-fill-mode
можно найти по адресу: https://www.w3.org/TR/css-animations-1/#animation-fill-mode.
без animation-fill-mode

с animation-fill-mode forwards

Рис. 9.22. Если свойству animation-fill-mode не задано значение forwards, анимация
запускается, а затем немедленно сбрасывается

280

Глава 9. Переходы, преобразование и анимация

Упражнения и практика
Здесь может быть полезно найти сайт, использующий переходы, преобразования и анимацию, и попробовать поиграть с настройками в инструментах разработчика. Изучите все движущиеся элементы, а затем задайте соответствующие значения и свойства. Сможете запустить движение элементов в обратном
направлении? Сможете сделать переходы продолжительнее или короче? Есть
ли 2D-преобразования, которые вы сможете изменить, используя функцию
transform3d()?
Можете начать с сайта https://rwd.education — я не против!

Итоги
Описаниям преобразований, переходов и анимации средствами CSS можно посвятить целые книги. Надеюсь, что даже поверхностное ознакомление в этой главе с данным вопросом позволит вам усвоить основы и приступить к практическому использованию этих эффектов.
Из этой главы вы узнали, что такое CSS-преобразования и как создается код
для их реализации. Научились пользоваться функциями развития процесса перехода по времени ease и linear, а затем применили их для создания простых, но
весьма интересных эффектов. Затем изучили все, что касается 2D-преобразований,
в том числе scale и skew, после чего рассмотрели способы их использования в связке с переходами. Кратко познакомились с 3D-преобразования, а затем изучили
CSS-анимацию. И трудно не согласиться, что ваши возможности по части использования CSS существенно возросли!
Но есть одна область в разработке сайтов, которую я всегда старался обойти
стороной, — это создание форм. Не знаю почему, но мне всегда казалось, что их
создание является нудной и не приносящей радости работой. Представьте, как
я обрадовался, когда узнал, что HTML5 и CSS могут как никогда ранее упростить
процесс создания, стилевого оформления и даже проверки правильности заполнения форм! У меня появилось желание заняться этим вопросом. Подобный прилив энтузиазма можете испытать и вы. Готов поделиться своими знаниями в следующей главе.

10

Освоение форм
с помощью HTML5
и CSS

До появления HTML5 для добавления в формы таких компонентов, как панели
выбора даты, замещаемый текст и ползунок диапазонов, всегда требовалось применение JS. Кроме того, не было простого способа довести до пользователя, какой
ввод мы от него ждем, например телефонный номер, адрес электронной почты или
URL-адрес.
К счастью, теперь во многом эти задачи решаются средствами HTML5.
В этой главе ставятся две основные цели: освоить особенности создания форм
в HTML5 и упростить разметку форм для разных устройств с применением последних возможностей CSS.
Вы научитесь:
y быстро добавлять замещаемый текст в соответствующие поля формы;
y отключать при необходимости автозавершение в полях формы;
y устанавливать обязательное заполнение полей перед отправкой формы;
y указывать различные типы ввода, например электронные адреса, телефонные
номера и URL-адреса;
y создавать ползунки диапазонов чисел для упрощенного выбора значений;
y помещать в форму панели выбора дат и цветовых решений;
y использовать регулярные выражения для определения допустимых значений
в формах;
y создавать стилевое оформление форм с помощью Flexbox;
y изменять цвета каретки.

Формы HTML5
Рассмотрим пример, но прежде кое-что объясню. Во-первых, я люблю кино, вовторых, у меня всегда собственное мнение о том, какой фильм хороший, а какой —
нет.

282

Глава 10. Освоение форм с помощью HTML5 и CSS

Каждый год, когда объявляют номинантов на премию «Оскар», я не могу избавиться от ощущения, что одобрение академии получают совсем не те фильмы. Поэтому мы начнем с формы HTML5, позволяющей киноманам выразить свое недовольство
постоянным выдвижением недостойных фильмов в номинацию на эту премию.
Форма состоит из нескольких элементов fieldset, в которые включены основные типы ввода и атрибуты формы HTML5. Кроме стандартных полей ввода
формы и областей ввода текста у нас будут поле ввода чисел с возможностью прокрутки, ползунок диапазона и замещаемый текст для нескольких полей.
Вот как эта форма выглядит в браузере Chrome без примененных к ней стилей:

Рис. 10.1. Изначальная форма без стилевого оформления

Если установить фокус на первое поле и приступить к вводу текста, замещаемый
текст исчезнет. Если убрать фокус, оставить поле нетронутым и еще раз щелкнуть
за пределами поля ввода, замещаемый текст останется в поле. Если отправить
данные формы без текста, произойдет следующее:

Рис. 10.2. Стандартное предупреждение браузера о необходимости заполнения поля

Формы HTML5

283

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

Основные сведения о компонентах формы HTML5
В нашей форме HTML5 есть множество усложнений, поэтому разберемся с ними
по порядку. Каждый из трех разделов формы заключен в набор полей fieldset
с легендой, которая содержит текстовое пояснение:

About the offending film (part 1 of 3)

The film in question?




В предыдущем фрагменте кода можно увидеть, что каждый элемент input формы заключен в контейнер div с элементом label, связанным с каждым полем ввода (можно обернуть элемент input элементом label). Пока все просто. Но внутри
первого элемента input есть первая особенность формы, создаваемой с помощью
HTML5. После обычных атрибутов ID, name и type появился атрибут placeholder.

Атрибут placeholder
Как следует из названия, атрибут placeholder предлагает средство предоставления
подсказок (заполнителей), указывающих пользователю, какие данные можно ввести, например слово «найти» в поле для поиска.
Некий текст в полях формы стал общепринятым требованием, и создатели
HTML5 решили, что он должен стать стандартным свойством HTML. Чтобы добавить пояснительный текст в поле элемента input , просто добавьте атрибут
placeholder. Его значение будет отображаться в поле для ввода до тех пор, пока
его не заменит пользовательский ввод данных. Если данные в поле не введены,
а фокус переведен в другое поле, текст-заместитель остается в поле.

284

Глава 10. Освоение форм с помощью HTML5 и CSS

В нашем примере атрибут placeholder заполняется следующим образом:
placeholder="e.g. King Kong"

Стиль текста-заместителя
Придать стиль тексту атрибута placeholder можно с помощью псевдокласса
:placeholder-shown.

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

input:placeholder-shown {
color: #333;
}

Можно изменить размер текста-заместителя, поскольку он не обязательно
должен совпадать по размеру с окружающим текстом. Но не забывайте о доступности. Использование текста размером менее 10 px не рекомендуется.
Также в цвете текста необходимо использовать соответствующий контраст.
Если у вас еще нет инструмента для проверки приемлемых уровней контрастности,
рекомендую добавить в закладки https://webaim.org/resources/contrastchecker/.

Стилизация указателя ввода с помощью свойства
caret-color
Карет в контексте форм означает текстовый указатель в поле для ввода. Эту обычно мерцающую вертикальную линию еще называют «курсором», но в CSS она
специально названа по-другому, чтобы отличать ее от других курсоров, например
от того, который появляется при вводе с помощью мыши.
Кстати, «карет» (caret) по-английски произносится как ваш любимый оранжевый овощ «морковь» (carrot), но можете произносить «carrit», как в Великобритании, и все будет нормально, пока королева вас не слышит!
Свойство caret-color было добавлено в CSS не так давно. Оно позволяет менять
цвет текстового указателя — карета.
Если нам нужен оранжевый текстовый указатель, его можно оформить сле­
дующим образом:
.my-Input {
caret-color: #f90;
}

Формы HTML5

285

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

Знали ли вы атрибут contenteditable? Он может сделать содержимое обычного элемента, такого как div или span, доступным для редактирования пользователем. В этих ситуациях можно использовать и :caret-color.

Атрибут required
required — это булев атрибут. Термин «булев» означает, что этот атрибут имеет

только две возможности: быть или не быть включенным в элемент.
В разметке он выглядит так:


Добавление атрибута required в элемент ввода показывает, что значение в поле
ввода является обязательным и без него форма не будет отправлена.
Если попытаться отправить форму без заполненного поля, в котором должно
содержаться обязательное значение, на экран будет выведено предупреждающее
сообщение. Каким оно будет (по текстовому содержанию и оформлению), зависит
от применяемого браузера и типа незаполненного поля.
Мы уже видели, как выглядит сообщение, касающееся обязательного для заполнения поля, в браузере Chrome. Такое сообщение в браузере Firefox выглядит
как на рис. 10.3.

Атрибут autofocus
HTML5-атрибут autofocus позволяет иметь в форме поле, готовое к пользовательскому вводу, на которое сразу после загрузки страницы установлен фокус. Сле­
дующий код является примером поля ввода, заключенного в контейнер div с добавленным в конце атрибутом autofocus:

Search the site...



286

Глава 10. Освоение форм с помощью HTML5 и CSS

Рис. 10.3. Сообщения об ошибке при отправке формы в Firefox из-за незаполненных
обязательных полей

Чтобы гарантировать ввод данных, значение required можно использовать
совместно с полями для ввода нескольких типов данных. Исключениями являются элементы ввода range, color, button и скрытые поля ввода, поскольку они
практически всегда должны иметь значение по умолчанию.
При использовании этого атрибута нужно проявлять осмотрительность, поскольку с ним легко можно создать неудобный для пользователей интерфейс.
Например, важно, чтобы этот атрибут был добавлен на странице только один
раз. Если autofocus добавлен к нескольким полям, то при загрузке страницы в Safari фокус получит последнее из полей с автофокусом, а в Firefox и Chrome, наоборот, фокус получит первое из таких полей.
Чтобы быстро пропустить содержимое веб-страницы после ее загрузки некоторые пользователи используют клавишу пробела. Но при установке автофокуса
такой возможности не будет и введенный символ пробела добавляется в поле
ввода с фокусом. Нетрудно догадаться, что ничего, кроме раздражения, это у пользователей не вызовет.

Формы HTML5

287

Кроме того, у пользователей вспомогательных технологий фокус будет сразу
перенесен в другое место на странице, которое они не смогут контролировать, что
не очень удобно!
При использовании атрибута autofocus убедитесь, что он использован в форме
только один раз и вы представляете себе последствия его применения.

Атрибут autocomplete
По умолчанию большинство браузеров помогают пользователю вводить данные
с применением функции автозавершения значений в полях формы там, где это
возможно.
Хотя пользователь сам может отключить или включить эту функцию в браузере,
теперь мы можем показать браузеру, что отказываемся от функции автозавершения
для формы или поля благодаря атрибуту autocomplete. Это пригодится не только
при вводе личных данных (например, номеров банковских счетов), но и при необходимости обратить внимание пользователя и заставить его ввести текст вручную.
Например, во многих формах, запрашивающих номер телефона, я вводил вымышленный номер. Так поступал не я один (вы ведь тоже так делали?). Но установив в соответствующем поле значение off для атрибута autocomplete, я могу
гарантировать, что пользователи не введут фиктивный номер, часть которого за
них введет функция автозавершения. В следующем примере показано поле с атрибутом autocomplete со значением off:

Telephone (so we can berate you if you're
wrong)



Автозавершение можно отключить и для всей формы (но не для набора полей),
воспользовавшись в объявлении формы атрибутом autocomplete:




Атрибут list и элемент datalist
Атрибут list и связанный с ним элемент datalist позволяют представить пользователю ряд вариантов выбора, как только он начнет вводить значение в поле.
В следующем примере они оба заключены в контейнер div:

288

Глава 10. Освоение форм с помощью HTML5 и CSS


Award Won











Элемент datalist содержит список возможных значений для ввода. Чтобы
подключить список данных к элементу input, необходимо установить значение
атрибута list в элементе input равным идентификатору (id) элемента datalist.
В нашем примере мы добавили идентификатор awards в элемент datalist и задали такое же значение атрибуту list элемента input.
Варианты заключены в необязательный элемент select, который помогает добавлять сопоставимую функциональность для браузеров, в которых она не реализована.
После подключения элементов list и datalist поле ввода по-прежнему ничем
не отличается от обычного поля, предназначенного для ввода текста. Но при вводе данных под ним появляется окно выбора с наиболее подходящими результатами из перечня, указанного в datalist. Работа атрибута list (в браузере Firefox)
показана на следующем скриншоте.
В данном примере буква «B» присутствует во всех вариантах, перечисленных
в datalist, и пользователю для выбора показываются все варианты.

Рис. 10.4. Элемент datalist, показывающий соответствующие возможные варианты

Но если ввести букву «D», то на экране появится меньше вариантов (рис.10.5).
Атрибут list и элемент datalist не мешают пользователю ввести в поле любой
текст, но они предоставляют еще один способ добавления общих функциональных
возможностей и улучшения условий работы пользователя на основе разметки HTML5.
Поддержка list и datalist раньше была не повсеместной. Там, где этой поддержки нет, элемент input будет вести себя как стандартное поле для ввода. Если
вам необходимо поддерживать старые версии браузеров и вы должны быть увере-

Типы вводимой информации, определяемые HTML5

289

ны в том, что будут видеть пользователи, обязательно проверьте поддержку datalist
по адресу: http://caniuse.com/#search=datalist.

Рис. 10.5. Список сократился до значений, соответствующих введенному символу

Со спецификацией элемента можно ознакомиться по адресу: http://www.w3.org/
TR/html5/forms.html#the-datalist-element.

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

Типы вводимой информации,
определяемые HTML5
В HTML5 добавлен ряд дополнительных типов вводимой информации, которые
при должной поддержке открывают интересный функционал. В случае отсутствия
их поддержки браузеры выводят обычные текстовые поля ввода. Посмотрим на
новые типы вводимой информации.

Тип email
Установить для input тип данных email можно так:
type="email"

Поддерживающие этот тип браузеры будут ожидать пользовательского ввода,
соответствующего синтаксису электронного адреса. В следующем примере объявление type="email" используется вместе с атрибутами required и placeholder:

Your Email address



При связке с атрибутом required отправка несоответствующих данных вызовет
появление предупреждающего сообщения:

Рис. 10.6. При вводе некорректных данных выводится сообщение об ошибке

Устройства с сенсорным экраном (Android, iPhone и т. д.) на основе такого типа
вводимой информации изменяют представляемую пользователю системную клавиатуру. На следующем скриншоте показано, как программная клавиатура на iPad
отображается при фокусировке экрана на настройку ввода type="email". Обратите внимание на добавленный символ @.

Рис. 10.7. Программные клавиатуры часто адаптируются к типу вводимых данных

Типы вводимой информации, определяемые HTML5

291

Тип number
Чтобы поле ввода ожидало число, можно написать следующий код:
type="number"

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

Year Of Crime



На следующем скриншоте показано, как это выглядит в браузере Chrome:

Рис. 10.8. В браузерах для ПК прокрутка отображается для полей с числовым типом
данных

А вот как запись type="number" заставляет программную клавиатуру отображаться на iPad. Обратите внимание, что клавиши с цифрами отображаются по
умолчанию (рис. 10.9).
Браузеры по-разному реагируют на оставшиеся пустыми поля для числовых
значений. К примеру, Firefox ничего не делает, пока форма не отправлена, а при
попытке ее отправки выводит предупреждающее сообщение о незаполненном поле.
А Safari просто позволяет отправить форму.

292

Глава 10. Освоение форм с помощью HTML5 и CSS

Рис. 10.9. Если задан числовой тип данных, программные клавиатуры по умолчанию
отображают клавиши с цифрами

Использование атрибутов min и max для создание числовых диапазонов
В предыдущем примере кода есть диапазон допустимых минимальных и максимальных значений:
type="number" min="1929" max="2015"

Числа, выходящие за границы этого диапазона, должны проходить специальную
обработку.
Сведения о том, что существует разная реализация диапазонов min и max в брау­
зерах, вас вряд ли удивят. Например, Chrome и Firefox выдают предупреждение,
а Safari его не выдает.

Изменение шагов приращения
Вы можете изменить шаг приращения (степень детализации) элементов управления с прокручиваемыми числовыми значениями, воспользовавшись атрибутом
step. Например, прокрутку с шагом 10 единиц можно получить с помощью сле­
дующего объявления:


Типы вводимой информации, определяемые HTML5

293

Тип url
Настроить поле ввода на ожидание URL-адреса можно следующим образом:
type="url"

Нетрудно догадаться, что тип вводимых данных url предназначен для ввода
URL-адресов. Он похож на типы вводимых данных tel и email. Но некоторые
браузеры добавляют к связанному с ним предупреждающему сообщению специальную информацию в случае отправки некорректных значений. В следующий
пример кода включен атрибут placeholder:

Your Web address



Вот, что произойдет при некорректном заполнении поля URL-адреса и попытке отправки формы в Chrome:

Рис. 10.10. Браузер Chrome выводит предупреждающее сообщение, когда тип
вводимых данных не соответствует заданному

Здесь так же, как и при объявлении type="email", устройства с сенсорным
экраном часто вносят изменения в предлагаемую клавиатуру. На следующем
скриншоте показана реакция клавиатуры iPad:

294

Глава 10. Освоение форм с помощью HTML5 и CSS

Рис. 10.11. Экранная клавиатура адаптируется под заданный тип данных

Заметили клавишу .com? С ее помощью электронный адрес можно ввести быстрее.

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

Тип tel
Настроить поле ввода на ожидание телефонного номера можно следующим образом:
type="tel"

А вот как выглядит более сложный пример:

Telephone (so we can berate you if you're
wrong)



Браузеры обеспечивают низкий уровень проверки правильности ввода значений
в поля с типом tel. Когда введено неверное значение, они не выдают соответствую­
щее предупреждающее сообщение.
Но есть и хорошие новости: так же как и в случае с типами вводимых данных
email и url, устройства с сенсорными экранами заботливо подстраиваются под эту
разновидность ввода, изменяя экранную клавиатуру. Вот как выглядит экран
ввода телефонного номера при доступе с iPad на iOS 13.3.

Рис. 10.12. Экранная клавиатура, адаптированная для ввода номера телефона

Обратили внимание на отсутствие букв в области клавиатуры? Это позволяет
пользователям вводить значение в нужном формате намного быстрее.

296

Глава 10. Освоение форм с помощью HTML5 и CSS

Если используемый по умолчанию синий цвет телефонных номеров в iOS Safari
при вводе данных типа tel вас раздражает, можно его изменить, воспользовавшись следующим селектором: a[href^=tel] { color: inherit; }. Это
объявление задает им цвет родительского элемента.

Тип search
Настроить поле ввода под тип поиска можно следующим образом:
type="search"

Поля с этим типом ведут себя так же, как стандартные поля ввода текста. Рассмотрим следующий пример:

Search the site...



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

Атрибут pattern
Поле ввода можно настроить на ожидание конкретного паттерна:
pattern=""

Обратите внимание, что это не тип ввода. Этот атрибут сообщает браузеру,
какие данные для ввода ожидать при определенном паттерне.
Атрибут pattern позволяет с использованием регулярного выражения указать
синтаксис данных, разрешенный для ввода в данном поле.
Рассмотрим следующий пример кода:

Your Name (first and last)



Типы вводимой информации, определяемые HTML5

297

РЕГУЛЯРНЫЕ ВЫРАЖЕНИЯ
Если вы еще не сталкивались с регулярными выражениями, рекомендую для начала почитать статью https://ru.wikipedia.org/wiki/Регулярные_выражения. «Регулярки» используются во многих языках программирования для выявления соответствия данных определенным требованиям. Хотя поначалу они пугают, но
обладают невероятными эффективностью и гибкостью. Например, они позволяют проверить соответствие данных формату пароля или выбрать стиль наименования CSS-класса. Чтобы создать свой паттерн с помощью регулярного выражения и визуально представить его работу, рекомендую воспользоваться
запускаемым в браузере средством: http://www.regexr.com/.

Работая над книгой, я целых 458 секунд искал в интернете регулярное выражение, которому соответствовал бы базовый синтаксис имени и фамилии. Его
использование не является панацеей, но должно гарантировать, что введенное
значение не является числом (прости, R2D2, тебе придется регистрировать свои
жалобы на фильм в другом месте) и состоит как минимум из двух значений, разделенных пробелами, длиной от 2 до 30 символов.
Вводя регулярное выражение в атрибут pattern, я приказал поддерживающим
его браузерам ожидать в поле только те данные, у которых есть соответствующий
синтаксис. Атрибут required позволяет неверно введенным данным получить
трактовку (в поддерживающих браузерах). В данном случае я пытался отправить
форму, не указав фамилию.

Рис. 10.13. Тип pattern приводит к менее точному предупреждению, но позволяет
создавать индивидуальные требования

298

Глава 10. Освоение форм с помощью HTML5 и CSS

Тип color
Хотите настроить поле ввода на прием значения цвета в шестнадцатеричном формате?
input type="color"

Тип ввода color инициирует появление панели выбора цвета в операционной
системе хоста, позволяя пользователям выбирать значения цвета в шестнадцатеричном формате. Рассмотрим в качестве примера следующий код:

Your favorite color



Честно говоря, этот тип вводимых данных я не использовал, но, возможно, он
пригодится вам.

Типы date и time
Если вам приходилось покупать на сайте билеты на мероприятие, то, скорее всего,
вы уже пользовались панелью выбора даты. Новые типы вводимых данных date
и time задумывались с целью дать пользователям общее представление о выборе
значений дат и времени.
К сожалению, когда я пишу эти строки в 2020 году, трудно рекомендовать использовать исходные типы date и time, поскольку их поддержка полностью отсутствует в iOS и Safari. Конечно, без этой поддержки элемент input будет вести
себя как обычное поле ввода. Однако, если в этих браузерах у вас есть пользователи (велика вероятность, что это так), вам понадобится решение на JavaScript для
предоставления соответствующих возможностей.
В надежде, что поддержка этих браузеров скоро будет добавлена, обсудим эти
типы.

Тип date
Рассмотрим в качестве примера следующий код:


Вот что выводит UI в поддерживающих этот тип ввода браузерах (рис. 10.14).
Есть много различных типов ввода даты и времени. Ниже приведен краткий
обзор некоторых из них.

Типы вводимой информации, определяемые HTML5

299

Рис. 10.14. Интерфейс выбора даты, предоставляемый браузером

Тип month
Рассмотрим в качестве примера следующий код:


Интерфейс позволяет пользователю выбрать месяц в формате 2012-06. Так это
выглядит на экране браузера:

Рис. 10.15. Не забывайте, что для достижения одной и той же цели разные
операционные системы часто имеют разные пользовательские интерфейсы

300

Глава 10. Освоение форм с помощью HTML5 и CSS

Тип week
Рассмотрим в качестве примера следующий код:


При использовании типа вводимых данных week панель позволяет пользователю выбрать неделю года в формате 2012-W47.
На следующем скриншоте показано, как это выглядит в Chrome и Microsoft
Edge, которые написаны на одном и том же движке и сегодня являются единственными браузерами, поддерживающими этот тип ввода:

Рис. 10.16. Тип ввода week имеет свой стиль выбора данных в поддерживаемых
браузерах

Тип time
Рассмотрим в качестве примера следующий код:


Тип вводимых данных time позволяет вводить в поле значение в 24-часовом
формате, например 23:50.
Поле выглядит как стандартное поле для ввода данных в поддерживающих его
браузерах, но с дополнительными элементами прокрутки, допуская только один
формат ввода.
Сенсорные устройства отображают другой интерфейс. Вот как поле с таким
типом ввода выглядит на iOS:

Типы вводимой информации, определяемые HTML5

301

Рис. 10.17. Тип вводимых данных time создает специальные элементы интерфейса
в поддерживающих его браузерах

Тип range
Указание типа вводимой информации range приводит к созданию элемента интерфейса под названием «ползунок». Рассмотрим пример:


Здесь показано, как этот элемент выглядит в окне браузера Firefox:

Рис. 10.18. Ползунок диапазона по умолчанию не показывает числовые значения

По умолчанию устанавливается диапазон от 0 до 100. Но, указав в нашем примере величины min и max, мы ограничили выбираемые числа, задав диапазон от 1
до 10.
Одна из проблем применения типа range заключается в том, что при перемещении ползунка пользователь не видит текущего значения. Хотя ползунок предназначен для произвольного выбора чисел, я хотел бы видеть текущее значение
положения ползунка в процессе изменения. Пока способов сделать это средствами

302

Глава 10. Освоение форм с помощью HTML5 и CSS

HTML5 нет. Но этого нетрудно добиться с помощью несложного фрагмента кода
JavaScript. Внесем в код предыдущего примера следующие изменения:

5

Мы добавили два фрагмента: атрибут onchange и элемент span, имеющий идентификатор range. Теперь добавим следующий небольшой фрагмент кода JavaScript:

function showValue(newValue)
{
document.getElementById("range").innerHTML=newValue;
}


Мы получили текущее значение ползунка и показали его в элементе span
с идентификатором range. Совсем скоро мы займемся стилевым оформлением
формы.
В HTML5 есть и другие функциональные возможности, имеющие отношение
к формам. Их полную спецификацию можно найти по адресу: http://www.w3.org/
TR/html5/forms.html.

КАК РАБОТАТЬ С БРАУЗЕРАМИ, КОТОРЫЕ НЕ ПОДДЕРЖИВАЮТ НОВЫЕ
СВОЙСТВА
По ссылке https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-BrowserPolyfills#web-forms список библиотек JavaScript, которые можно использовать,
чтобы заставить браузеры поддерживать многие рассмотренные нами возможности.

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

Стилизация форм HTML5 с помощью CSS

303

Код формы со стилевым оформлением можно увидеть в каталоге example_10-02,
а код примеров можно найти здесь: http://rwd.education.
В этот пример я включил две версии таблицы стилей: styles.css, содержащую
префиксы производителей (добавленные с помощью Autoprefixer), и stylesunprefixed.css — версию с чистым кодом CSS. Легче работать с последней версией.
Вот как форма выглядит в небольшом окне просмотра с применением ряда
основных стилевых настроек.

Рис. 10.19. Наша форма на мобильном устройстве с примененными базовыми
стилями

А вот как она выглядит в более крупном окне просмотра.

304

Глава 10. Освоение форм с помощью HTML5 и CSS

Рис. 10.20. Та же форма, стилизованная под более широкие окна просмотра

В этом коде CSS есть множество технологических приемов, рассмотренных
в предыдущих главах. Flexbox (глава 4) создает отзывчивые элементы. Преобразования и переходы (глава 9) увеличивают размеры полей ввода, получающих
фокус, и создают вертикальный поворот кнопки с вопросом о готовности формы
к отправке. Блочные тени и градиенты (глава 7) выделяют разные области формы.
Медиазапросы (глава 3) переключают Flexbox-направления для разных размеров
окон просмотра. Новые селекторы CSS (глава 6) отрицают старые селекторы.

Стилизация форм HTML5 с помощью CSS

305

Мы не будем снова обсуждать эти технологии. И сконцентрируемся на двух
моментах: во-первых, как визуально обозначить поля, требующие обязательного
заполнения (и как обозначить наличие в них введенного значения), и во-вторых,
как создать эффект «заливки» поля, получающего фокус.

Обозначение полей, требующих обязательного
заполнения
Обязательные для заполнения поля можно обозначить для пользователя с помощью только кода CSS, например:
input:required {
/* стили */
}

Этот селектор может добавить обязательным для заполнения полям границу,
контур или фоновое изображение. Фантазировать здесь можно бесконечно! Рассмотрим конкретный селектор для нацеливания на поле ввода, обязательноедля
заполнения, только при получении им фокуса:
input:focus:required {
/* стили */
}

Но таким образом стили будут применяться к самому input. А как изменить
стили в отношении связанного с ним элемента label? Я решил, что буду помечать
поля, обязательные для заполнения, звездочкой. Но CSS позволит влиять на изменение только самого элемента, его дочерних, непосредственно примыкающих
к нему или последующих одноуровневых родственных элементов, получающих
некое состояние (hover, focus, active, checked и т. д.). В следующих примерах используется состояние hover, но такой вариант, несомненно, вызовет проблемы на
устройствах с сенсорным экраном:
.item:hover .item-child {
}

При использовании предыдущего селектора стили применяются к item-child
при прохождении над ним указателя мыши:
.item:hover ~ .item-general-sibling {
}

А при использовании этого селектора при прохождении указателя мыши стили
применяются к элементу item-general-sibling, если он находится на том же DOMуровне, что и item, и следует за ним:
.item:hover + .item-adjacent-sibling {
}

306

Глава 10. Освоение форм с помощью HTML5 и CSS

Благодаря предыдущему коду, когда указатель мыши будет находиться над
элементом, стили будут применяться к элементу item-adjacent-sibling, если по
отношению к исходному item он является примыкающим одноуровневым родственным элементом, следующим непосредственно за ним в DOM-модели.
Итак, вернемся к нашему вопросу. Стараясь расположить надпись над полем
ввода, мы попадаем в тупик:

The film in question?



В этой ситуации использование одного лишь кода не позволяет изменить стиль
label, расположенной над input, каким бы поле ни было — обязательным для заполнения или нет (поскольку оно следует в разметке после label). Мы можем

изменить порядок следования этих двух элементов в разметке, но тогда придется
смириться с надписью, расположенной под полем ввода.
И все же, вы помните, что Flexbox и Grid предоставляют возможность без особого труда поменять элементы местами (обратитесь к материалам глав 4 и 5)?
При этом можно воспользоваться следующей разметкой:


The film in question?


а затем просто применить к родительскому элементу объявление flex-direction:
row-reverse или flex-direction: column-reverse. Такие объявления меняют
визуальный порядок следования дочерних элементов на обратный, позволяя получить эстетически более привлекательное размещение надписи над полем (при
меньших по размеру окнах просмотра) или слева от поля ввода (при более крупных
окнах просмотра).
Теперь обозначим поля, подлежащие обязательному заполнению, и выделим
их при получении фокуса.
В нашей пересмотренной разметке это можно сделать с помощью селектора
непосредственно примыкающего одноуровневого элемента:

Стилизация форм HTML5 с помощью CSS

307

input:required + label:after {
}

Этот селектор предписывает применять правило к каждой надписи, которая
следует за полем ввода, имеющим атрибут required. А вот как выглядит код CSS
для этого раздела:
input:required + label:after {
content: '*';
font-size: 2.1em;
position: relative;
top: 6px;
display: inline-flex;
margin-left: 0.2ch;
transition: color 1s;
}
input:required:invalid + label:after {
color: red;
}
input:required:valid + label:after {
color: green;
}

Если в поле ввода, обязательное для заполнения, вводится соответствующее
значение, звездочка меняет цвет на зеленый. Мелочь, а приятно.

Создание эффекта заливки фона
В главе 7 мы научились выполнять линейные и радиальные градиенты в качестве
фоновых изображений, но, к сожалению, переход между двумя фоновыми изображениями невозможен (что вполне резонно, поскольку браузер растрирует такие объявления в изображения). И тем не менее мы можем обеспечить переходы
между значениями сопутствующих свойств, таких как background-position
и background-size. Создадим эффект заливки в момент получения фокуса input
или textarea.
К input добавим следующие свойства и значения:
input:not([type='range']),
textarea {
min-height: 40px;
padding: 2px;
font-size: 17px;
border: 1px solid #ebebeb;
outline: none;
transition: transform 0.4s, box-shadow 0.4s, background-position
0.2s;
background: radial-gradient(400px circle, #fff 99%, transparent

308

Глава 10. Освоение форм с помощью HTML5 и CSS

99%), #f1f1f1;
background-position: -400px 90px, 0 0;
background-repeat: no-repeat, no-repeat;
border-radius: 0;
position: relative;
}
input:not([type='range']):focus,
textarea:focus {
background-position: 0 0, 0 0;
}

В первом правиле генерируется сплошной белый радиальный градиент, позиционированный за пределами видимости. Расположенный за ним фоновый
цвет (шестнадцатеричное значение, указанное после radial-gradient) не имеет
смещения, поэтому предоставляет цвет по умолчанию. Когда input получает фокус,
radial-gradient получает значение по умолчанию, и поскольку происходит возвращение к установке background-image, создается красивый переход между двумя настройками фона. Результатом станет заливка поля другим цветом при получении фокуса.

Итоги
В этой главе мы изучили способы применения новых HTML5-атрибутов для работы с формами. Они позволяют сделать формы более удобными, а собираемые
с их помощью данные — соответствующими конкретным требованиям.
Мы также использовали некоторые приемы, рассмотренные в этой книге, чтобы изменить стиль формы и заставить ее макет реагировать на ограничения
устройства, на котором она используется.
И вот мы подходим к финалу путешествия по отзывчивому дизайну. Хотя за
время, проведенное вместе, мы охватили большой объем материала, рассказать
еще есть о чем. Поэтому в последней главе я хочу взглянуть на подходы к отзывчивому веб-дизайну на более высоком уровне и привести свой опыт, чтобы направить в нужное русло ваши проекты.

11

Бонусные техники
и советы

В моих любимых книгах и фильмах всегда есть сцена с наставником, дающим герою ценный совет и некие артефакты. Известно, что все это пригодится, но неизвестно как и когда.
В заключительной главе я хочу сыграть роль наставника (к тому же с моей поредевшей шевелюрой на роль героя я вряд ли подойду). При этом хочу, чтобы вы,
мой прилежный ученик, потратили еще немного времени на усвоение заключительных советов, прежде чем направите усилия на поиск собственных решений
в области отзывчивого веб-дизайна.
Половина этой главы — философские размышления и наставления. Другая
половина — подборка не связанных между собой советов и технических приемов.
Надеюсь, эти советы вам пригодятся.
Вот о чем мы поговорим:
y разбивка длинных URL-адресов;
y обрезка текста;
y создание панелей с горизонтальной прокруткой;
y использование модуля CSS Scroll Snap;
y плавная прокрутка с помощью CSS-свойства scroll-behavior;
y передача брейкпоинтов CSS в JavaScript.
А вот наши возможности:
y обкатка веб-дизайна в браузере;
y тестирование на реальных устройствах;
y принцип постепенного улучшения;
y определение матрицы браузерной поддержки;
y отказ от использования сред разработки CSS при создании конечного продукта;
y написание как можно более простого кода;
y скрытие, показ и загрузка содержимого для разных окон просмотра;
y использование средств контроля качества кода;

310
y
y

Глава 11. Бонусные техники и советы

повышение производительности;
отслеживание появления очередных грандиозных нововведений.

А теперь обратите внимание, 007...
На работе я использую одни возможности CSS постоянно, а другие не использую почти никогда. Думаю, полезнее поделиться с вами теми из них, которыми
я пользуюсь чаще всего.
Я перечислил их в произвольном порядке. Ни одна из них не важнее любой
другой. Если они вам когда-нибудь понадобятся, изучите их подробнее.

Разбивка длинных URL-адресов
Сколько раз вам приходилось добавлять длинный URL-адрес в маленькое пространство? Это сложно. Откройте файл в каталоге example_11-04 и посмотрите на
следующий скриншот. Обратите внимание, что URL-адрес выходит за пределы
выделенного пространства:

Рис. 11.1. Длинный URL-адрес может быть источником проблем

Проблему легко исправить с помощью простого объявления CSS, которое, как
оказалось, также работает в более старых версиях Internet Explorer, начиная с версии 5.5! Просто добавьте следующий код:
word-wrap: break-word;

в разметку элемента-контейнера. Это приведет к следующему эффекту:

Рис. 11.2. С помощью значения break-word можно организовать в небольшом
пространстве длинные URL-адреса

Итак, длинные URL-адреса теперь содержат перенос на следующую строку.

Обрезка текста

311

Обрезка текста
Иногда в ограниченном пространстве уместнее обрезать текст, а не помещать его
в контейнер полностью. Нас учили отмечать такое с помощью многоточия «...».
В CSS это просто, несмотря на долгое объяснение.
Рассмотрим следующую разметку (файл примера можно найти в каталоге
example_11-03):

OK, listen up, I've figured out the key eternal happiness. All you
need to do is eat lots of scones.


Мы хотим обрезать текст до ширины 520 px, чтобы он выглядел так:

Рис. 11.3. Обрезка текста удобна, когда первостепенное значение имеет
сохранение постоянной высоты символов

Вот CSS-код для осуществления этой задачи:
.truncate {
width: 520px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

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

Спецификацию свойства text-overflow можно посмотреть здесь: https://drafts.
csswg.org/css-overflow-3/#text-overflow.

Содержимое будет подвергаться обрезке каждый раз, когда его ширина превысит заданную ширину, которую можно задать в процентах, например 100%, если
она находится внутри flex-контейнера.
Объявление overflow: hidden скрывает все, что выходит за пределы поля.
Объявление text-overflow: ellipsis создает символ многоточия в нужном
месте, чтобы указать на переполнение контейнера. Если установите значение clip,
содержимое просто обрежется, возможно, в середине символа.
Пара свойство — значение white-space: nowrap необходима для того, чтобы
содержимое не переносилось во внешний элемент, что оно и будет делать по умолчанию.

312

Глава 11. Бонусные техники и советы

По-прежнему нет надежного кросс-браузерного способа выполнения многострочной обрезки содержимого, хотя есть спецификация: https://drafts.csswg.org/
css-overflow-3/#propdef--webkit-line-clamp. Свойство -webkit-line-clamp можно
использовать уже сейчас. Но не советую это делать, поскольку оно поддерживается только по соображениям совместимости и, вероятно, будет заменено, как
только «полная» версия спецификации будет широко внедрена.

Создание панелей с горизонтальной
прокруткой
Панели с горизонтальной прокруткой распространены в приложениях для iOS
и в Google Play Store для отображения связанного контента (фильмов, альбомов
и т. д.). Если по горизонтали достаточно места, отображаются все элементы списка.
Но, если пространство ограничено (например, на мобильных устройствах), панель
необходимо прокручивать из стороны в сторону в поисках элемента.
Я создал панель с прокруткой из 10 самых кассовых фильмов 2014 года. Помните этот пример из главы 6? Я просто выбрал случайный год.
На iPhone с iOS 13.3 панель выглядит так:

Рис. 11.4. Панель с горизонтальной прокруткой

Создание панелей с горизонтальной прокруткой

313

Разметка выглядит следующим образом. Для краткости я показал только первый элемент в списке:



Guardians of the Galaxy



Весь код из этого примера можно найти в каталоге example_11_02.
Обычно при добавлении все большего числа элементов в контейнер происходит их перенос на следующую строку. Ключом к этой технике является свойство white-space, которое существует еще со времен CSS 2.1 (http://www.w3.org/
TR/CSS2/text.html#white-space-prop). Мы использовали его для обрезки текста.
Установив для него значение nowrap, вы можете предотвратить перенос содержимого.
Чтобы прокрутка работала, нужен контейнер, который имеет меньшую ширину, чем сумма его содержимого. В нем необходимо установить значение auto для
свойства overflow по оси x. Тогда полоса прокрутки не будет появляться, если
места достаточно, и появится, если его не хватает.
В простейшем случае нам понадобится следующий код CSS:
.Scroll_Wrapper {
width: 100%;
white-space: nowrap;
overflow-x: auto;
overflow-y: hidden;
}
.Item {
display: inline-flex;
}

В этом фрагменте кода мы используем значение inline-flex для дочерних
элементов контейнера, но они также могут иметь значения inline, inline-block
или inline-table.
Чтобы придать оформлению больше эстетики, спрячем полосу прокрутки там,
где это возможно.
К сожалению, для этого нам нужно применить несколько разных объявлений,
чтобы охватить разные реализации браузеров: Internet Explorer, Chrome, Safari,
Microsoft Edge и Firefox. Теперь обновленное правило .Scroll_Wrapper выглядит
так:
.Scroll_Wrapper {
width: 100%;
white-space: nowrap;

314

}

Глава 11. Бонусные техники и советы

overflow-x: auto;
overflow-y: hidden;
/*Remove the scrollbars in supporting versions of older IE*/
-ms-overflow-style: none;
/* Hide scrollbar in Firefox */
scrollbar-width: none;

/*Stops the scrollbar appearing in Safari, Chrome and MS Edge
browsers*/
.Scroll_Wrapper::-webkit-scrollbar {
display: none;
}

Проект стандарта для CSS Scrollbars Module Level 1 можно найти по адресу:
https://drafts.csswg.org/css-scrollbars-1/.

Оставшаяся часть кода нужна для эстетического оформления и не имеет прямого отношения к прокрутке. Однако эту разметку можно изменить с помощью
системы Grid.

Создание панелей с горизонтальной прокруткой
с помощью Grid
Практикуясь с Grid, я понял, что с помощью этой системы можно легко создавать панели с горизонтальной прокруткой. Чтобы воспользоваться сеткой, мы
можем оставить существующую разметку как есть и постепенно улучшать ее
для Grid:
@supports (display: grid) {
.Scroll_Wrapper {
display: grid;
grid-auto-flow: column;
max-width: min-content;
grid-template-rows: auto;
}
}

В этом случае мы превращаем контейнер в сетку и позволяем ему автоматически распределяться по нужному количеству столбцов. Без объявления max-width:
min-content столбцы будут расти, предоставляя больше места, но мы не этого
хотим.

Модуль CSS Scroll Snap

315

Итак, раз уж мы зашли так далеко, «положим вишенку сверху», добавив модуль
CSS Scroll Snap!

Модуль CSS Scroll Snap
Модуль CSS Scroll Snap привязывает полосу прокрутки к определенным точкам
в контейнере. Этот паттерн UI является обычным явлением в интерфейсах приложений, магазинов приложений и таких вещей, как карусели, но раньше он требовал для реализации код JavaScript.

С 2014 года в браузерах использовались разные реализации CSS Scroll Snap
под разными названиями. Однако потребовалось время, чтобы появилась стабильная спецификация с совместимыми реализациями. Вы можете прочитать ее
по адресу: https://www.w3.org/TR/css-scroll-snap-1/.

Воспользуемся модулем CSS Scroll Snap, чтобы добавить привязку областей
прокрутки к нашему горизонтальному контейнеру «Самые кассовые фильмы
2014 года».

Свойство scroll-snap-type
Прежде всего определим свойство scroll-snap-type для контейнера. Нужно привязать прокрутку контейнера к оси x, y или к обеим осям.
Это свойство также позволяет определять строгость применяемой привязки.
Как правило, я выбираю значение mandatory, если не сбрасываю привязку прокрутки. После этого можно использовать значение none, которое вернет привязку
к стандартному контейнеру прокрутки.
Значение mandatory обеспечивает возврат элемента к точке привязки, если он
прокручен в контейнере частично (например, если левая сторона элемента находится за пределами области просмотра на определенном расстоянии).
Существует еще значение proximity, при котором привязка остается на усмотрение браузера.
Важно понимать, в каких случаях значение proximity будет полезным. Предположим, часть элементов в карусели выходит за пределы области просмотра.
Поскольку со значением mandatory элемент всегда будет возвращаться к точке
привязки, могут возникнуть проблемы с перемещением панели. Установка значения proximity означает, что содержимое останется доступным, поскольку браузер

316

Глава 11. Бонусные техники и советы

самостоятельно определит, на каком расстоянии от точки привязки осуществлять
возврат.
В нашем случае ширина ячеек не будет превышать ширину области просмотра,
поэтому целесообразно использовать значение mandatory.
Итак, контейнер получил дополнительный блок. Обратите внимание, что он
заключен в запрос возможности:
@supports (scroll-snap-type: x mandatory) {
.Scroll_Wrapper {
scroll-snap-type: x mandatory;
}
}

Теперь если вы обновите браузер и попытаетесь применить прокрутку панели,
то, скорее всего, будете разочарованы. Ведь мы еще не закончили. Теперь нужно
применить свойство scroll-snap-align к дочерним элементам.

Свойство scroll-snap-align
Свойство scroll-snap-align определяет, куда вернется элемент внутри контейнера. Возможные значения свойства:
y none — никуда;
y start — к началу области привязки;
y end — к концу области привязки;
y center — к центру области привязки.
Итак, внутри функционального запроса добавим класс .Item и установим для
привязки значение start:
@supports (scroll-snap-type: x mandatory) {
.Scroll_Wrapper {
scroll-snap-type: x mandatory;
}
.Item {
scroll-snap-align: start;
}
}

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

Модуль CSS Scroll Snap

317

Рис. 11.5. Нам нужно, чтобы номер фильма не обрезался с левой стороны

Свойство scroll-padding
К счастью, авторы спецификации учли такую возможность. Можно добавить отступ от области привязки прокрутки, и это расстояние будет учитываться, когда
браузер будет решать, к какой точке возвращать элементы. Это свойство добавляется в класс .Scroll_Wrapper:
@supports (scroll-snap-type: x mandatory) {
.Scroll_Wrapper {
scroll-snap-type: x mandatory;
scroll-padding: 0 20px;
}
.Item {
scroll-snap-align: start;
}
}

318

Глава 11. Бонусные техники и советы

Теперь при прокрутке браузер учитывает заданный отступ и производит возврат к точке привязки:

Рис. 11.6. Использование свойства scroll-padding решает проблему

СВОЙСТВО SCROLL-SNAP-STOP
По умолчанию чрезмерная прокрутка может привести к тому, что несколько элементов окажутся за точкой привязки прокрутки. Свойство scroll-snap-stop
позволяет это избежать. Есть два значения на выбор: normal по умолчанию
и always, которое обеспечивает остановку в каждой точке привязки прокрутки.
Плохая новость: на момент написания этих строк свойство scroll-snap-stop
поддерживается только в браузерах Chrome и Edge. Так что проверьте поддержку браузеров, прежде чем добавлять это свойство в проект и удивляться, почему
оно работает не так, как ожидалось!

Привязка брейкпоинтов CSS к JavaScript

319

Модуль CSS Scroll Snap имеет очень приятный функционал! Написав всего
несколько строк, мы можем достичь в CSS того, что раньше требовало целых биб­
лиотек JavaScript. И самое приятное, что мы можем применить это как усложнение.
Если браузер пользователя поддерживает это, отлично. Если нет — ничего страшного.

Плавная прокрутка с помощью свойства
scroll‑behavior
Одной из старейших в HTML является возможность привязки к различным точкам документа. Вы оставляете на странице ссылку, и вместо того, чтобы отправлять пользователя на другую веб-страницу, направляете его в другую точку на той
же странице.
Обычно такие точки располагаются по оси y или вниз по странице. Но эти
функции работают так же хорошо по горизонтали на оси x.
Исторически сложилось, что переход к якорной ссылке всегда был немного
неприятным. Поскольку внимание пользователя мгновенно переносилось в новую
точку на странице, он не сразу понимал, что только что произошло. На протяжении
многих лет люди решали эту распространенную проблему с помощью JavaScript,
эффективно анимируя действие прокрутки.
Теперь CSS предоставил нам более простую альтернативу: свойство scrollbehavior.
Я добавил точки привязки «start» и «end» к каждому концу только что созданной панели прокрутки и поместил две ссылки под панелью прокрутки. Как вы
могли догадаться, по умолчанию щелчок по ссылке «end» мгновенно прокручивает панель до конца. Но если мы добавим запись scroll-behavior: smooth к панели
прокрутки, то получим вместо этого плавное поведение прокрутки. Отлично!
К сожалению, изображением это не передать. Но если откроете пример в каталоге example_11-02, то сможете поиграть с ним сами.

Привязка брейкпоинтов CSS к JavaScript
Если продукт, основанный на веб-технологиях, предполагает работу в интерактивном режиме, к делу подключается JavaScript. При разработке проекта отзывчивого приложения вам, скорее всего, при разных размерах окон просмотра потребуются разные действия. Не только в CSS, но и в JavaScript.
Предположим, что нужно вызвать функцию JavaScript при достижении брейкпоинта в CSS (напомню, что брейкпоинтом называется точка, в которой отзывчивый веб-дизайн должен существенно измениться). Предположим, что брейкпоинтом считается 47,5 rem (при основном размере шрифта 16 px это эквивалентно

320

Глава 11. Бонусные техники и советы

760 px) и нам нужно при этом размере запустить функцию. Существует API JavaScript под названием matchMedia, который позволяет проводить тестирование
в JavaScript так же, как в CSS. Очевидным решением будет использовать этот
интерфейс и создать тест, сопоставимый с медиазапросом.
Но он не отменяет наличие двух мест для обновления и изменения этих значений при изменении размеров окна просмотра.
К счастью, есть более подходящий способ. Впервые я познакомился с ним на
сайте Джереми Кейта (Jeremy Keith) http://adactio.com/journal/5429/.
Полный код можно найти в каталоге example_10-01. Суть в том, что в CSS вставляется нечто такое, что может быть легко считано и правильно воспринято кодом
JavaScript.
Рассмотрим этот прием в CSS:
@media (min-width: 20rem) {
body::after {
content: 'Splus';
font-size: 0;
}
}
@media (min-width: 47.5rem) {
body::after {
content: 'Mplus';
font-size: 0;
}
}
@media (min-width: 62.5rem) {
body::after {
content: 'Lplus';
font-size: 0;
}
}

В каждом брейкпоинте, который мы хотим связать с JavaScript, используется
псевдоэлемент after (можно использовать и before, так как подойдет любой из
них) и указывается содержимое этого псевдоэлемента для именования брейкпоинта. В предыдущем примере я использовал Splus для экранов не меньше меньших,
Mplus — для экранов не меньше средних и Lplus — для экранов не меньше больших.
Здесь можно использовать любые значимые имена и изменять значения там, где
есть смысл (использовать другие показатели ориентации, высоты, ширины и т. д.).

Псевдоэлементы ::before и ::after вставляются в DOM в качестве теневых
DOM-элементов. Псевдоэлемент ::before вставляется в качестве первого дочернего элемента своего родительского элемента, а ::after — в качестве его
последнего дочернего элемента.

Привязка брейкпоинтов CSS к JavaScript

321

При использовании этих настроек CSS мы можем просмотреть DOM-дерево
и увидеть псевдоэлемент ::after.

Рис. 11.7. Можно использовать псевдоэлементы для взаимодействия с кодом
JavaScript

Потом это значение можно будет прочитать в коде JavaScript. Сначала присвоим значение переменной:
var size = window
.getComputedStyle(document.body, ':after')
.getPropertyValue('content');

Чтобы подтвердить концепцию, я создал простую самостоятельно вызываемую
функцию (она выполняется сразу, как только браузер проведет ее синтаксический
анализ), которая после загрузки страницы выводит в окне предупреждения разные
сообщения в зависимости от размера окна просмотра:
var size = window
.getComputedStyle(document.body, ':after')
.getPropertyValue('content');
(function alertSize() {
if (size.indexOf('Splus') != -1) {
document.body.textContent =
size + ' I will run functions for small screens';
}
if (size.indexOf('Mplus') != -1) {
document.body.textContent =
size + ' Run a different function at medium sizes';
}
if (size.indexOf('Lplus') != -1) {
document.body.textContent =
size + ' I will run functions for LARGE screens';
}
})();

Итак, в зависимости от размера экрана, когда вы откроете этот пример, то увидите что-то вроде этого:

322

Глава 11. Бонусные техники и советы

Рис. 11.8. JavaScript может считать значение из CSS-кода

Надеюсь, что в реальных проектах ваша фантазия пойдет дальше вывода предупреждения, и думаю, что из такого подхода к решению проблемы вы извлечете
немалую пользу. И у вас никогда не возникнут опасения относительно рассогласованности медиазапросов CSS и зависимых от ширины окна просмотра функций
JavaScript.
Можно также решить эту проблему с помощью пользовательских свойств
CSS (глава 6), но я склонен придерживаться старого подхода, поскольку он попрежнему хорошо работает в таких браузерах, как Internet Explorer 11.

Обратите внимание, что я использовал те же техники, которые рассматривались
в этой книге, для одностраничного веб-сайта https://rwd.education. Надеюсь, будет
не слишком навязчиво снова предложить вам его посетить.

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

Тестирование на реальных устройствах

323

Обкатка веб-дизайна в браузере
на самых ранних стадиях
Чем больше отзывчивых проектов я разрабатывал, тем более важной мне представлялась обкатка веб-дизайна в среде браузера на самых ранних стадиях. Если
вы и веб-дизайнер, и разработчик в одном лице, то вам будет проще. Как только
у вас сложится какое-то визуальное представление о потребностях, обкатайте прототип в браузере и прорабатывайте идею в среде браузера.
Если вы в первую очередь разработчик, то поставленная цель «дать веб-дизайну
жить в браузере», может значительно помочь процессу проектирования. В каждом
проекте, над которым я работаю, веб-дизайн тем или иным образом пересматривается, когда создается в браузере. Это не провал исходных плоских веб-дизайнов,
это следствие осознания того, что веб-дизайн — всего лишь шаг к реализации идеи.
И увидеть, как он работает в браузере, — это еще один шаг на пути к цели.
Есть куча проблем, которые можно решить, только дизайн непосредственно
в браузере. Каковы размеры окон на устройствах и в браузере? Как настроить
интерактивность при открытии пользователем меню? Как долго должна длиться
вводная анимация? И все равно это много? И т. д.

Тестирование на реальных устройствах
Приступать к созданию «лаборатории устройств» для тестирования можно с самых старых моделей телефонов и планшетов. Разнообразные устройства позволят
не только отследить работу веб-дизайна, но и выявить особенности макета и вывода элементов на экран. Ведь новость о не работающем в конкретной среде проекте, считающемся уже завершенным, вряд ли кого-то обрадует. Начинайте тестировать как можно раньше и как можно чаще! Это окупится сторицей. Можно,
к примеру, купить устаревшие модели телефонов и планшетов на рынке или у друзей и знакомых, обновляющих свою технику.

СИНХРОНИЗАЦИЯ РАБОТЫ С ПОМОЩЬЮ BROWSERSYNC
Одним из наиболее эффективных средств экономии времени, которым я пользуюсь, является BrowserSync. После его настройки при сохранении работы любые
изменения, вносимые, к примеру, в CSS, внедряются в браузер, не требуя при
этом постоянного обновления экрана. Если это вас не сильно впечатлило, добавлю: обновляются и любые другие окна браузеров на устройствах, находящихся в той же Wi-Fi-сети. При этом при внесении каждого изменения уже не приходится брать каждое тестируемое устройство и щелкать на кнопке обновления.
Это средство синхронизирует также прокрутку и щелчки на элементах интерфейса. Настоятельно рекомендую: http://browsersync.io/.

324

Глава 11. Бонусные техники и советы

Использование принципа постепенного
улучшения
В предыдущих главах я упомянул принцип постепенного улучшения. Полагаю, об
этом подходе к разработке, в котором я вижу немалую практическую пользу, можно напомнить еще раз. Суть в том, что интерфейсный код (HTML, CSS или Java­
Script) начинается с соответствия наименьшему общему знаменателю. Затем код
постепенно усложняется с расчетом на устройства и браузеры с более широкими
возможностями. Если вы привыкли работать в обратном порядке, то все может
показаться неким упрощением, и так оно и есть: если вы имеете оптимальные наработки, а затем нашли способ добиться работоспособности в устройствах и браузерах с самыми скромными возможностями, то поймете, что постепенное улучшение является наиболее простым подходом.
Представьте себе маломощное устройство с весьма ограниченными возможностями. В нем отсутствует JavaScript, не поддерживается Flexbox, нет поддержки CSS3
и CSS4. Что в подобных обстоятельствах можно сделать, чтобы обеспечить пользователю удобство восприятия содержимого? Важнее всего создать на HTML5 выразительную разметку с точным описанием всего содержимого. Если создаются чисто
текстовые или иные сайты, основанные на содержимом, то эта задача считается
наиболее простой. В таком случае следует сконцентрироваться на правильном использовании элементов main, header, footer, article, section и aside. Это не только
поможет отделить друг от друга разные разделы кода, но и обеспечит пользователям
высокую доступность информации без дополнительных затрат с вашей стороны.
Если ваш продукт основан на веб-технологиях или визуальных компонентах
пользовательского интерфейса — ползунках, вкладках, раскрывающихся панелях
и т. п., подумайте о том, как превратить визуальную схему в доступную разметку.
Дело в том, что хорошо продуманный макет очень важен, поскольку обеспечивает базовый уровень восприятия для всех пользователей. Чем больше полезных
свойств предоставлено средствами HTML, тем меньше придется иметь дело с CSS
и JavaScript для поддержки устаревших браузеров. Уверен, что никто не любит
писать код для поддержки старых браузеров.
Для погружения в тему рекомендую эти статьи: http://www.cssmojo.com/how-tostyle-a-carousel/ и http://www.cssmojo.com/use-radio-buttons-for-single-option/. Они позволят понять, как довольно сложные взаимодействия могут быть обработаны
конструкциями, созданными на основе HTML и CSS.
А теперь поговорим о браузерах.

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

Использование принципа постепенного улучшения

325

выясняли, почему полезно применять принцип постепенного улучшения. При
правильном подходе к делу это позволит основному объему сайта сохранять функциональность даже в самых старых браузерах.
Но обстоятельства бывают такими, что требуется стартовать с более сложного
набора предварительных требований. Возможно, это будет работа над проектом,
в котором большое значение имеет JavaScript, как нередко и случается. В таком
случае вы все равно можете придерживаться принципа постепенного улучшения.
Просто это усложнение будет происходить с других начальных позиций.
Самое главное — установить свою начальную позицию. Только тогда можно
определить и согласовать объем визуальных и функциональных наработок для
различных намеченных для поддержки браузеров и устройств.

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

Выбор поддерживаемых браузеров
Обычно когда речь заходит о браузерах, которые следует поддерживать, есть две
возможности.
Если дело касается реального сайта, посмотрите статистику его посещений (например, в Google Analytics или подобных системах). Получив представление, вы
сможете сделать прогнозы. Например, если стоимость поддержки браузера X
меньше, чем выгода от его поддержки, то нужно поддерживать браузер X!
Если теми или иными браузерами пользуются менее 10 % пользователей, просмотрите статистику за предыдущие периоды и выявите тенденцию. Как объем
использования менялся за последние 3, 6 и 12 месяцев? Если он составляет 6 %
и его значение за последние 12 месяцев уменьшилось в два раза, то это более чем

326

Глава 11. Бонусные техники и советы

убедительный довод для принятия решения по исключению этого браузера из
числа тех, к которым должны применяться конкретные усовершенствования.
Если дело касается нового проекта, статистика для которого еще не наработана,
то я обычно придерживаюсь политики «двух предыдущих». Это текущая версия
плюс две предыдущие версии каждого браузера. Например, если текущей является версия Safari 13, рассматривайте применение усложнений для этой версии,
а также для Safari 12 и Safari 11 — двух ее предшественников. Проще, конечно,
выбирать из самых популярных браузеров, подвергаемых постоянным обновлениям и имеющим короткий цикл выпуска следующей версии (к примеру, Firefox,
Chrome и Microsoft Edge).

Создание нескольких уровней пользовательского
восприятия
Представьте, что акционеры уже в курсе, что у вас есть подборка браузеров, на
которых вы хотите обеспечить более высокий уровень пользовательского восприя­
тия. Теперь нужно настроиться на создание нескольких таких уровней. Чтобы
ничего не усложнять, везде, где возможно, я провожу оптимизацию для определения простого базового и более совершенного уровней.
Базовый уровень пользовательского восприятия обеспечит минимально жизнеспособная версия сайта, а усложненный уровень — наиболее полнофункциональная и эстетически привлекательная версия. Вам может понадобиться более
точно подогнать характеристики уровней, разветвляя, к примеру, уровень восприятия в зависимости от функциональных возможностей браузеров, используя
признаки поддержки Grid или Scroll Snap. Независимо от способа определения
уровней определяйте как сами уровни, так и то, что вы собираетесь дать пользователю на каждом из них. Затем создавайте код для уровней. Вот где такие техники, как запрос возможностей (глава 6), могут быть полезны.

Отказ от использования сред разработки
CSS при создании конечного продукта
Есть куча свободно распространяемых сред, помогающих быстро создать прототипы и построить отзывчивые сайты. В качестве двух самых распространенных из
них можно назвать Bootstrap (http://getbootstrap.com/ ) и Foundation (http://
foundation.zurb.com/). Несмотря на то что это весьма интересные проекты, в особенности для обучения созданию отзывчивых визуальных шаблонов, полагаю, что
в конечном продукте их использования нужно избегать.
Я обсуждал эту тему со многими разработчиками, начинавшими проекты с использованием одной из таких сред, а затем вносившими в код изменения. Этот

Скрытие, показ и загрузка содержимого для разных окон просмотра

327

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

Скрытие, показ и загрузка содержимого
для разных окон просмотра
Один из наиболее активно продвигаемых принципов отзывчивого веб-дизайна
гласит: если чего-то нет на экране при самом меньшем по размеру окне просмотра,
этого не должно быть и на более крупных экранах.
Суть в том, что пользователи должны достигать одинаковых целей (покупка
товара, чтение статьи, выполнение интерфейсной задачи) при любом размере окна
просмотра. Здравый смысл в этом, безусловно, есть. В конечном счете мы как
пользователи будем разочарованы, когда зайдем на сайт с определенной целью
и не сможем что-то сделать только потому, что наш экран меньше по размеру.
Кроме того, это означает, что при увеличении полезной площади экрана мы не
должны добавлять что-либо просто для заполнения пространства (к примеру,
виджеты, рекламные объявления или ссылки). Если пользователь может обходиться без этих дополнений на экранах меньших размеров, то прекрасно обойдется без них и на более крупных экранах.
В целом я считаю, что хороший совет лучше принципов. Но этот принцип заставляет веб-дизайнеров и разработчиков более тщательно продумывать состав
отображаемого на экране содержимого. Однако ничто не обходится без исключений.
Я всеми силами сопротивляюсь загрузке нового макета для различных окон
просмотра, но иногда без этого просто не обойтись. Есть сложные UI, для которых
вполне оправданным требованием является использование в более широких окнах
просмотра другого макета и другого дизайна. В таких случаях для замены одной
области макета на другую используется код JavaScript. Это сценарий далек от
идеала, но он наиболее практичный.
Кроме того, я считаю вполне разумным скрывать некоторые фрагменты макета с помощью CSS до тех пор, пока они не станут уместными. Например, заголовки. Прежде чем модуль Grid получил широкую поддержку, я тратил слишком

328

Глава 11. Бонусные техники и советы

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

Средства контроля качества кода
При написании кодов HTML и CSS прощаются многие огрехи. Можно просчитаться с количеством вложенных элементов, забыть поставить кавычки или слеш в элементе или не заметить проблему. Мне чуть ли не еженедельно приходится сталкиваться с собственными просчетами в разметке. Иногда это ляпы вроде опечаток.
А иногда ученические ошибки типа вложения div в span (разметка, при которой
элемент блочного уровня div попадает в линейный элемент span, приводит к непредсказуемым результатам). К счастью, нам в помощь разработаны специальные
инструментальные средства. Можете обратиться по адресу: http:// validator.w3.org/
и вставить на этот сайт свою разметку. В результате будут помечены все ошибки
и получены номера их строк, что существенно облегчит их устранение.

Рис. 11.9. Пропускайте проверку HTML на свой страх и риск!

А еще лучше установите и настройте средства контроля качества вашего кода
HTML, CSS и JavaScript. Или выберете текстовый редактор с определенным уров-

Повышение производительности

329

нем встроенной проверки правильности кода. Тогда по мере набора кода вы будете видеть обозначенные проблемные области. Посмотрите на пример простой
ошибки в написании кода CSS, которая сразу же была замечена редактором Visual Studio Code:

Рис. 11.10. Пользуйтесь инструментами, которые избавят вас от основных проблем

Я специально набрал widtth вместо width. Редактор это заметил и указал на
ошибку, предлагая при этом разумные альтернативы. По возможности нужно
пользоваться именно такими инструментами. Лучше потратить время на их подбор, чем на выискивание глупых ошибок в своем коде.

Повышение производительности
Наряду с эстетическим восприятием не менее важно учитывать производительность отзывчивых веб-конструкций. Но производительность представляется
чем-то вроде движущейся цели. Например, браузеры обновляются и улучшают
способы обработки ресурсов, взамен существующих оптимальных методов разрабатываются новые технологии, получающие со временем достаточный уровень
браузерной поддержки и становящиеся на путь широкого внедрения. И этот перечень можно продолжить.
Но некоторые базовые рекомендации по работе с браузерами практически неизменны. К ним относятся:
y Максимальное облегчение страницы. Если есть возможность сжать изображения, значительно уменьшив их размер по сравнению с исходным, то
так и нужно поступать. Это всегда должно быть первостепенной задачей
оптимизации. Можно вдвое сэкономить на размере файла, сжав одно изображение вместо всего CSS и JavaScript-кода.
y Отсрочка загрузки второстепенных ресурсов (если можно загрузить дополнительный код CSS и JavaScript до вывода страницы на экран, это может
существенно сократить скорость загрузки страницы).

330

Глава 11. Бонусные техники и советы

y

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

Инструменты для оценки производительности
Есть также эффективные средства для определения уровня производительности
и ее оптимизации. Лично я предпочитаю пользоваться сайтом http://webpagetest.
org/. В наипростейшем варианте набирается URL-адрес и делается щелчок на
кнопке START TEST. Сайт покажет полный анализ страницы, но, что еще полезнее,
если вы выберете опцию визуального сравнения, он покажет раскадровку страницы по мере ее загрузки, позволяя сконцентрироваться на как можно более быстром
завершении вывода страницы на экран. На рисунке ниже показано, как выглядит
раскадровка загрузки главной страницы сайта BBC:

Рис. 11.11. Просмотр загрузки страницы как диафильма может наглядно показать
историю производительности

Также в инструменты разработчика браузера встроены мощные тулзы повышения производительности. Lighthouse — это часть инструментов разработчика Google
Chrome, которые можно запустить на вкладке Audits. Укажите в данном инструментарии ваш сайт, и он выдаст вам список возможных улучшений (рис. 11.12).
Это полезный инструмент, так как в каждом совете есть ссылки на дополнительную документацию, благодаря чему вы больше узнаете о проблеме и возможных способах ее решения.

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

Впреддверии великих перемен

331

Рис. 11.12. Инструмент Lighthouse покажет, что и как можно улучшить

В преддверии великих перемен
Одно из обстоятельств, повышающих интерес к разработке веб-интерфейса, заключается в условиях быстрых перемен. Всегда есть что-то новое для изучения,
и веб-сообщество всегда придумывает способы, как при решении тех или иных
задач все улучшить, ускорить и сделать эффективнее.
Например, во время подготовки первого издания отзывчивых изображений (получаемых с помощью атрибута srcset и элемента picture, подробно рассмотренных
в главе 4) не было. Тогда, чтобы получить изображения, подходящие для разных
окон просмотра, приходилось пользоваться хитроумными обходными средствами
от сторонних разработчиков. Теперь эти потребности нашли свое отражение
в стандартах W3C, реализованных в браузерах.

332

Глава 11. Бонусные техники и советы

Аналогично этому несколько лет назад Flexbox еще только мерещился тем, кто
создавал спецификацию. И даже по мере развития спецификации ее реализация
давалась с большим трудом до тех пор, пока за нее не взялся талантливейший разработчик Андрей Ситник (Andrey Sitnik) со своими коллегами из Evil Martians (https://evilmartians.com/). Этот инструмент позволил писать единый синтаксис
и преобразовывать код CSS в код, который мог работать в нескольких реализациях, как по волшебству.
Прогресс в развитии новых интернет-технологий не ослабевает. Набирает популярность WASM (WebAssembly) — средство создания веб-кода, который работает быстрее, чем компилируемый язык. Оно существенно ускорит работу вебприложений. Лин Кларк (Lin Clark), разработчик браузера Mozilla, опубликовал
доступную серию статей о WebAssembly, с которой можно ознакомиться по адресу: https://hacks.mozilla.org/2017/02/a-cartoon-intro-to-webassembly/.
Модуль CSS Grid, подробно рассмотренный в главе 5, имеет в разработке версию Level 2, которая позволит использовать подсетки. Вариативные шрифты,
которые мы рассмотрели в главе 6, станут повседневным явлением, так что ожидайте интересных вещей и в этом направлении.
В общем, ждите перемен и будьте готовы их принять!

Итоги
Время нашего общения подошло к концу, и ваш покорный слуга надеется, что
теперь у вас есть все технологии и инструменты, которые помогут приступить
к разработке отзывчивого сайта или веб-приложения.
В книге мы охватили большой объем информации, рассмотрели методики,
технологии, способы оптимизации производительности, спецификации, основы
организации рабочего процесса, вопросы применения различных инструментов
и многое другое. Усвоить все это сразу вряд ли получится. Поэтому, когда вам
нужно будет вспомнить синтаксис или приемы разработки отзывчивых конструкций, надеюсь, вы вернетесь к страницам этой книги.
А пока желаю удачи на вашем нелегком, но увлекательном пути разработки
отзывчивого веб-дизайна.
До новых встреч!

Бен Фрэйн

Отзывчивый дизайн на HTML5 и CSS3
для любых устройств.
3-е издание
Перевел с английского Сергей Черников
Заведующая редакцией
Ю. Сергиенко
Ведущий редактор
А. Юринова
Научный редактор
К. Тульцева
Литературный редактор
А. Руденко
Обложка
В. Мостипан
Корректоры
М. Одинокова, Н. Петрова
Верстка
Е. Неволайнен

Изготовлено в России. Изготовитель: ООО «Прогресс книга».
Место нахождения и фактический адрес: 194044, Россия, г. Санкт-Петербург,
Б. Сампсониевский пр., д. 29А, пом. 52. Тел.: +78127037373.
Дата изготовления: 02.2022.
Наименование: книжная продукция.
Срок годности: не ограничен.
Налоговая льгота — общероссийский классификатор продукции ОК 034-2014,
58.11.12 — Книги печатные профессиональные, технические и научные.
Импортер в Беларусь: ООО «ПИТЕР М», 220020, РБ, г. Минск, ул. Тимирязева, д. 121/3, к. 214, тел./факс: 208 80 01.
Подписано в печать 17.12.21. Формат 70х100/16. Бумага офсетная. Усл. п. л. 27,090. Тираж 700. Заказ

Наглядный CSS
Грег Сидельников
На 1 июня 2018 года CSS содержал 415 уникальных
свойств, относящихся к объекту style в любом элементе браузера Chrome. Сколько свойств доступно
в вашем браузере на сегодняшний день? Наверняка
уже почти шесть сотен. Наиболее важные из них мы
и рассмотрим. Грег Сидельников упорядочил свойства по основной категории (положение, размерность,
макеты, CSS-анимация и т. д.) и визуализировал их
работу. Вместо бесконечных томов документации две
с половиной сотни иллюстраций помогут вам разобраться во всех тонкостях работы CSS. Эта книга
станет вашим настольным справочником, позволяя
мгновенно перевести пожелания заказчика и собственное видение в компьютерный код!

Создаем динамические
веб‑сайты с помощью PHP,
MySQL, JavaScript, CSS
и HTML5. 5-е изд.
Робин Никсон
Новое (5-е) издание признанного бестселлера, описывающее как клиентские, так и серверные аспекты вебразработки. Эта книга поможет вам освоить динамическое веб-программирование с применением самых
современных технологий. Книга наполнена ценными
практическими советами, содержит подробный теоретический материал. Для закрепления материала автор
рассказывает, как создать полнофункциональный сайт,
работающий по принципу социальной сети.
• Изучите важнейшие аспекты языка PHP и основы
объектно-ориентированного программирования.
• Познакомьтесь с базой данных MySQL.
• Управляйте cookie-файлами и сеансами, обеспечивайте высокий уровень безопасности.
• Пользуйтесь фундаментальными возможностями
языка JavaScript.
• Применяйте вызовы AJAX, чтобы значительно повысить динамику вашего сайта.
• Изучите основы CSS для форматирования и оформления ваших страниц.
• Освойте продвинутые возможности HTML5: геолокацию, обработку аудио и видео, отрисовку на
холсте.

Новая большая книга CSS
Д. Макфарланд
Технология CSS3 позволяет создавать профессионально оформленные сайты, но тонкости этого языка
могут оказаться довольно сложными даже для опытных веб-разработчиков. Полностью переработанное
четвертое издание этой книги поможет вам поднять
навыки работы с HTML и CSS на новый уровень; она
содержит множество ценных советов, описаний приемов, а также инструкции, написанные в стиле справочного руководства. Веб-дизайнеры, как начинающие, так и опытные, при помощи этой книги быстро
научатся создавать красивые веб-страницы, которые
при этом молниеносно загружаются как на ПК, так
и на мобильные устройства.