Текст
                    

Санкт-Петербург «БХВ-Петербург» 2024
УДК 004.43 ББК 32.973.26-018.1 Н64 Н64 Никсон Р. HTML5 и CSS3. Мастер-класс: Пер. с англ. — СПб.: БХВ-Петербург, 2024. — 464 с.: ил. ISBN 978-5-9775-1929-8 Книга посвящена разработке веб-сайтов и веб-приложений с нуля, с применением самых современных клиентских и серверных технологий, селекторов CSS и подходов к веб-дизайну. Рассмотрены стандарт CSS 3+, отрисовка на холсте (технология Canvas), адаптивный веб-дизайн (технологии Flexbox и Grid), технология SASS, расширяющая возможности CSS, а также художественные аспекты веб-дизайна, обеспечение кроссплатформенности сайтов и приложений и приверженность отзывчивому веб-дизайну. Для веб-дизайнеров и веб-разработчиков УДК 004.43 ББК 32.973.26-018.1 Группа подготовки издания: Руководитель проекта Зав. редакцией Перевод с английского Редактор Компьютерная верстка Корректор Оформление обложки Олег Сивченко Людмила Гауль Николая Вильчинского Дарья Кустовская Натальи Смирновой Светлана Крутоярова Зои Канторович Copyright 2022 BPB Publications, India. All rights reserved. First published in the English language under the title HTML5 and CSS3. Masterclass: In-depth Web Design Training with Geolocation, the HTML5 Canvas, 2D and 3D CSS Transformations, Flexbox, CSS Grid, and More, ISBN 9789355511218 by BPB Publications India (sales@bpbonline.com). Russian translation rights arranged with BPB Publications, India. © 2022 BPB Publications, Индия. Все права защищены. Впервые опубликовано на английском языке под названием HTML5 and CSS3. Masterclass: In-depth Web Design Training with Geolocation, the HTML5 Canvas, 2D and 3D CSS Transformations, Flexbox, CSS Grid, and More, ISBN 9789355511218 издательством BPB Publications India (sales@bpbonline.com). Права на перевод на русский язык предоставлены издательством BPB Publications, Индия. "БХВ-Петербург", 191036, Санкт-Петербург, Гончарная ул., 20. ISBN 978-93-55511-218 (англ.) ISBN 978-5-9775-1929-8 (рус.) © BPB Publications, India, 2022 © Перевод на русский язык, оформление. ООО «БХВ-Петербург», ООО «БХВ», 2023
Содержание Предисловие ................................................................................................................... 15 Об авторе.......................................................................................................................... 17 ГЛАВА 1. Начальные сведения о HTML5 и CSS3 .................................................. 19 Введение .......................................................................................................................... 19 Структура......................................................................................................................... 21 Цели.................................................................................................................................. 21 Знакомство с HTTP и HTML.......................................................................................... 21 Знакомство с CSS ............................................................................................................ 24 Использование атрибутов id и class............................................................................... 25 Чем обусловлена необходимость применения HTML5 и CSS3 ................................. 28 Заключение ...................................................................................................................... 29 ГЛАВА 2. Установка веб-сервера .............................................................................. 31 Вступление ...................................................................................................................... 31 Структура......................................................................................................................... 31 Цели.................................................................................................................................. 31 Представление о WAMP, MAMP и LAMP ................................................................... 32 Установка под Windows ................................................................................................. 32 Работа с корнем документа ............................................................................................ 36 Установка под MacOS .................................................................................................... 39 Работа с корнем документа ............................................................................................ 41 Установка под Linux ....................................................................................................... 43 Работа с корнем документа ............................................................................................ 44 Заключение ...................................................................................................................... 44 ГЛАВА 3. Visual Studio Code....................................................................................... 45 Вступление ...................................................................................................................... 45 Структура......................................................................................................................... 45 Цели.................................................................................................................................. 45 Популярность VS Code................................................................................................... 46 Установка VS Code под Windows.................................................................................. 47
6 | Содержание Установка VS Code под MacOS ..................................................................................... 49 Установка VS Code под Linux........................................................................................ 51 Начало работы с VS Code............................................................................................... 52 Заключение ...................................................................................................................... 54 ГЛАВА 4. Консоль разработчика............................................................................... 55 Вступление ...................................................................................................................... 55 Структура......................................................................................................................... 55 Цели.................................................................................................................................. 55 Доступ к консоли разработчика..................................................................................... 56 Польза, извлекаемая из работы с консолью ................................................................. 60 Автозавершение .............................................................................................................. 61 Просмотр элементов ....................................................................................................... 63 Заключение ...................................................................................................................... 65 ГЛАВА 5. Введение в HTML5..................................................................................... 67 Введение .......................................................................................................................... 67 Структура......................................................................................................................... 67 Цели.................................................................................................................................. 68 HTML5 гораздо серьезнее, чем просто HTML4 + 1..................................................... 68 SVG и MathML ................................................................................................................ 79 Заключение ...................................................................................................................... 80 ГЛАВА 6. Использование холста в HTML5............................................................. 81 Введение .......................................................................................................................... 81 Структура......................................................................................................................... 81 Цели.................................................................................................................................. 81 Ускоренный курс JavaScript ........................................................................................... 82 Размещение кода внутри тегов <script> ........................................................................ 82 Размещение кода в отдельном файле ............................................................................ 85 Функция getElementByID()............................................................................................. 87 Превращение холста в изображение ............................................................................. 88 Заключение ...................................................................................................................... 90 ГЛАВА 7. Прямоугольники и заливки ..................................................................... 91 Введение .......................................................................................................................... 91 Структура......................................................................................................................... 91 Цели.................................................................................................................................. 91 О примерах работы с холстом ....................................................................................... 92 Рисование прямоугольников.......................................................................................... 93 Использование переменных ........................................................................................... 94 Применение стилей рисования ...................................................................................... 95
Содержание | 7 Изменение толщины линии............................................................................................ 96 Очистка прямоугольника ............................................................................................... 97 Применение градиентной заливки................................................................................. 98 Применение радиального градиента ........................................................................... 100 Разноцветные градиентные заливки............................................................................ 101 Использование заполнения узором ............................................................................. 103 Использование перемещения ....................................................................................... 106 Заключение .................................................................................................................... 109 ГЛАВА 8. Надписи на холсте .................................................................................... 111 Введение ........................................................................................................................ 111 Структура....................................................................................................................... 111 Цели................................................................................................................................ 111 Создание надписей........................................................................................................ 112 Изменение способа отображения текста..................................................................... 112 Выравнивание текста .................................................................................................... 113 Изменение толщины обводки ...................................................................................... 115 Надписи с заполнением ................................................................................................ 118 Использование узора для заполнения надписи .......................................................... 121 Заключение .................................................................................................................... 122 ГЛАВА 9. Рисование на холсте................................................................................. 123 Введение ........................................................................................................................ 123 Структура....................................................................................................................... 123 Цели................................................................................................................................ 123 Рисование линий с использованием путей ................................................................. 124 Применение заполнений............................................................................................... 128 Ограничения областей холста...................................................................................... 128 Рисование кривых линий.............................................................................................. 131 Выбор направления....................................................................................................... 132 Рисование дуги к конкретной точке............................................................................ 136 Использование аттракторов ......................................................................................... 138 Завершение и схождение линий .................................................................................. 141 Заключение .................................................................................................................... 144 ГЛАВА 10. Работа с холстом ..................................................................................... 145 Введение ........................................................................................................................ 145 Структура....................................................................................................................... 145 Цели................................................................................................................................ 145 Рисование с использованием изображений ................................................................ 146 Извлечение частей изображений ................................................................................. 148 Использование холста в качестве исходного изображения ...................................... 149 Прикрепление теней ..................................................................................................... 151
8 | Содержание Тени прикрепляются не только к изображениям ....................................................... 153 Непосредственное редактирование пикселей............................................................. 154 Как хранятся данные о цвете ....................................................................................... 156 Последовательный перебор данных ............................................................................ 157 Обработка данных изображения.................................................................................. 157 Усреднение данных о цвете ......................................................................................... 158 Другие эффекты ............................................................................................................ 158 Создание собственных данных изображения............................................................. 162 Заключение .................................................................................................................... 162 ГЛАВА 11. Расширенные возможности работы с холстом ................................. 163 Введение ........................................................................................................................ 163 Структура....................................................................................................................... 163 Цели................................................................................................................................ 163 Выстраивание композиции и прозрачность ............................................................... 164 Использование цикла.................................................................................................... 167 Рисование изображения................................................................................................ 167 Изменение прозрачности.............................................................................................. 168 Применение преобразований ....................................................................................... 169 Использование поворотов ............................................................................................ 171 Применение перемещений ........................................................................................... 172 Применение сразу нескольких преобразований......................................................... 173 Заключение .................................................................................................................... 173 ГЛАВА 12. Применение геолокации ....................................................................... 175 Введение ........................................................................................................................ 175 Структура....................................................................................................................... 175 Цели................................................................................................................................ 176 Что такое GPS................................................................................................................ 176 Альтернативы применению GPS ................................................................................. 176 Проверка доступности геолокации ............................................................................. 177 Использование консоли разработчика ........................................................................ 179 Перенаправление пользователей ................................................................................. 180 Получение сведений о местоположении пользователя ............................................. 182 Именованные функции................................................................................................. 184 Когда получено разрешение......................................................................................... 185 Заключение .................................................................................................................... 186 ГЛАВА 13. Работа с формами................................................................................... 187 Введение ........................................................................................................................ 187 Структура....................................................................................................................... 187 Цели................................................................................................................................ 187 Атрибуты формы HTML5 ............................................................................................ 188
Содержание | 9 Атрибут autofocus.......................................................................................................... 188 Атрибут autocomplete.................................................................................................... 190 Атрибут form ................................................................................................................. 191 Атрибут formaction........................................................................................................ 193 Другие переопределения формы ................................................................................. 194 Атрибут multiple............................................................................................................ 195 Атрибут novalidate ........................................................................................................ 196 Атрибуты width и height ............................................................................................... 196 Атрибут list и теги <datalist> и <option> ..................................................................... 197 Атрибуты min, max и step............................................................................................. 198 Другие типы ввода даты и времени............................................................................. 200 Атрибут pattern .............................................................................................................. 200 Атрибут placeholder ...................................................................................................... 201 Атрибут required............................................................................................................ 202 Тип ввода color .............................................................................................................. 203 Числа и диапазоны ........................................................................................................ 204 Тип ввода search ............................................................................................................ 206 Заключение .................................................................................................................... 207 ГЛАВА 14. Локальное хранилище и многое другое ............................................. 209 Введение ........................................................................................................................ 209 Структура....................................................................................................................... 209 Цели................................................................................................................................ 209 Использование локального хранилища....................................................................... 210 Хранение и извлечение локальных данных................................................................ 210 Удаление и очистка локальных данных...................................................................... 213 Использование взамен этого хранилища сеансов ...................................................... 214 Микроданные ................................................................................................................ 214 Веб-воркеры................................................................................................................... 217 Автономные веб-приложения ...................................................................................... 220 Как работают автономные веб-приложения............................................................... 220 Перетаскивание ............................................................................................................. 222 Обмен сообщениями между документами ................................................................. 223 Заключение .................................................................................................................... 223 ГЛАВА 15. Аудио и видео .......................................................................................... 225 Введение ........................................................................................................................ 225 Структура....................................................................................................................... 225 Цели................................................................................................................................ 225 Аудио в HTML5 ............................................................................................................ 226 Аудиокодеки.................................................................................................................. 226 Воспроизведение аудио ................................................................................................ 227 Видео в HTML5............................................................................................................. 229
10 | Содержание Видеокодеки .................................................................................................................. 230 Воспроизведение видео ................................................................................................ 230 Заключение .................................................................................................................... 236 ГЛАВА 16. Введение в CSS3...................................................................................... 237 Введение ........................................................................................................................ 237 Структура....................................................................................................................... 237 Цели................................................................................................................................ 237 Разработка CSS3 продолжается ................................................................................... 238 Новое в CSS3 ................................................................................................................. 239 Селекторы атрибутов.................................................................................................... 239 Фоновые решения ......................................................................................................... 240 Границы ......................................................................................................................... 242 Тени блоков ................................................................................................................... 244 Столбцы и перетекания ................................................................................................ 246 Цвета и прозрачность.................................................................................................... 247 Текстовые эффекты и шрифты .................................................................................... 248 Перемещения и преобразования.................................................................................. 250 Flexbox-разметка ........................................................................................................... 252 Flexbox как отдельный модуль .................................................................................... 252 CSS grid .......................................................................................................................... 255 Заключение .................................................................................................................... 258 ГЛАВА 17. Селекторы атрибутов CSS3.................................................................. 259 Введение ........................................................................................................................ 259 Структура....................................................................................................................... 259 Цели................................................................................................................................ 259 Селекторы атрибутов CSS............................................................................................ 260 Селектор по имени атрибута........................................................................................ 260 Селектор по значению атрибута .................................................................................. 261 Селектор по слову из списка........................................................................................ 262 Селектор по дефису ...................................................................................................... 263 Селектор по начальным символам .............................................................................. 264 Селектор по конечным символам ................................................................................ 265 Глобальный селектор.................................................................................................... 267 Флажок невосприимчивости к регистру символов.................................................... 268 Флажок восприимчивости к регистру символов........................................................ 269 Заключение .................................................................................................................... 270 ГЛАВА 18. Создание фона......................................................................................... 271 Введение ........................................................................................................................ 271 Структура....................................................................................................................... 271 Цели................................................................................................................................ 271
Содержание | 11 Обрезка и начало фона ................................................................................................. 272 Литералы шаблонов ...................................................................................................... 272 Использование свойства background-clip.................................................................... 274 Использование свойства background-origin ................................................................ 275 Совместное использование обрезки и начала фона ................................................... 275 Раздел сценария JavaScript ........................................................................................... 278 Размер фона ................................................................................................................... 280 Использование градиентов........................................................................................... 282 Точки остановки цвета ................................................................................................. 284 Удаленность точек остановки цвета и повторения .................................................... 284 Радиальные и конические градиенты.......................................................................... 285 Заключение .................................................................................................................... 286 ГЛАВА 19. Построение границ................................................................................. 287 Введение ........................................................................................................................ 287 Структура....................................................................................................................... 287 Цели................................................................................................................................ 287 Радиус границы ............................................................................................................. 288 Цвета границ.................................................................................................................. 290 Градиентные границы................................................................................................... 291 Использование нескольких фонов............................................................................... 293 Использование одного изображения ........................................................................... 295 Заключение .................................................................................................................... 298 ГЛАВА 20. Свойства блока и текста ....................................................................... 299 Введение ........................................................................................................................ 299 Структура....................................................................................................................... 299 Цели................................................................................................................................ 299 Добавление теней.......................................................................................................... 299 Переполнение элементов.............................................................................................. 302 Макет, составленный из нескольких колонок ............................................................ 303 Заключение .................................................................................................................... 309 ГЛАВА 21. Цвета и прозрачность............................................................................ 311 Введение ........................................................................................................................ 311 Структура....................................................................................................................... 311 Цели................................................................................................................................ 311 RGB-цвета...................................................................................................................... 312 Использование цветового круга .................................................................................. 315 RGBA-цвета ................................................................................................................... 316 HSL-цвета ...................................................................................................................... 318 Применение прозрачности ........................................................................................... 321 Заключение .................................................................................................................... 323
12 | Содержание ГЛАВА 22. Текстовые эффекты и шрифты ........................................................... 325 Введение ........................................................................................................................ 325 Структура....................................................................................................................... 325 Цели................................................................................................................................ 326 Задание размеров блока................................................................................................ 326 Текстовое переполнение............................................................................................... 328 Перенос длинных слов.................................................................................................. 329 Изменение размеров элементов пользователем ......................................................... 331 Выделение фокуса......................................................................................................... 333 Текстовые тени.............................................................................................................. 334 Веб-шрифты................................................................................................................... 335 Заключение .................................................................................................................... 339 ГЛАВА 23. Двумерные преобразования ................................................................. 341 Введение ........................................................................................................................ 341 Структура....................................................................................................................... 341 Цели................................................................................................................................ 342 Преобразования............................................................................................................. 342 Переходы ....................................................................................................................... 344 Перемещения ................................................................................................................. 347 Ожидаемое вскоре свойство translate .......................................................................... 347 Масштабирование ......................................................................................................... 347 Вращение ....................................................................................................................... 349 Наклон............................................................................................................................ 350 Использование матриц.................................................................................................. 352 Заключение .................................................................................................................... 354 ГЛАВА 24. Трехмерная графика и анимация ....................................................... 355 Введение ........................................................................................................................ 355 Структура....................................................................................................................... 355 Цели................................................................................................................................ 355 3D-преобразования ....................................................................................................... 356 Задание перспективы .................................................................................................... 358 Два способа изменения перспективы .......................................................................... 360 Задание стиля преобразования..................................................................................... 362 Изменение исходной точки преобразования .............................................................. 363 Работа в 3D-пространстве ............................................................................................ 364 Управление кубом......................................................................................................... 366 3D-перемещение............................................................................................................ 367 3D-масштабирование .................................................................................................... 367 3D-вращение.................................................................................................................. 367 Видимость обратных сторон граней ........................................................................... 369 Заключение .................................................................................................................... 370
Содержание | 13 ГЛАВА 25. Макет Flexbox ......................................................................................... 371 Введение ........................................................................................................................ 371 Структура....................................................................................................................... 371 Цели................................................................................................................................ 371 Сведения о Flexbox ....................................................................................................... 372 Создание интерактивной среды Flexbox..................................................................... 372 Как работает пример..................................................................................................... 375 Работа с примером ........................................................................................................ 378 Flex-направление........................................................................................................... 379 Перенос flex-элементов ................................................................................................ 382 Выравнивание всего содержимого по главной оси.................................................... 382 Выравнивание элементов по поперечной оси ............................................................ 386 Выравнивание всего содержимого по поперечной оси ............................................. 389 Другие свойства ............................................................................................................ 393 Заключение .................................................................................................................... 394 ГЛАВА 26. CSS Grid ................................................................................................... 395 Введение ........................................................................................................................ 395 Структура....................................................................................................................... 395 Цели................................................................................................................................ 395 Сведения о CSS Grid ..................................................................................................... 396 Как работает пример..................................................................................................... 399 Работа с примером ........................................................................................................ 400 Задание потока Grid-элементов ................................................................................... 401 Выравнивание содержимого ........................................................................................ 402 Выравнивание элементов ............................................................................................. 407 Задание промежутков ................................................................................................... 412 Изменение местоположения и размеров..................................................................... 412 Заключение .................................................................................................................... 417 ГЛАВА 27. Знакомство с Sass ................................................................................... 419 Введение ........................................................................................................................ 419 Структура....................................................................................................................... 419 Цели................................................................................................................................ 420 Sass — достойное решение .......................................................................................... 420 Сведения о Sass ............................................................................................................. 420 Различные версии Sass.................................................................................................. 421 Установка под Windows ............................................................................................... 421 Другие установщики под Windows ............................................................................. 424 Установка под MacOS .................................................................................................. 424 Установка под Linux ..................................................................................................... 426 Альтернативные установки под Linux ........................................................................ 427 Препроцессинг в CSS.................................................................................................... 428 Заключение .................................................................................................................... 429
14 | Содержание ГЛАВА 28. Переменные и потоки выполнения в Sass......................................... 431 Введение ........................................................................................................................ 431 Структура....................................................................................................................... 431 Цели................................................................................................................................ 431 Переменные в CSS ........................................................................................................ 432 Переменные в Sass ........................................................................................................ 434 Значения переменных, используемые по умолчанию ............................................... 435 Область видимости переменных ................................................................................. 437 Принудительное задание глобальной видимости ...................................................... 438 Управление потоком выполнения ............................................................................... 439 Sass-операторы .............................................................................................................. 439 Sass-выражения (Sass-сценарий) ................................................................................. 440 @if … @else................................................................................................................... 441 Влияние скобок ............................................................................................................. 443 @else if ........................................................................................................................... 443 @each … in..................................................................................................................... 444 @for … from … through ................................................................................................ 445 @for … from … to ......................................................................................................... 447 @while ............................................................................................................................ 448 Заключение .................................................................................................................... 448 ГЛАВА 29. Расширенный Sass.................................................................................. 449 Введение ........................................................................................................................ 449 Структура....................................................................................................................... 449 Цели................................................................................................................................ 450 Вложенность, используемая в Sass.............................................................................. 450 Вложенные свойства..................................................................................................... 452 Наследование в Sass...................................................................................................... 453 Использование миксинов ............................................................................................. 455 Модули Sass................................................................................................................... 456 Будущие версии............................................................................................................. 457 Заключение .................................................................................................................... 458 Метаданные.................................................................................................................. 459 Описание........................................................................................................................ 459 Чему вы сможете научиться......................................................................................... 460 Для кого эта книга......................................................................................................... 460 Содержание.................................................................................................................... 461 Биография автора .......................................................................................................... 462
Предисловие Эта книга предназначена для всех, кто заинтересован в совершенствовании своих знаний и навыков в области веб-дизайна, причем неважно, кем именно будет читатель: просто любителем, профессиональным разработчиком или специалистом, намеревающимся построить карьеру веб-дизайнера. Инструменты, доступные веб-разработчикам, постоянно совершенствуются, сообразуясь с ростом потребностей профессиональных разработчиков в более объемных, качественных, более эффективных и интерактивных веб-свойствах. В прошлом основная масса улучшений вынужденно создавалась с применением кода JavaScript, но теперь в веб-браузеры встроено так много новых технологий, что вебдизайнеры могут создавать воистину фантастические страницы и сайты. Единственная проблема заключается в необходимости получения сведений о том, что доступно и как все это использовать. Вот тут-то и пригодится эта книга, поскольку она позволяет ознакомиться со всеми последними усовершенствованиями как HTML5, так и CSS3, а также уяснить их суть и научиться их использованию. Материал изложен простым и понятным языком. Эта книга полна рабочих примеров и рисунков, иллюстрирующих весь изучаемый на каждом этапе обучения материал. Кроме того, каждая глава начинается с краткого описания того, что предстоит изучить, и с постановки целей, которых следует добиться к моменту завершения изучения главы. Ознакомившись с материалом книги, вы действительно сможете усвоить всю нужную информацию о самых интересных улучшениях, появившихся в HTML5 и CSS3, и будете готовы продолжить карьеру веб-разработчика в полной уверенности обладания способностями, позволяющими создавать сайты любых нужных типов, основанной на успешном освоении следующего материала:  В главе 1 вы узнаете о тех функциональных возможностях, которые уже доступ- ны как в HTML5, так и в CSS3, и поймете, зачем они были добавлены, и что могут вам предложить.  В главе 2 вы пройдете весь технологический путь установки на свой компьютер веб-сервера, позволяющего вести локальную разработку и тестирование своих проектов, не испытывая потребностей их выкладки на разработочный сервер.
16 | Предисловие  В главе 3 вы узнаете наверное о лучшем из доступных бесплатном редакторе программного кода, Visual Studio Code, и поймете, в чем его высокая эффективность, а также узнаете, как его можно будет установить и использовать.  В главе 4 вы узнаете все о консоли разработчика, встроенной во все современ- ные браузеры, позволяющей проводить тестирование и отладку ваших проектов.  В главе 5 начнется изучение основ самых новых функций HTML5 и того, что они могут для вас сделать.  В главе 6 состоится знакомство с холстом HTML5, позволяющим создавать на этом холсте надписи и рисунки непосредственно в веб-браузере для получения разнообразных изображений и эффектов.  В главе 7 начнется детальное изучение различных функций холста, начиная с прямоугольников и их заливки.  В главе 8 предстоит изучение всех приемов создания надписей на холсте разно- образными способами, с применением разных текстовых размеров и шрифтов.  В главе 9 будут осваиваться приемы рисования на холсте с использованием про- стых и понятных инструкций на языке JavaScript.  В главе 10 начнется освоение холста с приемами непосредственного манипули- рования цветом и прозрачностью его содержимого.  В главе 11 вы перейдете к самым совершенным функциям холста, которые мо- гут понадобиться для получения доступа ко всем остальным вариантам его использования.  В главе 12 будет изучена геолокация, используемая для картографирования и помогающая пользователям добраться до мест, представляющих для них определенный интерес.  В главе 13 предстоит изучение целого ряда новых и весьма комфортных функ- ций обработки форм, которые теперь уже встроены в HTML5.  В главе 14 предстоит изучение способов совершенствования возможностей, ра- нее предоставляемых cookie-файлами, за счет замены их доступом к локальному хранилищу.  В главе 15 предстоит знакомство с аудио- и видеовозможностями HTML5, и ос- воение способов помещения этих медиа-источников непосредственно на ваши веб-страницы.  В главе 16 начнется переключение вашего внимания на CSS3 и на новые функ- ции, которые может предложить эта технология.  В главе 17 предстоит изучить всё, что касается новых селекторов атрибутов CSS3, и освоить приемы их наиболее эффективного использования.  В главе 18 вы приступите к созданию фонов, недоступных до появления CSS3.  В главе 19 будут представлены новые функции границ, включенные в CSS3, и показан ряд способов их использования.
Предисловие | 17  В главе 20 предстоит изучение всех новых свойств CSS3, касающихся блоков и текста, которыми можно будет воспользоваться для улучшения ваших дизайнерских решений.  В главе 21 будут показаны все новые функции цвета и прозрачности, которые теперь стали доступны благодаря CSS3.  В главе 22 предстоит исследование способов простого добавления к вашему тек- сту целого ряда разнообразных эффектов и даже получения доступа к тысячам бесплатных веб-шрифтов.  В главе 23 предстоит рассмотреть способы преобразования любых двумерных веб-элементов путем их растяжения, вращения и многого другого.  В главе 24 эти преобразования будут подняты на следующий уровень для мани- пулирования трехмерными объектами, а также применения к ним приемов анимации.  В главе 25 состоится знакомство с весьма эффективным макетом Flexbox, спо- собным как никогда ранее упростить создание страниц с привлекательным внешним видом, работающих на устройствах любого размера.  В главе 26 предстоит изучение альтернативы технологии Flexbox с еще более развитой гибкостью, которая называется CSS Grid.  В главе 27 состоится знакомство с препроцессором Sass, который служит рас- ширением CSS, и вне всяких сомнений позволит поднять ваш дизайн на более высокий уровень.  В главе 28 предстоит научиться использованию в Sass переменных и управле- нию потоком выполнения инструкций.  И наконец, в главе 29 вы завершите свое исследовательское путешествие, овла- дев различными передовыми технологиями Sass. Об авторе Робин Никсон — веб-разработчик и преподаватель, активно занимающийся программированием с 1980-х годов. Ранее он редактировал компьютерный журнал, был директором нескольких компаний-разработчиков программного обеспечения, а в последнее время стал автором ряда самых продаваемых книг о компьютерах и компьютерных технологиях, выходящих в издательстве O’Reilly. Области интересов Робина — фронтенд-разработка с использованием HTML, CSS и JavaScript, а также управление серверной частью с помощью PHP и MySQL. Он также активный исследователь в области искусственного интеллекта.
ГЛАВА 1 Начальные сведения о HTML5 и CSS3 Введение Вначале был Web 1.0, созданный сэром Тимом Бернерсом-Ли (Tim Berners-Lee) в 1990 году, когда он разработал первый в мире веб-браузер и соответствующий вебсервер. Работая в ЦЕРН (Европейская организация ядерных исследований), он создал систему под названием ENQUIRE, основанную на гипертексте, т. е. на тексте, содержащем ссылки на другой текст в том же или в других документах. В то время ЦЕРН был крупнейшим узлом Интернета из-за гигантского объема создаваемых им данных, которыми нужно было делиться, и Бернерс-Ли понял, что это прекрасная возможность совместить гипертекст с Интернетом. С этого, как говорится, все и началось. Но какой бы разумной изначально ни была концепция, вскоре ее ограничения стали очевидны. Язык HTML не выходил за рамки простого текста и изображений, а вебстраницы были статичными документами, не допускавшими взаимодействия с пользователем. То есть нужно было изобрести динамичную сеть, а именно Web 2.0, позволявшую открыть возможности взаимодействия пользователей друг с другом на веб-страницах, не требовавших перезагрузки при каждом вводе пользователем каких-либо данных, поскольку об этом уже закулисно позаботились с помощью применения асинхронного JavaScript и XML (Asynchronous JavaScript And XML, AJAX), ставшим средством отправки и получения данных по запросу, не заставляющим пользователя задумываться об этом или совершать какие-либо действия. Внедрение сетевых сервисов Web 2.0 привело к появлению социальных сетей и таких продуктов, как Facebook, Gmail, а также нового типа публикаций, названных веб-журналами (блогами), которые реализовывались в основном на таких платформах, как WordPress. Возможно, в названии Web 2.0 было больше семантики, нежели признаков существенных изменений по сравнению с Web 1.0, но все, получившее в этой технологии развитие, настолько далеко ушло вперед от самых первых HTMLстраниц, что Web 2.0 закрепилось за ней как прозвище. Самое существенное в Web 2.0 (по сравнению с Web 1.0) заключается в появлении возможности предложить пользователю внести свой вклад в контент сайта, оставляя комментарии или же создавая учетную запись и соответствующий профиль, что позволило добавлять на сайт свое собственное содержимое. В результате получил-
20 | Глава 1 ся динамически изменяющийся пользовательский контент (например, в Википедии) и возможность расширения его масштабов с применением таких облачных платформ, как Amazon Web Services (AWS). И все же для удовлетворения растущих потребностей веб-разработчиков того, что предоставляла сама технология Web 2.0, уже не хватало, им для доведения качества веб-страниц и веб-приложений до уровня тех программ, которые до этого специально создавались для работы под управлением тех или иных операционных систем, нужны были куда более солидные возможности. И вот на этом пути более или менее параллельно друг другу совершенствовались две технологии, нацеленные на привнесение в арсенал разработчиков целого ряда новых функций, обеспечивающих создание интерактивной, динамичной и анимированной среды, и это были HTML5 и CSS3. С их использованием разработчики получили возможность добавления в свои проекты аудио- и видеоконтента. А для предоставления картографических услуг стала доступной функция геолокации. В спецификацию HTML был добавлен еще и такой элемент, как холст, сопровождающийся огромным набором инструментов для рисования. Появилась возможность хранения на локальном ПК пользователя большого объема данных (не сравнимого с ранее доступными ущербными по объему файлами cookie), а также были предоставлены способы выполнения ресурсоемкого кода в отдельных процессах за счет применения веб-воркеров (web workers), а также ряда других новых инновационных функций. Тем временем также бурно развивалась и технология CSS. Как известно, единственной спецификацией, определяющей целый ряд функций, была CSS2, но требовалось расширение функциональных и управляющих возможностей, о некоторых аспектах которых у разработчиков еще даже не сложилось достаточного представления. Поэтому они пришли к созданию CSS3, где к отдельно взятым модулям по мере необходимости могли добавляться новые возможности, но (что немаловажно) без потери обратной совместимости, позволяющей сохранять работоспособность существующих веб-сайтов. В число новых функций входила улучшенная обработка фона, расширение блочной модели (Box Model), более совершенное управление каскадами, текстовые эффекты, преобразования, анимация и многое другое. П РИМЕЧАНИЕ Совсем скоро ожидается также и реализация концепции Web 3.0, обещающей массовый переход к контексту с высокой степенью распределенности по всему миру, избавляющему его от централизованного пребывания на отдельно взятых сайтах и облачных платформах, с блокчейном (цифровым реестром транзакций, продублированным и распространенным по всей сети компьютерных систем), используемым для проверки подлинности всех данных на различных узлах. В этой концепции также будет предложена поддержка новых технологий, например криптовалют и NFT-токенов (невзаимозаменяемых токенов, иначе говоря, уникальных цифровых идентификаторов, служащих доказательствами вла-
Начальные сведения о HTML5 и CSS3 | 21 дения цифровыми продуктами). Но все это (по крайней мере, на начальном этапе) будет скорее фоновыми изменениями, чем обновлением пользовательского восприятия. А для рассмотрения всех аспектов Web 3.0 потребовалась бы целая книга, не имеющая никакого отношения к освоению особенностей технологий HTML5 и CSS3. Структура В этой главе рассматриваются следующие темы:  Ознакомление с HTML и CSS (или освежение уже имеющихся знаний).  Осознание необходимости отделения стиля от содержания.  Изучение ряда новых функций HTML5 и CSS3.  Подготовка к началу освоения способов использования технологий. Цели Изучение материалов главы позволит получить базовое представление об HTML и CSS (если оно еще не сложилось), узнать о возможностях, открывшихся с появлением HTML5 и CSS3 и о стимулах, побуждающих к их доскональному освоению и включению в арсенал инструментов веб-разработки. Знакомство с HTTP и HTML Книга рассчитана на читателей, знающих, что такое HTML, но для завязки повествования или же для освежения знаний далее приводится краткий обзор стандарта обмена данными HTTP и языка HTML. Подготовленные читатели могут пропустить этот и, возможно, следующие разделы. Протокол передачи гипертекста (HTTP) — метод, позволяющий веб-браузеру обмениваться данными с веб-сервером. Работа веб-сервера — принять запрос от клиента, а затем ответить на него осмысленным образом, обычно возвращая HTMLдокумент (или, возможно, сообщение об ошибке, например «404 Not Found»). HTML-теги HTML-документы — это простые текстовые файлы с вкраплением специальных команд (тегов), заключенных в угловые скобки. Например: команда <body> обозначает начало основного раздела документа. Многие теги сопровождаются соответствующими закрывающими тегами, например тегом </body>, завершающим основной раздел документа.
22 | Глава 1 Но соответствующими закрывающими версиями обладают не все теги, поскольку некоторые из них умеют закрываться и без них. Например, тег для отображения изображения может выглядеть так: <img src='myimage.jpg' />. Последние символы /> приводят к автоматическому закрытию тега. Было время, когда такая форма указания на самостоятельное закрытие выступала стандартом HTML, но в силу очевидности этой особенности у ряда конкретных тегов в конце концов окончание тега /> было решено сделать необязательным, ограничившись в таком случае просто угловой скобкой >, что и будет использоваться в этой книге, хотя все браузеры поддерживают оба варианта. П РИМЕЧАНИЕ Требования версии HTML, используемой для обработки данных и носящей название XML, намного строже, и при ее использовании, например, в ленте Really Simple Syndication (RSS), самостоятельно закрывающиеся теги должны оформляться по всем правилам путем вставки слэша перед закрывающей угловой скобкой. Давайте посмотрим на стандартный документ шаблона HTML5, показанный в примере 1.1. Пример 1.1 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>My Webpage</title> </head> <body> My Content </body> </html> Здесь можно увидеть набор различных тегов, используемых для создания остова HTML-документа. С помощью тега <!DOCTYPE html> веб-браузеру сообщается, что это документ HTML5, и это все, что нужно сделать, чтобы приступить к использованию HTML5. Если же этот тег опустить, веб-браузер будет интерпретировать документ, используя правила HTML4. Можно заметить, что !DOCTYPE — самозакрывающийся тег (поскольку сопроводительный тег </!DOCTYPE> отсутствует), и поэтому следующая за ним строка не имеет отступа. Хотя отступы не входят в перечень обязательных требований HTML, их использование существенно упрощает создание и обновление документов, а также делает их более понятными для других специалистов. Поэтому в этой книге отступы используются повсеместно (во всех примерах HTML, CSS и JavaScript). Далее идет тег <html lang="en">, обозначающий начало HTML-раздела документа, а также уведомляющий браузер, что в нем будет использоваться английский язык.
Начальные сведения о HTML5 и CSS3 | 23 Затем внизу, с отступом и внутри пары тегов <head> ... </head> (обозначающей часть документа, известную как заголовок), следует указание на тип набора символов, который должен использовать браузер, т. е. utf-8, а сам заголовок вебстраницы заключен в пару тегов <title> ... </title>. Здесь также для других целей, например, для совместного использования ключевых слов, описаний для поисковых систем и т. д., могут использоваться и другие теги. Затем следует тело документа, заключаемое в пару тегов <body> ... </body>, внутри которого находится текст содержимого веб-страницы, и которое может (и наверняка будет) содержать множество отдельно взятых разделов и разных типов тегов. И наконец, раздел HTML закрывается тегом </html>. Этого будет вполне достаточно для большинства читателей, но новички теперь узнали почти все необходимое о создании HTML-документов, разумеется, за исключением того, что есть также ряд других тегов, которые необходимо будет изучить для создания высококачественных веб-страниц, но назначение этих тегов, когда до них дойдет очередь, зачастую будет понятно из их названий. Если же нет — Интернет вам в помощь. Атрибуты тегов Понятно, что HTML гораздо сложнее простой вставки набора тегов и текста, поскольку многим тегам следует предоставлять атрибуты. Возьмем недавно упомянутый тег img. Он, помимо способности к самостоятельному закрытию, служит примером тега, принимающего атрибут. В данном случае это атрибут src, или указание местонахождение файла, из которого нужно извлечь изображение, отображаемое на экране. Например, тег <img src='myimage.jpg'> служит командой веб-серверу извлечь файл myimage.jpg из текущей папки, а когда он будет получен, веб-браузер вставит его в нужное место веб-документа. А вот так может выглядеть ссылка на веб-сайт Google: <a href='http://google.com'> Здесь атрибуту href предоставляется URL-адрес (универсальный указатель ресурсов — URL, или веб-ссылка), указывающий место назначения, на которое должен быть нацелен веб-браузер, если щелкнуть на содержимом между тегами <a> и </a>. щелкните на мне</a>. Атрибут стиля Каждый HTML-тег, в зависимости от его типа, может поддерживать широкий спектр всевозможных атрибутов, но почти все теги поддерживают атрибут стиля. Его применение — один из способов стилизации текстового (или другого) вывода. Например, тег <p style='font-weight:bold'>полужирный текст</p> определяет часть текста, известную как абзац, которая будет отображаться полужирным шрифтом. Такой способ применения стилей далек от совершенства, поскольку они получаются встроенными в ваш документ, в то время как технология применения CSS пред-
24 | Глава 1 лагает разделение текста и стилей. Но здесь просто иллюстрируется иной тип атрибута и вводится понятие стиля. Однако это всего лишь один из способов изменения информации, выводимой на экран. Например, для достижения того же эффекта можно просто поместить текст в пару тегов <b> ... </b>, но тогда стиль также будет задаваться жестким образом, а это далеко не лучший подход, особенно если есть желание добиться возможности изменения стиля вывода вашего документа. Итак, рассмотрев пару примеров использования атрибутов и убедившись в том, что HTML предлагает множество различных способов достижения одного и того же результата, давайте перейдем к следующему разделу и посмотрим, что представляет собой технология применения CSS. Знакомство с CSS Название «Каскадная таблица стилей» (Cascading Style Sheet — CSS) и концепция, стоящая за ним, связаны с отделением стиля веб-страницы от ее содержимого. Но зачем это нужно? Давайте разберем пример удовлетворения потребностей человека с ослабленным зрением, которому нужны более контрастные цвета и, возможно, более крупные и легко читаемые шрифты. Решить эту задачу без CSS можно, только создав альтернативные веб-страницы. А если нужно подготовить страницы к печати? Зачастую распечатка веб-страницы без ее изменения будет выглядеть неприглядно, при этом возникнет потребность изменения порядка вывода части страницы на печать, изменения цвета и многих других ее параметров, чтобы она лучше смотрелась на бумаге. А как вы считаете, стоит ли подумать о возможности разного представления страницы в браузерах настольных компьютеров или ноутбуков и мобильных устройств, а также ее подгонки под разные размеры экрана планшетов и телефонов? А с CSS для всего этого нужно только загрузить другой набор команд стилей, вообще не касаясь при этом самой веб-страницы, и остается лишь признать разумность и эффективность применения этой технологии. В предыдущем примере принцип разделения стиля и содержимого был нарушен, поскольку атрибут стиля был применен прямо к элементу HTML. Это было сделано просто для демонстрации возможностей достижения одних и тех же результатов как в HTML, так и в CSS множеством различных способов. Однако нет необходимости встраивать стили в веб-страницы. Напротив, я рекомендую вам никогда не делать этого, главным образом потому что, как показано далее, есть несколько гораздо более подходящих способов получения нужного стиля. Использование элементов span и div Чтобы повысить эффективность применения CSS, в HTML были добавлены два элемента: span и div. Оба они служат для выделения какого-либо раздела HTML из остального документа, но работают по-разному.
Начальные сведения о HTML5 и CSS3 | 25 Элемент span обычно используется для изменения стиля букв, цифр и символов, имеющихся в тексте. Он вместе с текстом перетекает от строки к строке и используется следующим образом: <span>Это часть текста в элементе span</span>. Если нужно, в span можно заключать изображения и другие нетекстовые элементы, которые по возможности будут плавно перемещаться вместе с текстом, хотя возможны и неожиданные результаты, особенно если их размеры будут сильно отличаться от размеров используемого шрифта. А у элемента div более широкое назначение: он превращает раздел документа в блок. В отличие от span, он не встраивается в текст и не перетекает вместе с ним, поскольку принимает форму прямоугольника, и все, что внутри элемента div, растекается и вписывается в его границы. Элемент div может выглядеть так: <div>Это часть текста в элементе div</div>. Пока эти два новых типа элемента не станут использоваться для задания стиля, разницы между ними можно и не заметить. Задать их оформление можно, предоставив атрибут стиля: <span style='font-weight:bold'>Текст, выделенный полужирным шрифтом</span>, но добиться при этом желаемого разделения стиля и содержимого у вас все равно не получится, и тут на первый план выходят другие основные части CSS. Использование атрибутов id и class Для применения любых стилей к отдельно взятым элементам или группам элементов необходимо дать им либо уникальные имена, либо имена групп. В CSS это делается с помощью атрибутов id и class. Например, при наличии на странице основного заголовка и желании применять к нему уникальные стили можно воспользоваться атрибутом id: <h1 id='mainhead'>Добро пожаловать на мою страницу</h1>. Здесь в качестве значения атрибуту id было предоставлено название mainhead. Вскоре будет показано, как к идентифицированным элементам можно будет получить доступ из CSS, но сначала давайте рассмотрим использование атрибута class. Предположим, что в документе имеется множество примечаний, и желательно оформить их в едином стиле. Вот здесь и приходит на помощь применение к каждому из них идентификатора класса, например: <span class='note'>Это примечание</span>. После этого можно будет с помощью одной команды CSS изменять стиль каждого примечания как стиль группы. Но прежде чем рассказать, как это делается, давайте вернемся к той мысли, что HTML и CSS позволяют вам подходить к веб-разработке различными способами, поскольку вместо использования HTML-тега заголовка h1 можно было бы воспользоваться span, а для примечания вместо тега span его текст мог быть заключен в теги h1 или h2 или в любой другой HTML-тег, состоящий из двух частей, и т. д. В связи с этим на первый план выходит концепция удобочитаемости. Когда вебсайт создается с использованием HTML и CSS, из-за многообразия способов достижения желаемых результатов, становится ясно, что необходимо принять опреде-
26 | Глава 1 ленные правила, поскольку проекты имеют тенденцию к укрупнению. Замысел в том, чтобы можно было легко вернуться к тем частям, над которыми шла работа в прошлом, и сразу же понять, что имелось в виду, а кроме этого — помочь всем, кто также вынужден работать над вашими творениями. Поэтому лучше всего по возможности придерживаться использования элементов, предоставляемых HTML. Если создается заголовок первого уровня, поместите его в тег h1. Или же, если создается что-то вроде примечания, для которого нет тега, его лучше поместить в span (или, если это необходимо, в div) и предоставить понятное описательное значение для названия его атрибута class или id. Замысел состоит в задании простоты и логичности и в использовании описательных значений атрибутов. Использование таблиц стилей Замечательно, скажете вы, а как стили могут быть назначены различным элементам в документе, если они не применяются к ним напрямую? Ответ кроется в использовании таблицы стилей, состоящей из набора инструкций, которые можно включить либо в тот же самый документ, либо в отдельные документы, загружаемые по мере надобности. Давайте сначала вспомним, как включать стили в документ, предположив, что все заголовки первого уровня хочется отображать полужирным шрифтом размером 24 пт, весь обычный текст — 14 пт шрифтом с засечками, а все примечания — курсивом с использованием шрифта без засечек. Для этого стандартный шаблон HTML5 из примера 1.1 можно обновить, придав ему вид, показанный в примере 1.2. Пример 1.2 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>My Webpage</title> <style> body { font-size : 14pt; font-family : serif; } h1 { font-size : 24pt; font-weight : bold; } .note { font-style : italic; font-family : sans-serif; } </style>
Начальные сведения о HTML5 и CSS3 20. 21. 22. 23. 24. 25. 26. | 27 </head> <body> <h1>My Content</h1> <p>This is some text</p> <span class='note'>And this is a note</span> </body> </html> Как видите, исходный стиль для тела документа был установлен в паре тегов <style> ... </style> путем применения стилей к элементу body. Затем были присвоены стили всем элементам h1, после чего были назначены стили всем классам с именем note. П РИМЕЧАНИЕ Следует помнить, что точка в таблице стилей, поставленная перед именем атрибута, означает, что правило применяется к классу. Чтобы правило применялось к идентификатору с указанным именем, вместо точки перед именем идентификатора можно поставить знак #. И, как показано в примере, без точки и без знака # правило применяется к элементу с указанным именем. Кроме того, таблица стилей может быть сохранена в текущей папке (или в какомлибо другом месте), и для нее можно воспользоваться именем styles.css. Тогда ее можно хранить отдельно и придать ей вид, как в примере 1.3. Пример 1.3 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. body { font-size font-family } h1 { font-size font-weight } .note { font-style font-family } : 14pt; : serif; : 24pt; : bold; : italic; : sans-serif; Теперь HTML-файл можно сделать еще короче, чтобы он выглядел как в примере 1.4. Пример 1.4 1. 2. 3. <!DOCTYPE html> <html lang="en"> <head>
28 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. | Глава 1 <meta charset="utf-8"> <title>My Webpage</title> <link rel="stylesheet" href="styles.css"> </head> <body> <h1>My Content</h1> <p>This is some text</p> <span class='note'>And this is a note</span> </body> </html> Все его отличие от примера 1.1 сводится к вставке в заголовок документа следующей строки: <link rel="stylesheet" href="styles.css"> В ней содержится приказ веб-браузеру запросить у веб-сервера таблицу стилей, сохраненную в styles.css, после чего браузер воспользуется инструкциями, содержащимися в этом файле для изменения стиля текущего документа по мере надобности. П РИМЕЧАНИЕ Пока не стоит вдаваться в подробности, но теперь понятно, как можно загружать таблицы стилей, и что, сообразуясь с размерами экрана и типом компьютера, на котором работает браузер, можно решить, какую из нескольких предварительно сохраненных таблиц стилей следует выбрать для загрузки. Это весьма действенный прием, особенно если учесть, что основной HTML-документ для отображения в бесконечном разнообразии стилей в дальнейшей модификации не нуждается. Чем обусловлена необходимость применения HTML5 и CSS3 Все изложенное в главе до сих пор было нацелено на освежение в памяти основ HTML и CSS (или на ознакомление с этими технологиями, надеюсь, достаточно подробное, чтобы позволить разобраться с материалом этой книги). И я уверен, что предоставляемые ими возможности впечатляют. Так к чему же вся эта суета вокруг HTML5 и CSS3? Дело в том, что теперь ваши пользователи надеются увидеть и использовать все навороты, которыми могут похвастаться современные веб-браузеры. И не только в этом, но и в том, что последние разработки в рамках этих двух технологий также существенно упрощают жизнь разработчика, превращая функции, реализация которых в былые времена была истинной головной болью (если таковая вообще была возможна), в легкое включение коротких и простых инструкций. Всего пара строк на HTML5 позволяет вставить аудио- или видеоклип. С помощью одной или двух строк CSS3 можно трансформировать или анимировать текст, а также создать в элементе холста самые невероятные веб-приложения и игры, кото-
Начальные сведения о HTML5 и CSS3 | 29 рые ранее требовали сложного кодирования с помощью встроенных Flash- или ActiveX-элементов. Ранее все это отнимало уйму времени, и часто было сопряжено с ошибками и проблемами безопасности. Заключение Элементы технологий HTML5 и CSS3 больше не «лакомства» или расширения, добавляемые к веб-интерфейсу, которыми могли воспользоваться лишь немногие смелые разработчики. Теперь они полностью протестированы, отлажены и получили широкое распространение, и, если есть желание присоединиться к весьма достойным веб-разработчикам, необходимо полностью понять и освоить эти технологии, а также часто и умело использовать их во всех своих проектах. Именно этому и посвящена книга. Каким бы ни был ваш текущий уровень навыков, книга проведет вас через все особенности этих потрясающих новых технологий, чтобы они могли стать для вас повседневными инструментами, применяемыми без тени сомнения. Как только завершится чтение книги и освоение прилагаемых к ней файлов примеров (и, надеюсь, создание множества своих собственных файлов), вы усвоите все, что нужно знать для создания самых динамичных и интересных вебсайтов и веб-приложений, и ваши способности наверняка будут востребованы. Но давайте прямо в следующей главе начнем, как говорится, с истоков, и посмотрим, как совершенно бесплатно и без особого труда установить собственный стек серверной и клиентской части веб-разработки, а также связанные с ним инструменты, позволяющие сразу работать с этой книгой и тестировать примеры (и свои собственные проекты), как будто они были выложены на реальный сервер разработки.
ГЛАВА 2 Установка веб-сервера Вступление Многие HTML и CSS веб-разработки можно просто вести с использованием файловой системы и обычного текстового редактора, похожего на блокнот. Но нужно ли себя ограничивать при наличии многочисленных бесплатных инструментов разработки? К тому же ряд дополнительных функций веб-сайтов, например для применения технологии Asynchronous JavaScript And XML (AJAX) или же локального хранилища и cookie-файлов, требует запуска программных средств на веб-сервере, и попытка их использования путем простой загрузки файлов из папки в веб-браузер не увенчается успехом. Поэтому приступить к использованию всех возможностей HTML5 и CSS3 мы сможем, только обладая обычной персональной Mac- или Linux-машиной, оснащенной надлежащим набором средств разработки. Данная глава будет посвящена установке веб-сервера для тестирования наших проектов, а в следующая — настройке интегрированной среды разработки с Visual Studio Code. Не волнуйтесь, рекомендуемые программные средства совершенно бесплатны, легки в установке и использовании, поэтому не будут стоить вам ни денег, ни времени. Структура В этой главе рассматриваются следующие темы:  Представление о WAMP, MAMP или LAMP.  Порядок установки одного из этих средств в компьютер под управлением Windows, MacOS или Linux.  Сведения о корне документа и порядке получения доступа к нему.  Сведения о хранении страниц для веб-обслуживания. Цели Изложенный в главе материал поможет установить на компьютер локальный вебсервер, позволяющий обслуживать HTML с сопутствующими CSS (включая HTML5
32 | Глава 2 и CSS3), а также поддерживать сценарии на языке PHP для внутренних задач обработки, необходимые для некоторых примеров, приводимых далее в этой книге. Представление о WAMP, MAMP и LAMP Веб-сервер гораздо интереснее, чем просто сервер. Он и сервер, и база данных, и внутренний язык программирования. Широкую известность получило интегрированное решение под названием Windows, Apache, MySQL и PHP, а иногда еще и Python или Perl (WAMP). На Mac-системе оно называется MAMP, а на Linux — LAMP. Продукт, рекомендуемый в данной книге и доступный для загрузки по адресу https://www.mamp.info, называется просто MAMP. Есть его версии для Windows, а также для компьютеров Intel или M1 MacOS. Далее в книге будут даны инструкции по настройкам LAMP для Linux на тот случай, если предустановка этого средства в системе будет отсутствовать. П РИМЕЧАНИЕ Учтите, что книги могут не потерять свою актуальность долгое время, а веб-сайт или сам продукт MAMP может существенно измениться или же стать недоступным. Но по ключевым словам WAMP, MAMP или LAMP всегда можно будет найти альтернативные варианты. Затем вместо приведенных здесь инструкций нужно будет следовать тем, что изложены в новом источнике, но при этом окажется, что там будут аналогичные функции, даже если их использование будет изложено несколько иначе. Установка под Windows Программа MAMP поставляется в двух версиях: базовой и профессиональной. Базовая версия бесплатна, а позже при желании можно будет перейти и на профессиональную. Чтобы загрузить MAMP для Windows, просто перейдите на сайт http://www.mamp.info и будете перенаправлены в раздел Windows, где нужно будет щелкнуть на ссылке для бесплатной загрузки MAMP — Free MAMP download, на появившейся странице выберите MAMP & MAP PRO for Windows. На момент написания книги текущей была версия 5.0.4, но для вас может быть показана более свежая. При щелчке по ссылке загрузки может появиться всплывающее окно с предложением загрузить приложение NAMO DBS App. Его нужно проигнорировать, щелкнув мышью за пределами этого окна, чтобы оно исчезло. Затем, если будет предложено сохранить файл, выберите команду Keep (Сохранить). Загрузка продолжится, для версии 5.0.4 она будет иметь размер 742 Мб.
Установка веб-сервера | 33 После загрузки нужно запустить программу установки, и, если на вашем компьютере нет среды выполнения .Net, вам поступит предложение ее установить. Если так и будет, щелкните на кнопке OK, и появится окно, похожее на показанное на рис. 2.1. Рис. 2.1. Установка среды выполнения .Net Выберите Install (Установить), разрешив тем самым продолжить установку. После этого произойдет переход к экрану установки Mamp (рис. 2.2). Для начала установки MAMP щелкните на кнопке Next (Далее). При появлении показанного на рис. 2.3 запроса на установку Mamp Pro и (или) Bonjour нужно убедиться, что ни в одном из этих полей флажки не установлены, поскольку на этом этапе эти средства вам не понадобятся; если нужно, их всегда можно будет добавить в другое время. После щелчка на кнопке Next (Далее) появится еще пара окон с запросом на согласие с лицензией (щелкайте на кнопке Next) и вопросом, в какую папку вы желаете установить MAMP (рекомендуется принять значение по умолчанию C:\MAMP и щелкнуть на кнопке Next), какую папку выбрать для автозагрузки (рекомендуется оставить предлагаемую по умолчанию MAMP и щелкнуть на кнопке Next) и следует ли создавать значок на рабочем столе (рекомендуется установить соответствующий флажок, а затем щелкнуть на кнопке Next). Наконец, вы доберетесь до экрана, показанного на рис. 2.4, по мере готовности щелкнуть на кнопке Install (Установить). После завершения установки, чтобы выйти из программы, можно щелкнуть на кнопке Finish (Готово).
34 | Глава 2 Рис. 2.2. Окно установки MAMP Рис. 2.3. Устанавливать дополнительные компоненты на этом этапе не рекомендуется
Установка веб-сервера Рис. 2.4. Теперь среда MAMP готова к установке Рис. 2.5. Разрешите брандмауэру предоставлять доступ к MySQL и (или) Apache | 35
36 | Глава 2 Теперь можно запустить программу, но даже без специального напоминания похоже, что некоторые компьютеры будут работать лучше, если их сейчас перезагрузить, что и следует сделать. После перезагрузки можно будет щелкнуть на значке MAMP, который теперь должен появиться на вашем рабочем столе. При первом запуске могут появиться от одного до нескольких всплывающих окон, показанных на рис. 2.5. Они отправляются вашим брандмауэром с просьбой разрешить работу Apache и (или) MySQL. Чтобы среда MAMP смогла работать, нужно в любом случае щелкнуть на кнопке Allow Access (Разрешить доступ). Теперь, после разрешения доступа через брандмауэр, среда MAMP должна заработать, как показано на рис. 2.6, где рядом с Apache Server и MySQL Server появятся зеленые метки. А облачные функции, рекламируемые в нижней части окна, вам не понадобятся. Рис. 2.6. Разрешить доступ к MySQL и (или) Apache Работа с корнем документа В файловой системе Windows всегда есть корневой каталог или папка. Практически всегда в этой роли выступает C:\. Корневые папки других дисков — D:\, E:\ и т. д. У веб-браузера есть аналогичный корневой элемент, называемый корнем документа. Им необязательно должен быть корневой каталог диска (да он и не должен им быть по соображениям безопасности). Это самый высокий уровень расположения
Установка веб-сервера | 37 файлов, к которому сервер будет предлагать доступ, и для разных веб-серверов (и даже для разных установок одного и того же бренда веб-сервера) он будет находиться в разных местах. Если при использовании среды MAMP предположить, что был принят вариант по умолчанию, предложенный в ходе установки, корень документа можно будет найти в C:\MAMP\htdocs (или же, если предпочтительнее использовать простой слэш, то в C:/MAMP/htdocs, или весь путь можно даже будет указать строчными буквами, например: c:\mamp\htdocs или даже c:/mamp/htdocs). По умолчанию после первой установки корень документа будет содержать два файла: index.php и MAMP-PRO-Logo.png. Доступ к их размещению можно получить через файловую систему, а находящиеся там файлы можно загрузить локально прямо из вашего веб-браузера, введя в его адресную строку http://localhost (или даже просто localhost). Результат по определению будет выглядеть, как на рис. 2.7. Рис. 2.7. Отображение исходного файла index.php При желании или же по какой-то иной причине можно воспользоваться IP-адресами, зарезервированными на компьютерах для локального хоста, например: http://127.0.0.1 или просто 127.0.0.1. Если на экране появилось изображение, показанное на рис. 2.7, значит MAMP установлен правильно и все программные средства: PHP, MySQL и веб-сервер Apache — должны работать. Теперь, убедившись в успешном завершении установки, нужно удалить из корня документа два файла и поместить в него свои собственные
38 | Глава 2 HTML- и другие файлы (и любые необходимые вам подпапки), чтобы они сразу же стали доступны для просмотра путем обновления экрана браузера или указания в адресной строке локального хоста. А теперь давайте все протестируем, удалив файлы index.php и MAMP-PROLogo.png, сохранив в этой папке следующий пример (с именем файла index.html) и набрав в адресной строке вашего браузера localhost. Пример 2.1 1. 2. 3. 4. 5. 6. 7. 8. 9. <html lang="en"> <head> <meta charset="utf-8"> <title>My Webpage</title> </head> <body> <h1>Hey, it works!</h1> </body> </html> Если все в порядке, браузер выведет на экран текст, показанный на рис. 2.8. И тогда вас можно будет поздравить с установкой MAMP на ваш компьютер. Если же ничего не получится, еще раз внимательно прочитайте инструкции, приведенные в главе, и зайдите на веб-сайт MAMP, чтобы получить дополнительную информацию. Рис. 2.8. Отображение на экране нового HTML-документа Если вы решили воспользоваться другим набором программных средств WAMP, следуйте советам, изложенным в его инструкциях, где будет указано, как найти его корень документа и как убедиться, что его веб-сервер Apache запущен и готов к работе. Но в любом случае, теперь можно переходить к изучению следующей главы, посвященной установке второй части нашей среды разработки — Visual Studio Code от Microsoft.
Установка веб-сервера | 39 Установка под MacOS Привет пользователям Mac-систем! Ваш компьютер при запуске веб-сервера ничуть не уступает ПК по производительности, и вы можете воспользоваться той же программой, которая была рекомендована для Windows — MAMP. Это программное средство поставляется в двух версиях: базовой и профессиональной. Базовая версия бесплатна, а позже, если захочется, можно будет перейти и на профессиональную версию. Чтобы загрузить MAMP для MacOS, просто перейдите по адресу https://www.mamp.info, после чего должно состояться перенаправление в раздел веб-сайта для MacOS, где нужно будет щелкнуть по ссылке для загрузки под названием Free MAMP download (Бесплатная загрузка MAMP), и на появившейся странице следует выбрать MAMP & MAP PRO для той версии Mac, которая у вас установлена (Intel для MacOS 12.12 и выше или M1 для MacOS 11 и выше). На момент написания книги текущей была версия 6.6, но вам может попасться более свежая. После щелчка по ссылке загрузки может появиться всплывающее окно с предложением загрузить NAMO DBS App. Его лучше проигнорировать, щелкнув кнопкой мыши за пределами этого окна, чтобы оно исчезло. Нам пока это не пригодится, а позже, если захочется, можно будет вернуться к его загрузке. После загрузки нужно будет установить файл с расширением .pkg, щелкнув по ссылке на него, и тогда откроется окно, показанное на рис. 2.9 (при установленной версии для процессора Intel оно будет выглядеть несколько иначе). Рис. 2.9. Окно установки M1/arm MacOS
40 | Глава 2 После щелчка на кнопке Continue (Продолжить) появится всплывающее окно с просьбой принять условия; чтобы пройти дальше, нужно щелкнуть на кнопке Agree (Согласен). После этого скорее всего появится окно, показанное на рис. 2.10. Тогда для продолжения установки вам придется воспользоваться сенсорным идентификатором или паролем. Как только установка завершится, можно будет перейти в папку Applications (Приложения), где должен появиться только что установленный значок с надписью MAMP, на который теперь можно нажать для запуска сервера. Это, вероятнее всего, приведет к появлению окна, показанного на рис. 2.11, в котором нужно будет ввести свой пароль, чтобы получить возможность запускать и останавливать серверы и другие функции. Рис. 2.10. Проверка ваших учетных данных для продолжения Рис. 2.11. Для запуска вспомогательных инструментов введите свой пароль
Установка веб-сервера | 41 После запуска вспомогательных инструментов появится главное окно MAMP, где первым делом нужно будет в левом верхнем углу выбрать параметр Preferences (Настройки), а затем щелкнуть на вкладке Ports (Порты), где, как показано на рис. 2.12, для порта Apache нужно указать число 80. Рис. 2.12. Изменение порта Apache на 80 Дело в том, что при вводе в веб-браузер адреса localhost по умолчанию используется порт 80, поэтому именно его и нужно вводить, чтобы не пришлось вводить номера портов при каждом вызове локальной веб-страницы. Работа с корнем документа В файловой системе MacOS всегда есть корневой каталог или папка, доступные, как правило, через слэш-символ, например /. У веб-браузера есть аналогичный корень, называемый корнем документа. В этой роли необязательно должна выступать папка на диске корневого (или нижнего) уровня (и не должна быть таковой по соображениям безопасности). В ней будут файлы самого высокого уровня, к которым сервер будет предлагать доступ, и для разных веб-серверов (и даже для разных установок веб-сервера одной и той же марки) она будет находиться в разных местах. Для MAMP, при условии, что были приняты все значения по умолчанию, предложенные в ходе установки, корневой каталог документа можно будет найти по адресу /Applications/MAMP/htdocs.
42 | Глава 2 Изначально после первой установки в корне документа будет находиться файл с именем index.php. Доступ к местоположению корня документа можно получить через файловую систему, а имеющиеся там файлы — загрузить локально из вашего веб-браузера после ввода в его адресную строку http://localhost (или даже просто localhost). Исходный результат показан на рис. 2.13. Рис. 2.13. Отображение исходного файла index.php При желании или же по какой-то иной причине можно воспользоваться IP-адресами, зарезервированными на компьютерах для локального хоста, например: http://127.0.0.1 или просто 127.0.0.1. Если на экране появилось изображение, показанное ранее на рис. 2.7, значит, MAMP установлен правильно и все программные средства: PHP, MySQL и вебсервер Apache — должны работать. Теперь, убедившись в успешном завершении установки, нужно удалить из корня документа файл и поместить в него свои собственные HTML- и другие файлы (и любые необходимые вам подпапки), чтобы они сразу же стали доступны для просмотра путем обновления экрана браузера или указания в адресной строке локального хоста. А теперь давайте все протестируем, удалив файл index.php, сохранив в этой папке код примера (с именем файла index.html) и набрав в адресной строке вашего браузера localhost. Если все в порядке, в браузере появится изображение, показанное на рис. 2.14. И тогда вас можно будет поздравить с установкой MAMP на ваш компьютер. Если же ничего не получится, еще раз внимательно прочитайте инструкции, приведенные в главе, и зайдите на веб-сайт MAMP, чтобы получить дополнительную информацию.
Установка веб-сервера | 43 Рис. 2.14. Отображение на экране нового HTML-документа Если вы решили воспользоваться другим набором программных средств WAMP, следуйте советам, изложенным в его инструкциях, где будет указано, как найти его корень документа и как убедиться, что его веб-сервер Apache запущен и готов к работе. Но в любом случае, теперь можно переходить к изучению следующей главы, посвященной установке второй части нашей среды разработки — Visual Studio Code от Microsoft. Установка под Linux Приветствую тех, кто использует Linux! У вас, как известно, все немного подругому, и вы, наверное, уже привыкли к установкам всех необходимых вам программных средств. Но, если набор программных средств под названием LAMP на вашем компьютере не установлен, то из-за слишком большого количества различных версий операционной системы вам придется позволить установщику сделать это за вас. А так как набор программных средств Xampp поддерживает всевозможные версии, в том числе Debian, RedHat, CentOS, Ubuntu, Fedora, Gentoo, Arch, SUSE и многие другие, то именно им и рекомендуется воспользоваться. Для этого перейдите по адресу https://www.apachefriends.org/ и загрузите Linuxустановщик по вашему выбору (ориентируясь в основном на желаемую версию PHP, или же, если есть какие-то сомнения, остановив свой выбор на 64-битной версии 7.4.27 или ее аналоге). Каждый установщик занимает около 150 Мб и имеет расширение .run. При установке 64-битной версии 7.4.27 файлы с таким расширением нужно запускать из Ubuntu (и практически из всех других версий Linux) в следующем порядке: Откройте окно Terminal, перейдите в тот каталог, где был сохранен файл, и введите следующую (или ей подобную, в зависимости от имени загруженного файла) команду, чтобы убедиться, что файл исполняемый: chmod +x xampp-linux-x64-7.4.27-1-installer.run
44 | Глава 2 А затем для запуска программы установки введите следующую команду: run xampp-linux-x64-7.4.27-1-installer.run Работа с корнем документа В файловой системе Linux всегда есть корневой каталог или папка, доступные, как правило, через слэш-символ, например, /. У веб-браузера есть аналогичный корень, называемый корнем документа. В этой роли необязательно должна выступать папка в самом корне диске (и не должна быть таковой по соображениям безопасности). В ней будут файлы самого высокого уровня, к которым сервер будет предлагать доступ, и для разных веб-серверов (и даже для разных установок веб-сервера одной и той же марки) она будет находиться в разных местах. В случае использования Xampp корень документа обычно находится в Но поскольку доступ по записи в эту папку может быть открыт только с root-правами, вы можете создать символическую ссылку на ту папку, для которой у вас уже есть права на запись, например на предварительно созданную папку /home/web/, для чего нужно будет запустить следующую команду: /opt/lampp/htdocs/. ln -s /home/web /opt/lampp/htdocs/web Теперь можно будет сохранять файлы в папке /home/web, но получать к ним доступ в веб-браузере по адресу localhost/web. Это, конечно, не лучшее решение, и, если не хочется использовать поддомен /web вне локального хоста, вы можете научиться создавать новый виртуальный сервер или изменять корень вашего документа. Но данная книга не про Linux, и предполагается, что пользователи Linux с задачей обеспечения надлежащей настройки своего веб-сервера способны справиться своими силами. А здесь приводятся простые рекомендации, помогающие, если это нужно, приступить к предстоящей работе. Заключение Ну вот и все! Теперь самое сложное уже позади. В вашем распоряжении имеется работоспособный веб-сервер, позволяющий запускать и тестировать все примеры из этой книги без необходимости загружать их на удаленный рабочий сервер. Благодаря этому работа будет идти быстрее, безопаснее и проще. Осталось только предоставить вам в следующей главе достойный программный редактор, чтобы подготовить вас к роли настоящих мастеров HTML5 и CSS3.
ГЛАВА 3 Visual Studio Code Вступление Поскольку веб-страницы состоят в основном из текста, фактически для создания даже самых динамичных и привлекательных веб-сайтов понадобится всего лишь простой текстовый редактор. Но звучит это так, будто для создания великолепных цифровых образов понадобится всего лишь Microsoft Paint. Технически, если затратить на художественные творения немыслимую уйму времени, все верно, но захочется ли вам пройти этот путь? Вот тут-то и выходит на первый план полностью бесплатный редактор Visual Studio Code от компании Microsoft. Как правило, языки программирования от Microsoft весьма мощные и авторитетные, а Visual Studio Code (далее будем называть его VS Code) под стать им — мощный редактор, но при этом весьма простой и интуитивно понятный в использовании. Эти его качества стали настолько очевидны, что VS Code, похоже, становится чуть ли не фактическим стандартом для программирования и веб-разработки. Структура В этой главе рассматриваются следующие темы:  Оценка потенциала VS Code.  Изучение приемов установки VS Code на компьютер.  Изучение способом загрузки и редактирования файла в VS Code.  Порядок доступа к интерактивной среде редактирования, предлагаемой VS Code. Цели После изучения главы и выполнения всех рекомендуемых действий у вас будет установлен, готов к применению и освоен мощный редактор программного кода VS Code, позволяющий упростить веб-разработку и существенно повысить ее эффективность по сравнению с использованием обычного текстового редактора.
46 | Глава 3 Популярность VS Code В чем секрет популярности VS Code? Дело в том, что он быстрый, качественно спроектированный, с широкими возможностями настройки, предлагает удобные функции, например, редактирование с несколькими курсорами, разумное распознавание параметров, четкое форматирование кода и многое другое. Его использование ускорит цикл разработки почти для всех пользователей, особенно после того, как он распознает используемый вами язык (даже если это HTML или CSS) и услужливо предложит, что вводить по мере набора текста. Как только вы освоитесь, он станет волшебным помощником, пребывающим всегда на шаг впереди вас. Стоит только взглянуть на VS Code, работающий, как показано на рис 3.1, под управлением Windows, и сразу станет виден весь расклад предлагаемых настроек. Здесь используется темная тема, поскольку она может быть приятнее для глаз при длительных сеансах работы, но выбрать можно любую желаемую. Рис. 3.1. Редактирование HTML-файла в VS Code Обратите внимание, что в строке 4 после текста title видна левая угловая скобка — <, а затем был набран символ слэша — /, а VS Code предоставил закрывающую угловую скобку, в которой была явная потребность, после чего выдвинул наиболее удачное предположение о том, что в эти угловые скобки правильнее всего было бы впечатать /title. Теперь осталось только нажать клавишу Tab или Enter, или же переместить курсор на следующее редактируемое место, и автоматическая вставка будет принята. Кроме того, чуть выше кода HTML можно заметить, что VS Code проанализировал, где находится курсор в документе, и показывает уровень вложенности в этой точке. Разве можно опровергнуть, что это весьма разумно и может сэкономить уйму времени? А что еще лучше, VS Code доступен для всех операционных систем: Windows, MacOS и Linux. Итак, посмотрим, как этот редактор можно будет скачать и установить для каждой из операционных систем.
Visual Studio Code | 47 Установка VS Code под Windows Перейдите по адресу https://code.visualstudio.com/, щелкните на ссылке Download (Загрузить), а затем выберите загрузку, подходящую под вашу версию Windows. Загрузка должна начаться автоматически, и одновременно с ней в окне браузера появится вспомогательная страница Getting Started (Начало работы), предназначенная для ознакомления с функциями редактора в ожидании его загрузки. На возможный запрос о продолжении загрузки или об отказе от нее нужно выбрать Keep (Продолжить). После загрузки щелкните на кнопке запуска установщика, активируя установку, и примите лицензионное соглашение, установив правильный флажок, как показано на рис. 3.2, а затем щелкните на кнопке Next (Далее). Рис. 3.2. Для продолжения установки нужно принять соглашение Затем, как показано на рис. 3.3, вам будет предложено установить флажки для создания значка на Рабочем столе, а также для добавления пункта Open with Code (Открыть с Code) в контекстное меню Проводника, для регистрации Code в качестве редактора для файлов поддерживаемых типов и для соответствующей настройки глобальной переменной PATH, где уже будут установлены все рекомендуемые флажки (с чем нужно будет согласиться, за исключением флажка у PATH, установкa кото-
48 | Глава 3 рого потребует перезагрузки компьютера, и не окажет никакого влияния, по крайней мере, на начальном этапе работы). Рис. 3.3. Установите флажки рядом с нужными настройками Для продолжения щелкните на кнопке Next (Далее), чтобы открылось главное окно установки, где для ее запуска нужно будет щелкнуть на кнопке Install (Установить). Установка не займет много времени, и по ее завершении для выхода из установщика и запуска программы, если установлен флажок, предлагающий это, можно будет щелкнуть на кнопке Finish (Готово). В первую очередь нужно будет, как показано на рис. 3.4, выбрать пункт меню Help (Помощь), а затем щелкнуть на пункте Editor Playground (Интерактивная среда редактора). Это своеобразный интерактивный документ, позволяющий изучить все 10 основных областей использования VS Code. Чтобы после знакомства с VS Code и его возможностями приступить к редактированию, можно набрать в окне редактора код примера 3.1, или же, если вы загрузили прилагаемый к книге набор файлов примеров, можно воспользоваться для загрузки пунктом меню File (Файл), или просто перетащить показанный ниже текст примера 3.1 в окно VS Code. Пример 3.1 1. 2. <html lang="en"> <head>
Visual Studio Code 3. 4. 5. 6. 7. 8. 9. | 49 <meta charset="utf-8"> <title>My Webpage</title> </head> <body> <h1>Hey, it works!</h1> </body> </html> Рис. 3.4. Использование Interactive Editor Playground (интерактивной среды редактора) Установка VS Code под MacOS Установить VS Code на MacOS очень просто. Нужно перейти по адресу https://code.visualstudio.com/, щелкнуть на ссылке Download (Загрузить), а затем выбрать версию загрузки для Mac. Загрузка должна начаться автоматически, и одновременно с ней в окне браузера появится вспомогательная страница Getting Started (Начало работы), предназначенная для ознакомления с функциями редактора в ожидании его загрузки. У загруженного файла будет расширение .zip. Чтобы его разархивировать, нужно просто выбрать место его загрузки, которое обычно находится в папке Downloads (Загрузки). Добраться до этого места можно с помощью проводника Finder, выбрав пункт Go (Перейти), а затем Downloads (Загрузки). Теперь нужно запустить файл .zip точно так же, как любой программный файл, и содержимое будет извлечено в файл с именем Visual Studio Code (рис. 3.5).
50 | Глава 3 Рис. 3.5. Извлечение файлов из загруженного ZIP-файла Код VS Code можно запустить прямо отсюда, но все же лучше открыть другое окно проводника, выбрав в строке меню пункт File (Файл), а затем New Finder Window (Новое окно Finder). Теперь нужно выбрать пункт Go (Перейти), а затем пункт Applications (Приложения), чтобы из нового окна перейти в папку Applications (Приложения), и перетащить файл Visual Studio Code из папки Downloads (Загрузки) в папку Applications (Приложения). Рис. 3.6. Может открыться окно с предупреждением о запуске VS Code Теперь программа сохранена в нужном месте, и ее можно запустить обычным порядком, щелкнув на имени ее файла. В результате может открыться окно, показан-
Visual Studio Code | 51 ное на рис. 3.6, с предупреждением о запуске программ, загруженных Open из Интернета. В этом случае, чтобы продолжить, нужно щелкнуть на кнопке Open (Открыть), и VS Code будет запущен и готов к работе. В первую очередь нужно будет, как показано на рис. 3.7, выбрать пункт меню Help (Помощь), а затем щелкнуть на пункте Editor Playground (Интерактивная среда редактора). Это своеобразный интерактивный документ, позволяющий изучить все 10 основных областей использования VS Code. Рис. 3.7. Использование Interactive Editor Playground (интерактивной среды редактора) Чтобы после знакомства с VS Code и его возможностями приступить к редактированию, можно набрать в окне редактора код примера 3.1, или же, если вы загрузили прилагаемый к книге набор файлов примеров, можно воспользоваться для загрузки пунктом меню File (Файл), или просто перетащить текст примера 3.1 в окно VS Code, как показано на рис. 3.1 в начале главы, и, хотя там речь шла о версии для Windows, от версии для Mac код практически ничем не отличается. Установка VS Code под Linux VS Code также вполне подходит для ПК под управлением Linux и поддерживается всеми разновидностями этой операционной системы: Debian, Ubuntu, Red Hat, Fedora и SUSE (и, возможно, многими другими). Теперь, как и при установке LAMP, сам факт использования вами операционной системы Linux уже говорит о нарабо-
52 | Глава 3 танной привычке использования при установке различных программ командной строки. VS Code так же прост в установке, как и любое другое программное средство, и поставляется в версиях установщика .deb и .rpm, а также в версиях для различных чипсетов. А Linux-новичкам можно пояснить, что способ установки файла .deb в дистрибутивах Linux типа Debian заключается в вводе следующей команды (где следует указать имя того файла, который был загружен): sudo dpkg -i code_1.63.2-1639562499_amd64.deb Если используется дистрибутив с файлами .rpm, вводится следующая команда (где следует указать имя того файла, который был загружен): rpm -ivh code-1.63.2-1639562596.el7.x86_64.rpm Можно, конечно же, воспользоваться графическим интерфейсом, но здесь просто предлагается более привычный для вас способ. Если есть сомнения, обратитесь к инструкциям по вашей версии Linux. После установки VS Code первым делом нужно будет, как показано на рис. 3.7 (в разделе Установка VS Code под MacOS), выбрать пункт меню Help (Помощь), а затем щелкнуть на пункте Editor Playground (Интерактивная среда редактора). Это своеобразный интерактивный документ, позволяющий изучить все 10 основных областей использования VS Code. Чтобы после знакомства с VS Code и его возможностями приступить к редактированию, можно набрать в окне редактора код примера 3.1 (из раздела Установка VS Code под Windows), или же, если вы загрузили прилагаемый к книге набор файлов примеров, загрузить код примера оттуда, или просто перетащить текст примера 3.1 в окно VS Code, как показано на рис. 3.1 в начале главы, и, хотя там речь шла о версии для Windows, от версии для Linux код практически ничем не отличается. П РИМЕЧАНИЕ Чтобы ничего не усложнять, для приводимых в книге снимков экрана была выбрана только одна операционная система, поэтому далее снимки будут относиться к работе под Windows, так как именно эта операционная система наиболее востребована разработчиками, но в любом случае это мало что меняет. Начало работы с VS Code Итак, VS Code установлен на ваш компьютер под используемую вами операционную систему. Давайте попристальнее присмотримся к тому, как его использовать и что с ним можно сделать. Для этого рекомендуется загрузить бесплатный прилагаемый к книге архив с файлами примеров, а затем сохранить распакованное дерево каталогов непосредственно в корневой папке документа. Если помните, в главе 2 «Установка веб-сервера» предлагалось установить систему MAMP, и в Windows по умолчанию корневым каталогом документа будет C:/MAMP/htdocs. В MacOS им будет /Applications/MAMP/htdocs, а если устанавливался
Visual Studio Code | 53 Xampp в Linux, то обычно корневым каталогом будет /opt/lampp/htdocs/ или же будет использоваться символическая ссылка, которую вам предложат сделать для него: /home/web. После копирования всех файлов примеров в оговоренное место там должна появиться подпапка Examples, содержащая названия из ссылок на различные разделы и главы данной книги, а файлы примеров будут находиться в подпапках этих папок. Чтобы проверить при работающем веб-сервере, так ли это, нужно просто набрать в адресной строке браузера localhost, и просмотреть все примеры. Затем этот корневой каталог документа можно будет использовать в качестве домашнего каталога в VS Code, выбрав в меню пункт File (Файл), после него пункт Add Folder to Workspace… (Добавить папку в рабочую область) (как показано для версии под Windows на рис. 3.8), а затем в предоставленном диалоговом окне выбора файла, указав на корневую папку документа. При этом может появиться вопрос о том, доверяете ли вы авторам файлов, находящихся в этой папке, на который следует ответить Yes (Да). Рис. 3.8. Добавление папки в рабочее пространство VS Code Теперь все готово к загрузке примеров и работе с ними. Нужно выбрать еще раз пункт меню File (Файл) и загрузить из папки Section_1/03 файл example_01.html. Результат должен быть таким, как на рис. 3.9. Теперь можно поработать над тем, что по своей сути представляет простую оболочку веб-документа. Перейдем к строке 8 файла и просто для наработки практики добавим еще немного кода HTML в следующие строки: 8. <p>Here is a paragraph of additional text just to practice using VS Code for editing documents. </p>
54 | Глава 3 Рис. 3.9. Редактирование кода примера из этой главы Теперь даже без сохранения файла можно загрузить документ в используемый вами браузер в режиме отладки, нажав клавишу F5. Или же, если нужно просто загрузить документ без отладки, следует применить комбинацию клавиш Ctrl + F5. Любой из этих вариантов можно выбрать из меню запуска. Если в системе установлено более одного браузера (например, Chrome и Edge в Windows), то при первой попытке может быть предложено выбрать один из них. После этого выбранный браузер будет запускаться по умолчанию. Теперь VS Code готов к использованию в качестве редактора и отладчика одновременно, и вскоре станет понятно, что работать с примерами в этой книге проще некуда. Можно будет свободно экспериментировать, редактируя пример по своему усмотрению, что будет отличным способом полноценного освоения изучаемых функций. Конечно, VS Code — весьма основательная программа с множеством функций, позволяющих эффективно работать, набирая текст на клавиатуре (и манипулируя мышью), и имеющихся на данный момент сведений вполне достаточно для начала работы с ней и ее успешного применения. Полную документацию обо всех возможностях VS Code с ответами на все вопросы можно найти по адресу: https://code.visualstudio.com/docs. Заключение Мои поздравления! При изучении предыдущей главы была установлена среда WAMP, MAMP или LAMP, а при изучении этой — редактор Visual Studio Code, и теперь все практически готово для начала работы со всеми последующими примерами. Но в следующей главе нужно будет сделать еще один шаг — узнать порядок использования встроенной консоли разработчика вашего веб-браузера, позволяющей легко проверять и отлаживать ваш код.
ГЛАВА 4 Консоль разработчика Вступление Помнится, в прежние времена при веб-разработке, особенно при применении стилей с использованием CSS (или же расширенных функций CSS3), или же, возможно, при вставке кодового фрагмента JavaScript или функций HTML5, было нелегко понять, что при этом происходит, отследить какие-либо странные результаты или необычные ошибки. Чтобы выправить ситуацию, была создана консоль разработчика. С ее помощью можно просматривать все элементы блочной модели связки HTML-CSS до мельчайших подробностей и даже отправлять информацию на консоль при загрузке страницы или выполнении сценария JavaScript. В этой главе рассматриваются способы вызова консоли разработчика в различных браузерах, и целый ряд интересных приемов использования этой консоли, освоение которых позволит приступить к изучению курса по HTML5 и CSS3. Структура В этой главе рассматриваются следующие темы:  Сведения о консоли разработчика и ее назначении.  Чем различаются консоли разработчика.  Приемы вызова консоли в браузере.  Подготовка к отладке своих проектов с помощью консоли. Цели Изучив главу, вы научитесь использовать встроенную консоль разработчика вашего браузера с целью совершенствования своих веб-документов и CSS-стилей, а также применения консоли для создания исправно работающих динамичных вебсайтов и веб-приложений.
56 | Глава 4 Доступ к консоли разработчика В прежние годы помочь в отладке программ непосредственно из среды браузера могли различные приемы (изначально — просто вызовы функции document.write() для отображения значений переменных), но теперь ситуация существенно упростилась и приобрела стандартные формы, особенно с тех пор, как основной исходный код веб-браузера Google Chrome (ставшего мировым лидером) теперь включен во многие другие браузеры, в числе которых Microsoft Edge и Opera. В конкурентах остались только два других основных веб-браузера: Mozilla Firefox и Safari от Apple. Если усреднить разнящиеся показатели популярности браузеров, полученные от разных мониторинговых организаций, получится, что Google Chrome занимает около 60% рынка, Safari — 20%, Edge — 4%, Firefox — 4%, интернет-браузер Samsung — 3%, Opera — 2%, и около 7% — все остальные вместе взятые браузеры. С учетом этого, а также по факту доступности Google Chrome почти на всех платформах, этот браузер используется в данной книге по умолчанию, но в табл. 4.1 показано, как можно вызвать консоль разработчика в большинстве популярных браузеров. При желании консоль разработчика в большинстве браузеров можно вызвать из их меню. Как видите, на ПК обычно используется одна и та же комбинация клавиш, а в MacOS, как следует из той же таблицы, обычно есть два разных способа вызова консоли в зависимости от используемого браузера. Таблица 4.1. Комбинации клавиш для вызова консоли разработчика Браузер / Операционная система Windows / Linux Apple MacOS Google Chrome Shift + Ctrl + I Option + ⌘ + I Apple Safari (Не применяется) Option + ⌘ + C Microsoft Edge Shift + Ctrl + I Option + ⌘ + I Firefox Shift + Ctrl + I Shift + ⌘ + I Opera Shift + Ctrl + I Option + ⌘ + I Консоли разработчика — мощный инструментарий со многими функциями, но в данной главе состоится знакомство с основными, самыми необходимыми из них. То есть основная задача — показать способы их вызова и сообщить о том, что они предлагают. Приступив к разработке с помощью HTML5 и CSS3, вы неизменно станете полагаться (если уже не стали) на консоль разработчика как на постоянного помощника в программировании. Посмотрим, к примеру, на рис. 4.1. Это копия экрана, полученная при использовании Chrome под Windows, где в весьма простом и кратком веб-документе из примера 4.1 используется холст HTML5 для рисования в цвете множества Мандельброта.
Консоль разработчика | 57 Рис. 4.1. Консоль разработчика Chrome открыта и отображает информацию о документе Справа можно увидеть консоль разработчика с исходным кодом документа в верхнем правом углу и представлением текущей блочной модели под ним. При наведении курсором мыши по различным элементам они автоматически выделяются во всех трех окнах, предоставляя подробную и лаконичную информацию о структуре вашего документа. П РИМЕЧАНИЕ Как ни удивительно (возможно, не для всех), компания Microsoft привыкла, что браузером номер один считался Internet Explorer, но ей удалось свести на нет его фантастическое преимущество, не поспевая за последними разработками в Интернете и принимая решения о реализации функций своими, нестандартными способами. Вполне логичным результатом этого стал в последние годы вынужденный отказ Microsoft от собственной кодовой базы браузера и использование базы с открытым исходным кодом для Chrome, и теперь Edge и Chrome стали очень похожими. Но, поскольку у пользователей весьма долгая память, почти все они при покупке нового компьютера загружают вместо Edge другой браузер, хотя теоретически Edge должен предлагать все то же самое, что и Chrome. К счастью, в любом случае больше уже о странностях политики Microsoft нам беспокоиться не нужно, поскольку Edge и Chrome одинаковы во всех смыслах и целях, преследуемых при изучении книги. По тем же причинам на той же кодовой базе работает и браузер Opera.
58 | Глава 4 Пример 4.1 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Mandelbrot</title> </head> <body> <canvas id='canvas'></canvas> <script> canvas = document.getElementById('canvas') context = canvas.getContext('2d') w = 640 h = 480 canvas.width = w canvas.height = h z y rm rx ix im = = = = = = 16 0 -2 1 1.35 -ix for (i = im ; i <= ix ; i += (ix - im) / h, ++y) { for (x = 0, r = rm ; r <= rx ; r += (rx - rm) / w) { for (x1 = r, y1 = i, j = 0 ; j < z ; ++j) { xsq = x1 * x1; ysq = y1 * y1 if (xsq + ysq > 4.0) break y1 = 2 * x1 * y1 + i ; x1 = xsq - ysq + r } context.fillStyle = '#' + ( j % 16).toString(16) + ((j + 2) % 16).toString(16) + ((j + 7) % 16).toString(16) context.fillRect(x++, y, 1, 1) } } </script> </body> </html>
Консоль разработчика | 59 Объяснения, что такое Мандельброт или как его создать, лучше опустим, но если вы взглянете на строки 10–15 и 36–40, то сможете увидеть несколько команд на JavaScript, необходимых для рисования на элементе холста HTML5, которые будут рассматриваться в разделе 2 данной книги. Чтобы прикрепить консоль к любой выбранной вами стороне окна браузера или даже открыть ее в отдельном окне, нужно щелкнуть на значке из трех вертикально расположенных точек рядом со значком закрытия консоли. Если выбран браузер Firefox, то, как показано на рис. 4.2, который также является копией экрана ПК под управлением Windows, все будет выглядеть несколько иначе. Здесь можно увидеть, что консоль занимает нижнюю часть экрана, что является ее исходной позицией, но, если щелкнуть на значке настроек в виде трех горизонтальных точек рядом с кнопкой закрытия консоли, ее можно будет прикрепить к любой желаемой стороне или даже открыть ее в собственном окне. Рис. 4.2. В открытой в Firefox консоли разработчика отображается информация о документе Хотя все консоли похожи друг на друга, работать они могут немного по-разному, и пункты меню у них следуют в разном порядке, имеют разные имена и содержат разные элементы списка. После демонстрации данной особенности нет никакого смысла показывать все остальные консоли в разных браузерах и в разных операционных системах, поскольку для вас уже не будут неожиданностью их отличия друг от друга. Получается, что теперь только вам следует решить, какой именно браузер желательно использовать для разработки, хотя ближе к началу развертывания нового проекта (или по возможности даже в ходе разработки) настоятельно рекомендуется
60 | Глава 4 иметь доступ ко всем браузерам в нескольких операционных системах, чтобы ваши веб-страницы выигрышно выглядели в среде всех браузеров. После выбора наиболее предпочтительного браузера для разработки (здесь рекомендуется Chrome просто из-за его высокой популярности как среди пользователей, так и среди разработчиков) вам необходимо ознакомиться с предоставляемой им консолью разработчика, поэтому в табл. 4.2 приводится список различных URLадресов документации, которую рекомендуется хотя бы просмотреть, прежде чем приступить к работе: Таблица 4.2. Веб-сайты документаций по консоли разработчика разных браузеров Браузер(ы) Веб-сайт документации Chrome / Edge / Opera https://developer.chrome.com/docs/devtools/ Firefox https://firefox-source-docs.mozilla.org/devtools-user/ Safari https://support.apple.com/en-in/guide/safari-developer/ Польза, извлекаемая из работы с консолью Консоль разработчика обладает такой разнообразной и эффективной функциональностью, что сначала может возникнуть вопрос: а что можно сделать со всем многообразием ее функций? Чтобы навести вас на ряд идей по ее использованию в качестве инструмента для творчества и тестирования ошибок при разработке вебсайтов, рассмотрим несколько предложений. Прежде всего выясним: приходилось ли вам восхищаться, насколько хорошо скомпонована посещаемая вами веб-страница? А потом не возникала ли мысль, что было бы при изменении всего лишь одной какой-либо мелочи? Обычно, когда появляется идея по улучшению веб-страницы, вы ее отгоняете от себя, поскольку пришлось бы делать локальную копию страницы и всего ее содержимого, а затем вносить изменения. На заре становления интернет-технологий многие разработчики именно так и учились создавать свои собственные веб-страницы, копируя то, что уже было создано до них и пробуя разные варианты изменения кода. Но теперь можно сделать редактируемой всю веб-страницу и сразу же посмотреть, что будет на ней происходить, открыв консоль разработчика и введя следующую команду: document.body.contentEditable=true Теперь на загруженной в данный момент веб-странице можно редактировать любое содержимое и сразу видеть получаемый от этого эффект. Получается, что этот инструмент отлично подходит для тестирования новых заголовков и других макетов. Конечно, изменяться будет только локальная копия в вашем веб-браузере, а не сама веб-страница на веб-сайте. Из всего этого следует, что в вашем распоряжении теперь есть просто фантастический инструмент для тех случаев, когда попадается привлекательный веб-сайт, и хочется увидеть, как он станет выглядеть после вне-
Консоль разработчика | 61 сения конкретных изменений, и понять, захочется ли вам реализовать какой-либо эффект или функцию, которую желательно было бы увидеть на вашей собственной веб-странице. Когда закончите экспериментировать и захотите испробовать вносимые изменения, введите в консоль следующую команду, предварительно вызвав ее подходящим для вашего компьютера способом, указанным в табл. 4.1: document.body.contentEditable=false Автозавершение Итак, первая предложенная идея была просто развлечением, привлекающим к использованию консоли. А теперь подойдем к делу посерьезнее и оценим ее возможности применительно к коду примера 4.1, который сначала нужно загрузить в браузер (в идеале, используя бесплатно загружаемый архив прилагаемых к книге примеров, чтобы не приходилось вводить код вручную). Рис. 4.3. Слово «canvas» в выпадающем меню В этом примере содержится несколько элементов HTML: раздел <html>, <head>, и раздел <script>. Все пока что непонятное объясняется по мере чтения книги. Предположим, что нужно узнать ширину элемента холста, не имея доступа к исходному листингу и не испытывая особого желания копаться в строках кода, чтобы выяснить это, но при этом известно, что у холста есть идентификатор canvas. <title>, <body>, <canvas> Достаточно просто начать вводить этот идентификатор в поле консоли, и сразу же после введения первой буквы c появится выпадающее меню, показанное на рис. 4.3, со всеми возможными вариантами продолжения. Теперь можно просто выбрать из списка слово canvas, добившись тем самым выделения холста на веб-странице, а затем ввести символ точки (.), а после — две первые буквы указателя ширины — wi, и появится выпадающее меню, показанное на рис. 4.4.
62 | Глава 4 Рис. 4.4. Нажав всего пару клавиш, удалось найти свойство ширины холста width Нужно просто выбрать в меню слово «width» и, как показано на рис. 4.5, консоль тут же сообщит, что ширина холста составляет 640 пикселей, не придется даже нажимать клавишу Enter. Правда же, быстро и удобно? Рис. 4.5. Теперь отобразилась ширина холста Занимаясь этим свойством, ему можно добавить присвоение значения, изменив ширину холста. А теперь посмотрим, что произойдет, если изменить CSS-стиль холста, используя следующую инструкцию: canvas.style.opacity = .5 При вводе этой инструкции сразу же станет заметно, что изображение на холсте, как показано на рис 4.6, стало наполовину прозрачным. Давайте научимся получать доступ к CSS-стилям элементов из консоли. Сначала нужно указать имя идентификатора элемента, затем поставить точку, набрать слово «style», снова поставить точку, чтобы выбрать свойства CSS-стиля этого элемента, ввести имя свойства, поставить за ним знак равенства (=), и, наконец, ввести значение, присваиваемое этому свойству.
Консоль разработчика | 63 Рис. 4.6. Установлена половинная прозрачность изображения холста В тех случаях, когда в свойстве CSS используется дефис для разделения имени свойства на два слова, следует удалить дефис и установить первую букву второго слова в верхний регистр. Это связано с тем, что дефис в JavaScript — знак минус, поэтому был выбран другой способ доступа к свойствам CSS. К примеру, чтобы установить для свойства холста margin-top значение 50 пикселей, можно ввести следующую инструкцию: canvas.style.marginTop = '50px' Как только это будет сделано, над холстом сразу же будет помещено пустое поле размером 50 пикселей. Просмотр элементов Еще один отличный способ получения информации об элементах — их просмотр. Сделать это можно, указывая на различные элементы в разных частях консоли и щелкая на них кнопкой мыши, или же введя текстовую команду с целью перехода к
64 | Глава 4 любому интересующему элементу. Давайте сделаем это с холстом, воспользовавшись функцией inspect(): inspect($('canvas')) В команде вызывается функция просмотра inspect, которой передается значение $('canvas'), являющееся инструкцией браузеру на получение элемента по его идентификатору, где $ — сокращение гораздо более длинного JavaScript-вызова getElementById(). В результате будет отображена показанная на рис. 4.7 вкладка консоли Элементы (Elements). Рис. 4.7. Различные сведения об элементах холста перечисляются во вкладках «Элементы» («Elements») и «Стили» («Styles») В верхней части консоли можно увидеть копию исходного веб-документа с выделенным элементом холста. Затем чуть ниже на вкладке Стили (Styles) показаны два только что примененных к холсту стиля, а под ними сообщается, что соотношение сторон холста — 640 x 480 пикселей. На первый взгляд, сразу после ввода одной инструкции inspect() становятся видны все детали, сведения о которых могут понадобиться. Несложно представить, что консоль разработчика предоставляет гораздо более широкие возможности, но теперь уже сформировалось, по крайней мере, представление о некоторых из них. Подробную информацию о консоли разработчика, по сведениям разработчиков Google Chrome, можно найти по следующему адресу (функции на всех других консолях разработчиков должны быть схожими, если не точно такими же): https://tinyurl.com/devcons
Консоль разработчика | 65 Заключение Не настало еще то время, когда все браузеры станут работать одинаково, но мы к нему уже намного ближе, чем когда-либо. К счастью для пользователей, нашими разработками в плане работы и отображения информации браузеры действительно очень близки друг к другу, и все же разработчикам еще приходится сталкиваться с различными закулисными странностями. Исходя из вышесказанного, все браузеры предлагают одни и те же мощные функции, просто доступ к ним в разных браузерах и операционных системах может осуществляться немного разными способами. В ходе чтения книги могут встречаться просьбы что-либо проверить с помощью консоли разработчика (например, просмотреть журнальный вывод), и вам уже известно, что это значит и как выполнить поставленную задачу. Вот теперь все готово, чтобы всерьез приступить к занятиям веб-разработкой на HTML5, начинающейся в разделе 2 (а затем и CSS3 в разделе 3), и с интересом ждать продолжения, поскольку оно обещает поразить вас тем, с какой легкостью можно будет добавлять невероятный арсенал новых функций и повышать интерактивность разрабатываемых вами веб-проектов.
ГЛАВА 5 Введение в HTML5 Введение По названию можно подумать, что HTML5 — просто очередная версия HTML, но это не так; в эту технологию заложено нечто большее. Чтобы уяснить это, нужно понять, что веб-разработка — своеобразное сближение и слияние технологий, и, хотя речь может идти о HTML5 и CSS3, они в известном смысле также переплетаются и взаимодействуют с JavaScript. Попытка полностью обособить HTML5 обречена на провал, поскольку весьма существенная часть спецификации HTML5 зависит от использования как CSS3, так и JavaScript, но мы приложим все силы, чтобы различать их везде, где только можно, а затем укажем, где именно размываются границы между ними. Например, одна из наиболее важных особенностей HTML5 — применение нового элемента холста <canvas>, но воспользоваться им можно только с помощью инструкций на языке JavaScript. С другой стороны, некоторые графические эффекты, проявляющиеся на холсте, также могут быть получены с помощью преобразований, присущих CSS3. Поэтому зачастую лучше думать о триаде HTML5, CSS3 и JavaScript, и в данной книге будет показано, как все три технологии интегрируются друг с другом. Но тем из вас, кто не считает себя программистом, не стоит волноваться: изучать программирование на JavaScript в полном объеме не придется, поскольку к холсту HTML5 и другим функциям HTML можно получить доступ с помощью весьма простого подмножества инструкций JavaScript, которые несложно выучить, так как они используются больше как расширение HTML, чем что-либо иное. И все же не стоит выстраивать предположения, что все сведется к изучению новых HTML-тегов и атрибутов, поскольку HTML5 — нечто большее. После всего сказанного давайте начнем с выяснения, что именно HTML5 привносит в набор инструментов программиста, делая при этом основной упор на новые элементы. Структура В этой главе рассматриваются следующие темы:  Все новые функции HTML5.
68 | Глава 5  Основные особенности работы этих функций.  Несколько примеров в ваш арсенал.  Особенности использования HTML5. Цели Здесь состоится знакомство со всеми основными технологиями и функциями, входящими в состав HTML5. Изучив предлагаемый материал, вы поймете, какие новые инструменты доступны в HTML5, и будете готовы приступить к изучению порядка их использования для достижения наивысших результатов при разработке ваших собственных проектов, следуя информации, представленной в остальных главах этого раздела. HTML5 гораздо серьезнее, чем просто HTML4 + 1 Во введении к главе уже говорилось, что HTML5 — это не просто очередная версия HTML, а нечто гораздо большее. Но давайте подойдем к исследованию того, чем по сути является HTML5, внимательно изучив те части этой спецификации, которые представлены новыми функциями языка HTML. Завершив эту работу, мы перейдем к рассмотрению той части спецификации HTML5, где начинают стираться ее границы с другими технологиями. А поскольку в поле нашего зрения уже попадал новый элемент под названием холст (canvas), то с него и начнем. Элемент <canvas> Чего так долго не хватало в HTML — это возможности рисования и манипулирования графикой. Сначала эта проблема была исправлена с помощью элементов управления Microsoft ActiveX, а затем с помощью плагина Adobe Flash. Но они оказались сбойными и открывали слишком много уязвимостей с точки зрения безопасности. Кроме того, они требовали установки, а нужно было встроенное решение. П РИМЕЧАНИЕ Проблемы с этими плагинами, и, в частности, с Flash, были настолько велики, что автор этой книги еще в 2015 году опубликовал статью в журнале Computer Weekly Magazine под названием «Why HTML Must Replace Flash» («Почему HTML должен заменить Flash»), подробно описав все основные связанные с плагинами проблемы, и объяснив, почему спецификация HTML5 была вполне очевидным решением. Если интересно, полная версия статьи, объясняющая сложившуюся на то время ситуацию, до сих пор доступна по адресу https://tinyurl.com/ flash-html5.
Введение в HTML5 | 69 Основным ответом на Flash (наряду с добавлением аудио- и видеофункций) стал элемент <canvas>, который впервые был поддержан компонентом MacOS WebKit еще в 2004 году, повышавшим эффективность использования браузеров Dashboard и Safari. В 2006 году его поддержка была добавлена в Firefox и Opera, и только потом Рабочая группа Web Hypertext Application Technology Working Group (WHATWG) добавила этот элемент в качестве стандарта, а такие браузеры, как Google Chrome, включили его в свой состав в 2010 году. Это один из примеров того, как происходило поэтапное развитие веб-стандартов, и напоминание о тех днях, когда для обнаружения запущенного браузера с целью определения доступности тех или иных функций приходилось включать в вебстраницу условный код. Это был сущий кошмар для разработчиков, который теперь уже, к счастью, развеялся как дурной сон, поскольку соблюдение спецификации HTML5 теперь считается вполне состоявшимся фактом. Следует все же заметить, что в дальнейшем, наверное, не обойдется и без появления новых вебтехнологий, в связи с чем понадобится некоторое время, чтобы отшлифовать их во всех браузерах, добившись однообразного внешнего вида и стиля их работы. Как бы то ни было, но теперь при правильной настройке элемента холста в HTML и включении в код всего лишь нескольких инструкций на JavaScript, мы располагаем фантастически мощными средствами рисования непосредственно в браузерной среде. Разъяснения даются в следующей главе, а пока на рис. 5.1 изображен элемент холста, в котором нарисован прямоугольник с заполненным цветовым градиентом, полученный путем использования простых команд из следующего примера: Рис. 5.1. Прямоугольник, заполненный цветовым градиентом, на элементе холста HTML5
70 | Глава 5 Пример 5.1 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Gradient Example</title> </head> <body> <canvas id='canvas'></canvas> <script> canvas = document.getElementById('canvas') context = canvas.getContext('2d') w = 640 h = 320 canvas.width = w canvas.height = h gradient = context.createLinearGradient(0, 0, w, 0) gradient.addColorStop("0", gradient.addColorStop(".25", gradient.addColorStop(".50", gradient.addColorStop(".75", gradient.addColorStop("1.0", "magenta") "blue") "green") "yellow") "red") context.fillStyle = gradient context.fillRect(0,0,640,320) </script> </body> </html> Геолокация Одной из самых заметных новых функций, необходимых для мобильного просмотра содержимого в Интернете, считается геолокация. С ее помощью можно вызвать карту своей местности, если заблудились, или же найти ближайшие заправочные станции или другие объекты. К сожалению, для полноценного использования геолокации несведущим в программировании все же понадобятся весьма незначительные знания JavaScript, позволяющие воспользоваться всего лишь несколькими строками кода, которые потом можно будет вырезать и вставлять в новый код. Например, на рис. 5.2 показана карта, отображенная на экране в результате поиска места, где используется веб-браузер (в данном случае — юго-восток Англии). Документ, использованный для создания этого снимка экрана, можно увидеть в примере 5.2. Опустим пока вопрос о том, как это работает, поскольку подробный ответ на него можно будет найти в главе 12 «Применение геолокации», а пока просто посмотрите на строку 8, в которой фигурируют две функции: granted (предоставлено)
Введение в HTML5 | 71 и denied (отказано). Дело в том, что пользователь сам решает, раскрывать ли свое местоположение браузеру или нет, поскольку это может быть сопряжено с угрозами безопасности. Рис. 5.2. Карта, отображаемая в результате геолокационного поиска Пример 5.2 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. <!DOCTYPE html> <html lang="en"> <head> <title>Geolocation Example</title> </head> <body> <script> navigator.geolocation.getCurrentPosition(granted, denied) function granted(position) {
72 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. | Глава 5 var lat = position.coords.latitude var lon = position.coords.longitude alert("Permission Granted. You are at location:\n\n" + lat + ", " + lon + "\n\nClick 'OK' to load " + "Google Maps with your location") window.location.replace("https://www.google.com/maps/@" + lat + "," + lon + ",8z") } function denied(error) { var message switch(error.code) { case 1: message = case 2: message = case 3: message = case 4: message = } 'Permission Denied'; 'Position Unavailable'; 'Operation Timed Out'; 'Unknown Error'; break; break; break; break; alert("Geolocation Error: " + message) } </script> </body> </html> Если пользователь не против, в строке 10 вызывается функция с именем granted, в противном случае в строке 23 запускается функция с именем denied. В первом случае координаты ищутся и передаются на карту Google для отображения, а во втором указывается причина, по которой карта не может быть отображена. Конечно, рабочий веб-сайт выдаст больше, чем просто краткое сообщение об ошибке, но этот код предназначен только для объяснения того, что происходит. И, как уже говорилось, не переживайте, если что-то непонятно, все станет ясно по мере чтения книги. Формы Использование форм в HTML5 подверглось целому ряду усовершенствований. Например, теперь теги <input> можно размещать вне тегов <form> и </form>, если для идентификации формы, к которой относится ввод, используется новый атрибут form. Точно так же с помощью нового атрибута formmethod можно изменять метод (выбирая GET или POST).
Введение в HTML5 | 73 Также имеется несколько усовершенствований, позволяющих изменять тип кодировки формы, создавать или даже переопределять новый атрибут novalidate. Для изменения действия (или, иначе говоря, назначения) формы можно также воспользоваться атрибутом formaction, а для изменения места отображения ответа на фрейм, вкладку или окно можно воспользоваться атрибутом formtarget. Наряду с этим с помощью атрибутов height и width можно изменять высоту и ширину типа image тега <input>. Кроме этого, как показано на рис. 5.3, в поисковой системе Google можно увидеть в повседневном применении несколько наиболее удобных новых атрибутов. Это автозаполнение, которое позволяет предлагать для поля заранее заготовленные значения, и автофокус, заставляющий браузер автоматически фокусироваться на поле формы. Рис. 5.3. Поисковая система Google, предлагающая выбор входных данных На рисунке показано, какие подразумеваемые вами поисковые запросы считаются наиболее вероятными, поскольку в наборе заранее заготовленных входных данных,
74 | Глава 5 доступных для выбора из форм HTML5, также содержатся новые атрибуты min, max и step, позволяющие четче управлять вводом таких данных, как числа или даты, а кроме того, для отправки сразу нескольких значений в сочетании с тегом <input> можно воспользоваться новым атрибутом multiple. Теперь с помощью атрибута pattern в формах можно воспользоваться сопоставлением с шаблонами, а отображение в поле ввода подсказки, помогающей пользователю сориентироваться в том, что нужно вводить, позволит применение нового атрибута placeholder. Кроме того, для атрибута type поддерживается ряд новых значений, включая color, date, month, time, week, number, range, Tel, url и email (цвет, дата, месяц, время, неделя, число, диапазон, телефон, URL-адрес и адрес электронной почты). С их помощью вы можете обеспечить ввод в ваши формы правильных значений и существенно упростить пользователю это действие. Есть и другие, не упомянутые здесь, важные усовершенствования работы с формами, рассматриваемые в главе 13 «Работа с формами». Локальное хранилище и хранилище сеансов Когда наступит пора создания по-настоящему интерактивных и динамичных вебстраниц, вы неизбежно столкнетесь с моментом исчерпания возможностей cookieфайлов по обеспечению максимально отзывчивой среды. Более того, во многих странах действуют строгие правила использования cookie-файлов, следовательно, придется часто добавлять предупреждения и запрашивать согласие на их использование. А что еще хуже — размер cookie-файлов ограничен всего лишь 4 Кб данных. Но для решения означенных задач есть более подходящий способ — использование локального хранилища, позволяющего пользователям быстро и легко перемещаться по веб-сайтам, сохраняя информацию о своих сеансах серфинга в этом хранилище. Локальным хранилищам для каждого веб-сайта предлагается до 5 Мб информации в легкодоступном формате пар ключ/данные. Дополнительное преимущество, в отличие от cookie-файлов, которые могут поддерживать доступ к множеству различных веб-сайтов (и, следовательно, использоваться для отслеживания поведения в Интернете), состоит в том, что доступ к хранящимся данным может получить только сайт, сохраняющий их в локальном хранилище. Данные остаются закрытыми для всех, кроме пользователя и веб-сайта. Смысл хранения информации на компьютере пользователя — избавление от необходимости многократной отправки ему одних и тех же данных. Если же просто хранить cookie-файлы, к примеру, с парой имя пользователя/пароль, можете полностью персонализировать сайт под нужды пользователя, отправляя ему соответствующие данные для каждой просматриваемой веб-страницы. Например, в локальном хранилище пользователя можно хранить содержимое его корзины (или что-то еще, что нужно отслеживать). А с помощью локального хранилища можно усовершенствовать естественное кэширование веб-страниц, подпадающих под управление вашим браузером (при ко-
Введение в HTML5 | 75 тором он сохраняет содержимое документов, вызывая их из памяти при возврате на ранее посещенную страницу и экономя ресурсы на времени загрузки и данных), а также сохраняя данные, которые в противном случае не были бы кэшированы в системе пользователя. Иметь доступ к 5 Мб данных в виде пар ключ-данные — все равно, что иметь своеобразную мини-базу данных, доступную на компьютере пользователя, следовательно, появляется возможность создания локальных веб-приложений, не хранящих данные на удаленном сервере, пригодные к полностью автономной работе. Это существенно повышает гибкость и вариативность в вопросах выбора порядка хранения и управления данными пользователя, а в главе 14 «Локальное хранилище и многое другое» будет показано, как доступ к локальному хранилищу осуществляется с помощью всего лишь нескольких простых строк кода на JavaScript. Хранилище сеансов ничем не отличается от локального хранилища, за исключением того, что хранящиеся в нем данные стираются при закрытии или перезапуске браузера, что превращает его в наиболее приемлемое решение для веб-сайтов и приложений с повышенными требованиями в вопросах безопасности, не приемлющих долгосрочное хранение информации. Это хранилище также рассматривается в главе 14 «Локальное хранилище и многое другое». П РИМЕЧАНИЕ Есть еще один тип локального хранилища под названием IndexedDB, предлагающий в зависимости от браузера (и в случае предоставления его пользователем) хранение от гигабайта и более данных, и, как следует из его названия, с ним для доступа к данным можно использовать индексы, что делает его гораздо более мощным по сравнению со стандартным локальным хранилищем. Но в книге этот тип хранилища не рассматривается, поскольку для его использования требуется предварительное знание порядка работы индексированных баз данных и более глубокие познания в использовании языка JavaScript. Интересующимся можно для начала посоветовать веб-сайт tinyurl.com/using-indexdb, где также можно будет узнать о библиотеках, применяемых для упрощения задачи программирования. Микроданные Один из аспектов HTML5, польза от которого в большей мере проявляется при продвижении вашего сайта в поисковых системах, — использование микроданных. Это новый набор тегов, которыми можно воспользоваться для точного объяснения, какие именно данные представлены в HTML-содержимом. Например, такой системе, как Google, можно сообщить, какие именно слова — имена людей, а какие — названия должностей, какие части адреса — названия улицы, города и т. д., какие строки текста относятся к организации, где работает человек, какие элементы текстов — названия специальностей и т. д.
76 | Глава 5 Имея все эти уточняющие данные, поисковые системы способны гораздо успешнее разобраться в документе, а затем найти более удачные соответствия поисковых запросов людей с содержимым ваших страниц. Все доступные теги и атрибуты микроданных будут рассматриваться в главе 14 «Локальное хранилище и многое другое», что станет весьма существенным подспорьем для тех, кому когда-либо придется заниматься поисковой оптимизацией (SEO), добавляя мощный набор инструментов в арсенал новичка. Другие семантические теги В спецификацию HTML5 также было включено много новых синтаксических функций, не считающихся микроданными, но служащих для дальнейшего объяснения содержимого веб-страницы поисковым системам (например, программам озвучания текста для слепых). Появились новые теги <summary> и <details>, а также новые элементы структуры страницы, в числе которых <main>, <section>, <article>, <header>, <footer>, <aside>, <nav> и <figure>, рассматриваемые в главе 14 «Локальное хранилище и многое другое». Веб-воркеры и приложения Источником нескольких других функций стала так называемая Рабочая группа вебприложений — Web Apps Working Group (WAWG). Их частичное поглощение спецификацией HTML5 состоялось в 2015 году, когда они были переданы Рабочей группе веб-платформы — Web Platform Working Group (WPWG). И теперь почти все они считаются частью HTML5, хотя изначально это и не планировалось. Первой из них считаются веб-воркеры, позволяющие перенести сложные задачи обработки в отдельный документ, содержащий инструкции JavaScript. Идея заключается в том, чтобы позволить им работать в фоновом режиме с максимальной скоростью, по мере необходимости обмениваясь сообщениями с задачей первого плана. Веб-воркеры не могут быть прерваны щелчками кнопками мыши или другими средствами взаимодействия с пользователем, поэтому они работают быстро и эффективно. Но, если по неосторожности допустить ошибку, веб-воркеры могут непредсказуемо выйти из-под контроля. Как правило, чтобы организовать фоновую обработку данных в среде JavaScript, нужно настроить постоянно вызываемый таймер, предоставляя доли процессорного времени одной или нескольким функциям, которые затем должны быстро выполнять небольшую часть работы и возвращать управление, чтобы не замедлять работу браузера и не снижать его отзывчивость. Веб-воркеры требуют знания JavaScript, но не-программисты могут просто скопировать и вставить код из главы 14 «Локальное хранилище и многое другое» или же не обращать внимание на веб-воркеры, поскольку они по большому счету нишевая технология.
Введение в HTML5 | 77 Веб-приложения Наряду с веб-воркерами появилась концепция веб-приложений, представляющих собой группы веб-страниц, которые можно загружать и рассматривать как отдельное приложение. Некоторые мобильные веб-сайты именно так и выглядят, работая в автономном режиме сродни приложениям, загруженным из магазина. Эта технология также относится к применению расширенных функций HTML5, и читатели, не считающие себя программистами или в настоящее время не испытывающие в ней необходимость, могут смело пропустить раздел о веб-приложениях в главе 14 «Локальное хранилище и многое другое». Аудио и видео Наверное, самым популярным дополнением к спецификации HTML стало включение в нее таких средств мультимедиа, как аудио и видео. Наконец-то появились способы воспроизведения большинства основных типов мультимедиа без использования подключаемых модулей и спагетти-кода, обеспечивающие за счет применения мощных и быстрых процедур сжатия и распаковки (посредством так называемых кодеков) высокое качество при узкой полосе пропускания. И это факт. Похоже, прошли уже те времена, когда необходимо было иметь копию Flash, чтобы воспроизводить созданные вами анимации или показывать в своем блоге домашнее видео. Теперь все сводится к вставке в код пары тегов <audio> и </audio> или <video> и </video> и указанию ссылки на медиафайл (находящийся на вашем сервере или в другом месте). Использование аудио Пока не будем подробно рассматривать сам процесс, ограничившись иллюстрацией той простоты, с которой звук добавляется на веб-страницу. Взгляните на код примера 5.3, запуск которого выведет на экран изображение, показанное на рис. 5.4. Рис. 5.4. Воспроизведение короткого аудиофайла в формате MP3
78 | Глава 5 Как видите, вся работа выполняется в строках 8–10, где используется тег <audio> с включенными пользовательскими элементами управления, а источник звука — файл example.mp3, расположенный в текущей папке. Пример 5.3 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. <!DOCTYPE html> <html lang="en"> <head> <title>Audio Example</title> </head> <body> <h1>Playing Audio</h1> <audio controls> <source src='example.mp3'> </audio> </body> </html> Использование видео Судя по коду, показанному в примере 5.4, видео вставляется в веб-страницу так же легко, а при запуске кода на экране появляется изображение, показанное на рис. 5.5. В строках 8–10 этого примера используется тег <video>, применяемый для вставки видеоклипа размером 640 на 360 пикселей с отображением пользовательских элементов управления. Видео хранится в локальной папке в файле example.mp4. Пример 5.4 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. <!DOCTYPE html> <html lang="en"> <head> <title>Video Example</title> </head> <body> <h1>Playing Video</h1> <video controls width='640’ height='360'> <source src='example.mp4'> </video> </body> </html> Видите, с какой поразительной легкостью можно включать мультимедиа в свои веб-страницы? А в главе 15 «Аудио и видео» будут представлены и другие функции, которыми также можно будет воспользоваться для дальнейшего совершенствования способа их отображения и воспроизведения.
Введение в HTML5 | 79 Рис. 5.5. Воспроизведение короткого видеофайла в формате MP4 (автор Ruitong Yu, файл взят с сайта pixabay.com) SVG и MathML В спецификацию HTML5 также включена поддержка двух невероятно эффективных технологий: SVG и MathML. Обе они представляют собой способы графического рисования на веб-странице без использования холста. Scalable Vector Graphics (SVG) позволяет выводить масштабируемую векторную графику прямо на вебстраницу. Ее можно использовать для рисования изображений буквально на лету, масштабировать их по своему усмотрению без потери качества (что невозможно проделывать с растровыми изображениями форматов PNG, GIF или JPG), а также создавать при помощи этой технологии анимацию, и все посредством обычных текстовых файлов формата XML или ряда графических инструментов, доступных для упрощения операций. В отличие от SVG, технология MathML предназначена для математиков и ученых, испытывающих потребность в отображении сложных формул и уравнений, не обеспечиваемую средствами HTML или ASCII. Более того, MathML сохраняет значение формулы, благодаря чему ее можно выразить в различных формах, не исключая вывод на печать или даже преобразования текста в речь.
80 | Глава 5 К сожалению, эти две технологии слишком объемны, и охватить их в данной книге не представляется возможным, поскольку для полного изучения каждой из них потребовалась бы отдельная книга. Но, как бы то ни было, теперь вы в курсе, что они доступны, и, если они вас впечатлили, получить сведения о них можно по следующим URL-адресам:  tinyurl.com/using-svg  tinyurl.com/using-mathml Заключение Теперь у вас появилось общее представление о том, что такое HTML5, чем была вызвана необходимость подобной эволюции HTML и как функции, включенные в данную спецификацию, способны помочь вам в создании высококачественных вебдокументов. Вы узнали, насколько легко аудио и видео добавляются на ваши вебстраницы, как узнать, где именно находится пользователь (если он дал на это согласие), как рисовать на холсте, а также как использовать семантические и синтаксические элементы, чтобы документы на вашем веб-сайте приобрели конкретный смысл для поисковых систем, а также для приложений, которые должны в них разбираться, в частности, для программ чтения с экрана для слепых. В следующей главе начнется по-настоящему серьезная работа, позволяющая понять, как и зачем создавать впечатляющую веб-графику, овладев приемами использования холста с применением элемента <canvas>.
ГЛАВА 6 Использование холста в HTML5 Введение В этой книге HTML5-тегу <canvas> посвящено немало страниц, и все потому, что это одно из самых эффективных и значительных нововведений в HTML. В нем воплотились практически все функции, ранее предоставлявшиеся такими плагинами, как Flash, но в весьма безопасном и простом для использования виде. Для применения холста придется немного ознакомиться с языком JavaScript, но фактически все сведется к изучению всего лишь нескольких команд рисования, которые ничуть не сложнее освоить, чем HTML или даже CSS. В качестве бонуса, благодаря вновь полученным знаниям, вы уже проложите маршрут к дальнейшему освоению JavaScript, позволяющий реализовать возможное решение о добавлении этого языка в свой арсенал инструментов веб-разработки. Но не стоит переживать, я обещаю, что с точки зрения программирования все сведется к созданию списка покупок в порядке появления товаров в вашем местном супермаркете. Это не более чем вопрос подачи нескольких команд в надлежащем порядке. И все будет эффективно спрограммировано или, с позиции холста HTML5, — нарисовано. Структура В этой главе рассматриваются следующие темы:  Сведения о холсте HTML5 и порядке получения доступа к нему.  Освоение приемов передачи идентификаторов элементов в JavaScript.  Изучение порядка использования контекста для управления рисованием на холсте.  Способы преобразования холстов в изображения. Цели Здесь состоится знакомство с элементом холста HTML5. Также будут освоены азы JavaScript, позволяющие рисовать прямоугольники разных цветов и даже преобра-
82 | Глава 6 зовывать холсты в изображения. Тем самым пройдет подготовка к изучению более сложных методов рисования, предстоящему в следующих главах. Ускоренный курс JavaScript Чтобы в полной мере воспользоваться всеми преимуществами, предоставляемыми HTML5, нужно освоить азы JavaScript. Поскольку наилучший момент для этого настал именно сейчас, давайте сразу нырнем поглубже и приступим к программированию. Вставка кода JavaScript в HTML-документы происходит внутри двух инструкций Зачастую они размещаются в разделе заголовка документа, чтобы обеспечить ранний запуск кода в ходе загрузки страницы, но разделы кода JavaScript можно увидеть и в других местах, например в теле документа. <script> … </script>. Существует два способа вставки кода. Первый — ввести его между двумя тегами, а второй — сохранить в отдельном документе и загрузить. Первый способ чаще всего используется для очень коротких фрагментов кода, а второй больше подходит для вставки более длинных сценариев. Давайте рассмотрим оба способа. Размещение кода внутри тегов <script> Взгляните на код примера 6.1, где показан типичный документ HTML5, в который между строками 15 и 25 вставлен программный код на языке JavaScript. Подобный код уже встречался в предыдущей главе, где элемент холста был представлен путем рисования прямоугольника с градиентной заливкой. Пример 6.1 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Using script tags 1</title> <style> #canvas { background-color : cyan; border : 1px solid black; } </style> </head> <body> <canvas id='canvas'></canvas> <script> canvas = document.getElementById('canvas')
Использование холста в HTML5 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. | 83 context = canvas.getContext('2d') canvas.width = 640 canvas.height = 320 context.beginPath() context.strokeStyle = 'green' context.rect(20, 20, 600, 280) context.stroke() </script> </body> </html> Но в этом примере на экран выводится простой прямоугольник без какой-либо заливки, показанный на рис. 6.1, что делает код максимально простым: Рис. 6.1. Рисование незакрашенного прямоугольника в элементе холста Здесь следует обратить внимание на ряд моментов. Во-первых, между строками 6 и 11 имеется раздел <style>, в котором объекту холста canvas придается черная рамка и голубой фон, чтобы он изначально выделялся на белом фоне веб-страницы. Вовторых, в строке 14 холсту присваивается идентификатор canvas, чтобы на него можно было ссылаться как в CSS-стиле, так и в последующем программном коде. А теперь с учетом этих замечаний давайте взглянем на сам код JavaScript. В строке 16 создается так называемый объект JavaScript с именем canvas. Затем следует под-
84 | Глава 6 ключение этого объекта к ранее созданному холсту, для чего используется сложная на вид инструкция JavaScript. Здесь всего лишь выполняется поиск HTML-элемента с идентификатором canvas, а затем создается объект, понятный JavaScript, который также называется canvas. П РИМЕЧАНИЕ Одинаковые имена идентификаторов и объектов выбраны намеренно, чтобы стало понятнее, что именно происходит. Но в реальной обстановке, где может быть сразу несколько холстов и объектов, потребуются разные имена, позволяющие отличать их друг от друга, поэтому у них, вероятнее всего, будут имена вроде canvas1, canvas2 и т. д., или, например, mapcanvas, если изображается карта. Затем, после того как элемент <canvas> помещен в объект JavaScript с именем canvas, в строке 17 на основе этого объекта создается так называемый 2D-контекст. Пока что не стоит ломать голову над происходящим, достаточно лишь знать, что контекст (которому присвоено предельно понятное имя context), похож на ссылку, которая с этого момента и для всех дальнейших инструкций по созданию рисунка на этом холсте будет использоваться для доступа к нему. Фактически везде, где в книге понадобится получить доступ к холсту с идентификатором canvas, можно будет просто скопировать и вставить строки 16 и 17. В строках 18 и 19 задаются ширина и высота холста. Здесь это делается в коде JavaScript, но точно так же это можно было бы сделать и при создании холста, например: <canvas id='canvas' with='640' height='320'></canvas> А вот установить ширину и высоту холста в разделе CSS, как показано ниже, не получится, поскольку этими командами можно только добиться масштабирования холста от любых его исходных размеров. Нужно не забывать устанавливать размеры холста в коде HTML или в коде JavaScript. Width : 640px; // Такие команды CSS не будут height : 320px; // работать согласно задуманному Осталось разобраться с еще четырьмя строками кода. При рисовании линий на холсте обычно необходимо определить начало пути, а затем вести рисунок по этому пути. Итак, в строке 21, за счет вызова функции beginPath() в текущем контексте, говорится: «Давайте начнем рисование пути в этом контексте». После этого для рисования выбирается зеленый цвет, поэтому в строке 22 именно этот цвет назначается атрибуту strokeStyle текущего контекста. Это все равно, что прикрепить ручку с зеленым гелем к рисующей головке плоттера. И теперь мы готовы с помощью кода в строке 23 выполнить рисунок, дав браузеру простую команду по перемещению пера в позицию, отстающую на 20 пикселей от края холста и опущенную на 20 пикселей вниз по холсту, а затем на рисование незакрашенного прямоугольника размером 600 на 280 пикселей, используя уже установленные текущие стили, в данном случае имеется в виду простой зеленый цвет.
Использование холста в HTML5 | 85 Но пока еще прямоугольник не нарисован, поскольку мы прошли только половину пути. Чтобы завершить задание пути и поместить рисунок на холст, требуется последняя команда, показанная в строке 24, где в текущем контексте вызывается функция stroke(), похожая на команду интерпретатору языка JavaScript: «Все инструкции даны, теперь нарисуй путь согласно описанию». Размещение кода в отдельном файле Теперь, посмотрев на код, работающий в веб-документе, и разобравшись в его работе, давайте посмотрим на содержимое примера 6.2 и поймем, как этот код можно будет спрятать в отдельный файл, представляющий собой чистый файл JavaScript, который обычно сохраняется с расширением .js. В данном случае он сохраняется под именем canvas.js. Пример 6.2 1. 2. 3. 4. 5. 6. 7. 8. 9. canvas context canvas.width canvas.height = = = = document.getElementById(‘canvas’) canvas.getContext(‘2d’) 640 320 context.beginPath() context.strokeStyle = ‘green’ context.rect(20, 20, 600, 280) context.stroke() Как видите, в этом файле содержится только сам код JavaScript, и ему не нужен большой отступ от края, поскольку здесь нет окружающего HTML. В коде ничего не изменилось, кроме удаления ненужного пространства отступа и его сохранения в файле под именем canvas.js. А теперь давайте приведем код примера 6.1 к виду, показанному в примере 6.3, и посмотрим, как выглядит извлечение кода из внешнего файла JavaScript. Пример 6.3 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. <!DOCTYPE html> <html lang=”en”> <head> <meta charset=”utf-8” /> <title>Using script tags 2</title> <style> #canvas { background-color : cyan; border : 1px solid black; }
86 11. 12. 13. 14. 15. 16. 17. | Глава 6 </style> </head> <body> <canvas id=’canvas’></canvas> <script src=’canvas.js’></script> </body> </html> Взгляните на строку 15, это теперь все, что осталось от JavaScript в этом HTMLдокументе. Вместо предназначаемого для запуска кода, находящегося внутри тега, весь прежний код был заменен простым присвоением атрибуту src значения, указывающего, откуда следует взять файл JavaScript (в данном случае он берется из только что сохраненного локального файла canvas.js). Посмотрите, насколько лаконичнее стал код HTML, а код JavaScript теперь можно поместить в отдельный файл и работать автономно. И теперь, как показано на рис. 6.2, в таком редакторе, как VS Code, можно открыть сразу несколько вкладок, упрощающих многозадачную разработку, и там же можно заметить, что перед каждым названием цвета имеется небольшой цветной квадратик. Рис. 6.2. Одновременное редактирование в VS Code двух файлов Такие подсказки особенно полезны, когда вместо названий используют номера цветов. Попробуйте навести на них указатель мыши, и увидите появление всплывающего окна выбора цвета (показанного на рис. 6.3), из которого можно изменить цвет одним щелчком мыши, что очень удобно. Конечно, программирование на JavaScript намного серьезнее показанного здесь. И все же теперь у вас неплохие стартовые позиции, а новые функции, используемые в этой книге, будут объясняться по мере надобности.
Использование холста в HTML5 | 87 Рис. 6.3. Предлагаемое VS Code всплывающее окно выбора цвета П РИМЕЧАНИЕ По вопросу применения точки с запятой в JavaScript. Во многих языках программирования, таких как PHP, C или даже в старом добром CSS, точку с запятой нужно ставить в конце каждой законченной строки. То же самое можно делать и в JavaScript, и код с таким оформлением будет попадаться довольно часто. Но в JavaScript эти точки с запятой необязательны, и если это так, то зачем их вообще использовать? (По той же логике в этой книге для определенных самозакрывающихся тегов не рекомендуется использовать слэш). И все же следует признать наличие ряда крайних случаев, когда без точки с запятой не обойтись, но о них известно, наверное, только самым квалифицированным программистам. При желании можете воспользоваться точкой с запятой для разделения нескольких операторов JavaScript в одной строке. Но новичкам этого делать не рекомендуется. Функция getElementByID() Нам уже встречалось использование функции getElementByID()для получения идентификатора элемента: canvas = document.getElementById(‘canvas’) И здесь важно напомнить, что это весьма распространенная инструкция, используемая везде, где нужно разрешить доступ к элементу из кода JavaScript. Она часто будет встречаться в стороннем коде, и некоторые разработчики используют ее настолько часто, что создают новую функцию (или используют такую библиотеку, как jQuery), чтобы уменьшить объем ввода (всякий раз экономя 22 символа): canvas = $(‘canvas’)
88 | Глава 6 То есть, если вам когда-либо попадался код, в котором символ $ используется таким вот образом, то в нем почти наверняка объекту JavaScript передавался идентификатор элемента. Но какое бы имя ни использовалось для этой функции, в результате ее применения объект сможет получить доступ к этому HTML-элементу и всем его свойствам CSS, и все это из кода JavaScript. Получается так, что стиль можно задавать не только с помощью CSS, но и с помощью JavaScript. П РИМЕЧАНИЕ В случае вопроса, может ли использование JavaScript для оформления стилей нарушить принцип разделения контента и стилей, нужно отвечать утвердительно. Применять настройки стиля нужно по возможности только с помощью CSS. Но в тех случаях, когда нужны функции, не поддающиеся изменению с помощью CSS, таких как видео, аудио или, как в этой главе, холст, нужно знать, как это можно сделать и в JavaScript. В книге и далее будут встречаться примеры передачи идентификаторов элементов в код JavaScript, но теперь вы уже сможете понять, что при этом происходит. Превращение холста в изображение Один из недостатков (а быть может, из преимуществ) элемента <canvas> — то, что это не изображение, которое можно перетаскивать или сохранять. Но разработчику может понадобиться воспользоваться холстом для создания графики, которой хочется поделиться, не включая весь связанный код JavaScript (которым, возможно, не захочется с кем-то делиться). К счастью, имеется относительно простой способ конвертировать холсты в стандартные веб-изображения с помощью так называемого URL-адреса данных. Это строка с URL-адресом, не указывающим на ссылку на вашем сервере или где-либо в Интернете. Вместо этого в ней содержатся все данные для создания изображения прямо в URL-адресе. Для этого сначала нужно создать пустой элемент изображения в своем коде HTML, а затем из JavaScript скопировать данные холста в атрибут src этого изображения, присвоив ему URL-адрес данных. Тогда изображение появится на экране, и его можно будет как угодно перетаскивать или сохранять! Взгляните на пример 6.4. В нем представлен документ, включающий код JavaScript, чтобы содержать в одном месте весь код, с помощью которого создается рисунок на холсте. Он сохраняется в изначально пустом изображении, созданном в строке 15. Результат показан на рис. 6.4. Если попытаться перетащить и холст, и изображение на рабочий стол, обнаружится, что холст не среагирует, а изображение легко позволит это сделать. Давайте попробуем.
Использование холста в HTML5 Рис. 6.4. Изображение справа было создано из холста слева Пример 6.4 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. <!DOCTYPE html> <html lang=”en”> <head> <meta charset=”utf-8” /> <title>Converting to an Image</title> <style> #canvas { background-color : yellow; border : 1px solid red; } </style> </head> <body> <canvas id=’canvas’ width=’320’ height=’320’></canvas> <img id=’image’> <script> canvas = document.getElementById(‘canvas’) context = canvas.getContext(‘2d’) context.beginPath() context.arc(160, 160, 150, 0, 2 * Math.PI) context.fillStyle = ‘green’ context.strokeStyle = ‘blue’ | 89
90 24. 25. 26. 27. 28. 29. | Глава 6 context.fill() context.stroke() document.getElementById(‘image’).src = canvas.toDataURL() </script> </body> </html> Чтобы все слегка запутать, в примере рисуется зеленый круг с синей рамкой. Как это делается (если вы еще не догадались), рассказано в следующей главе, а затем в строке 26 происходит настоящее волшебство: атрибуту источника изображения src предоставляется URL-адрес данных холста, и изображение сразу же отображается рядом с ним. Но заметьте, что желтый фон и красная рамка холста во вновь созданном изображении отсутствуют, потому что они являются атрибутами CSS холста и не составляют часть холста как такового. Если бы нам захотелось, чтобы они были на новом изображении, их нужно было бы нарисовать на холсте, а не применять в качестве стилей CSS. Если перетащить изображение на Рабочий стол, то оно, скорее всего, будет сохранено с использованием имени файла, например, download.png. И с этого момента с изображением можно будет делать все что угодно, поскольку это уже будет стандартный файл .png. П РИМЕЧАНИЕ В некоторых современных браузерах можно щелкнуть правой кнопкой мыши на холсте, а затем выбрать его сохранение в виде изображения, но это только с позиции пользователя. Разработчику все же придется иногда создавать изображения «на лету» на холсте вне экрана, а затем загружать их как реальные изображения в нужные места своих веб-документов, добиваясь этого путем превращения холста в изображение. Заключение Закончив чтение главы, вы расширили свои познания о холсте HTML5, узнали, как его настроить, как его оформить в CSS и JavaScript, как рисовать на холсте с помощью простых инструкций JavaScript, а также как превратить холст в обычное изображение. В следующей главе нас ждет углубленное изучение более сложных функций рисования.
ГЛАВА 7 Прямоугольники и заливки Введение В этой книге HTML5-тегу <canvas> посвящено немало страниц, и это правильно, поскольку элемент холста считается одним из наиболее эффективных и значительных. Теперь, после достаточно неплохого ознакомления с холстом HTML5, а также с использованием JavaScript для рисования на нем, настала пора приступать к более подробному изучению различных инструментов рисования, предлагаемых разработчикам. В ходе изучения главы придется сталкиваться с целым рядом функций JavaScript, без которых просто невозможно работать с холстом, и к этому обстоятельству нужно относиться позитивно, поскольку изучение основ JavaScript можно при освоении материалов книги считать своеобразным бонусом. Даже при отсутствии явных способностей к рисованию всем этим функциям все равно можно будет найти множество вариантов применения: от построения диаграмм и графиков и до создания собственных значков и иллюстраций. Поскольку все рисование происходит под управлением инструкций, станет понятно, что для большинства простых проектов добиться той точности, которая при этом получается, куда легче, чем в процессе рисования с помощью мыши или пера в графическом редакторе. Структура В этой главе рассматриваются следующие темы:  Способы рисования прямоугольников на холсте HTML5.  Приемы заполнения прямоугольников заливками, градиентами и узорами.  Сведения о загрузках изображений и об управлении ими в JavaScript.  Способы сохранения, перемещения и восстановления контекста холста. Цели После освоения предлагаемого материала ваш арсенал инструментов веб-разработчика расширится за счет полного набора приемов рисования прямоугольников.
92 | Глава 7 Кроме того, попутно вы освоите ряд базовых, но весьма удобных методов JavaScript, применимых к другим функциям холста и HTML, а также к рисованию прямоугольников. О примерах работы с холстом Чтобы избежать ненужных сложностей, далее в этом разделе книги примеры использования элемента холста даются только с кодом JavaScript без окружения из кода HTML. Нужно будет исходить из предположения, что в документе уже создан элемент <canvas> с идентификатором canvas (как правило, шириной 640 и высотой 320 пикселей), а также, что в сценарий уже включены две первые строки на JavaScript, создающие контекст для записи на холст (строки 16 и 17 примера 7.1). В примере 7.1 показан полноценный HTML-документ, который, как будет предполагаться далее, присутствует во всех примерах работы с холстом. Он уже должен быть знаком по коду незаполненного зеленого прямоугольника из главы 6 «Использование холста HTML5». А далее будет показываться только код, размещенный внутри двух комментариев (строки 19 и 24) (и по ходу чтения главы там будут появляться многочисленные дополнительные строки). А архиве файлов примеров, прилагаемом к книге, будет присутствовать весь окружающий HTML-код, позволяющий запускать пример сразу на выполнение без ввода недостающих строк. Пример 7.1 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Example Document</title> <style> #canvas { background-color : cyan; border : 1px solid black; } </style> </head> <body> <canvas id='canvas' width='640' height='320'></canvas> <script> canvas = document.getElementById('canvas') context = canvas.getContext('2d') // Примеры буду начинаться здесь context.beginPath() context.strokeStyle = 'green' context.rect(20, 20, 600, 280)
Прямоугольники и заливки 23. 24. 25. 26. 27. | 93 context.stroke() // А здесь они будут заканчиваться </script> </body> </html> В этом примере показан также способ комментирования кода в JavaScript. Комментарии — это простой текст, вводимый в код для напоминаний разработчику (и его коллегам, обновляющим код) о сути исходного замысла. Включение в код комментариев считается полезной практикой, поскольку они освежают память и помогают при дальнейшей отладке или при просмотре кода по прошествии длительного периода времени, когда из памяти уже стерлись некоторые детали. Комментарий создается путем вставки в любом месте программы двойного слэша, показывающего, что весь последующий текст игнорируется, не считаясь инструкцией JavaScript. В показанном далее программном коде присутствуют только те части каждого примера, которые демонстрируются в этой книге (если только окружающий подобный код документ не будет в том или ином примере иметь какие-либо отличия). Поэтому следует исходить из предположения, что для каждого примера вся остальная часть документа уже имеется, и можно просто сосредоточить внимание только на таких вот рассматриваемых в данный момент инструкциях. context.beginPath() context.strokeStyle = 'green' context.rect(20, 20, 600, 280) context.stroke() Эти инструкции и описание порядка их работы уже встречались в предыдущей главе, здесь же предполагается, что холст соответствующего размера уже создан и должным образом стилизован, а также что создан контекст из идентификатора холста со значением canvas. После всех этих объяснений давайте перейдем к другим примерам рисования. Рисование прямоугольников Прямоугольники — одна из самых простых фигур для рисования на холсте HTML5. Их можно рисовать с заполнением или контурно, используя различные стили, настраиваемые отдельно в текущем контексте, или же, если никакие стили не установлены, с использованием исходных значений. Первый уже встречавшейся ранее тип представляет собой незаполненный прямоугольник с простым стилем, который можно создать с помощью следующей инструкции: context.strokeRect(20, 30, 50, 70) При ее выполнении будет нарисован прямоугольник с верхним левым углом, начинающимся на 20 пикселей вовнутрь холста и на 30 пикселей вниз, с шириной 50
94 | Глава 7 пикселей и глубиной 70 пикселей. При рисовании прямоугольников нужно запомнить, что передаваемые аргументы должны указываться в следующем порядке: отступ слева, отступ сверху, желаемая ширина и высота. Функция может вызываться и в том виде, что представлен в следующей строке кода. Но что это означает? context.strokeRect(r_left, r_top, r_width, r_height) Использование переменных Дело в том, что в JavaScript, как и во всех языках программирования, есть так называемые переменные. Это именованные контейнеры, содержащие значения, в качестве которых могут быть цифры, числа, строки текста и т. д. В этом случае нам просто нужны обычные числа, и если бы предыдущую строку кода включить в работу, то сначала следовало бы присвоить переменным значения: r_left r_top r_width r_height = = = = 10 20 400 200 Префикс r_ означает «rectangle», т. е. «прямоугольник», и обеспечивает уникальность имен переменных, поскольку некоторые слова, вроде top, left и т. д. могут входить в перечень зарезервированных слов языка JavaScript, используемых в целях, не входящих в круг обсуждаемых в книге вопросов. Так или иначе, строки, помещенные перед инструкцией рисования прямоугольника, приведут к появлению на холсте прямоугольника размером 400 на 200 пикселей, с верхним левым углом, отстоящим на 10 пикселей внутрь и на 20 пикселей вниз. Но не следует забывать, что сначала нужно объявить начало нового пути. Давайте объединим все означенные строки в некий работающий код, показанный в примере 7.2 (памятуя о том, что весь окружающий HTML и некоторые другие части в этом примере опущены). Результат запуска кода можно увидеть на рис. 7.1. Пример 7.2 r_left r_top r_width r_height = = = = 10 20 400 200 context.beginPath() context.strokeRect(r_left, r_top, r_width, r_height) context.stroke() Если ранее еще никогда не приходилось программировать, посмотрите, как в ходе обучения рисованию прямоугольника удалось немного приоткрыть для вас завесу тайн программирования на JavaScript. А представьте себе, каких невероятных успехов в этом деле предстоит добиться к концу чтения книги!
Прямоугольники и заливки | 95 Рис. 7.1. Использование переменных для рисования прямоугольника без заливки Применение стилей рисования Теперь вы умеете рисовать прямоугольники. Давайте посмотрим, как можно сделать их интереснее, изменив способ рисования, и начнем с их заполнения. В главе 5 «Введение в HTML5», если помните, говорилось, что не нужно довольствоваться рисованием только пустых прямоугольников. Гораздо чаще понадобится их чем-то заполнять, и при этом можно воспользоваться множеством различных эффектов, начиная с простой заливки (как это делается в примере 7.3), где, как показано на рис. 7.2, рисуется желтый прямоугольник с синей рамкой. Пример 7.3 context.strokeStyle = 'blue' context.fillStyle = 'yellow' context.beginPath() context.fillRect( 20, 20, 600, 280) context.strokeRect(20, 20, 600, 280) context.stroke() Теперь уже нетрудно разобраться во всем здесь происходящем. Сначала синим цветом задается внешняя граница прямоугольника и желтая внутренняя заливка, затем объявляется начало нового пути, заполняется прямоугольник, рисуется путь и, наконец, путь закрывается.
96 | Глава 7 Рис. 7.2. Прямоугольник с желтой заливкой и синей рамкой Изменение толщины линии Теперь на рис. 7.3 можно увидеть результат изменения нового свойства контекста под названием linewidth после добавления еще одной инструкции, показанной в примере 7.4, который содержит дополнительную инструкцию к коду примера 7.3, добавляемую в начало инструкций рисования (напомню, что в прилагаемом архиве файлов примеры приводятся в полном объеме). Пример 7.4 context.lineWidth = 20 Посмотрите, с какой легкостью выбирается толщина рисуемых линий. Также обратите внимание, что толщина добавляется по обе стороны рисуемой линии, поэтому она расширяется как во внешнюю, так и во внутреннюю сторону. Вопреки ожиданиям, что прирост будет либо в одну, либо в другую сторону, при создании своих фигур следует помнить, что он равномерно идет в обе стороны, т. е. в результате изменения толщины линии новый прямоугольник (включая его контур) теперь занимает больше места, чем прямоугольник с указанным размером 600 × 280 пикселей. И это только лишь начальные сведения о том, что можно будет делать с линиями. Гораздо больше об изменении линий, которыми создается рисунок на холсте, можно будет узнать в главе 9 «Рисование на холсте». Посмотрим, что еще можно сде-
Прямоугольники и заливки | 97 лать с прямоугольниками, включая их очистку и усложнение заливки с помощью градиентов. Рис. 7.3. Увеличение толщины контурной линии Очистка прямоугольника Прямоугольники можно не только рисовать, но и выбирать в качестве области очистки холста до его исходных стилевых значений, то есть удалять все значения красных, зеленых и синих пикселей, а также их альфа-значений. Используемый в графите термин «альфа-значение», относится к степени прозрачности пикселя, который может быть полностью непрозрачным, полностью прозрачным или прозрачным в той или иной мере. При очистке прямоугольника альфа-значения в нем будут возвращены к нулю, что означает отсутствие прозрачности, и все цвета также будут установлены в ноль. Возьмем пример 7.4 и очистим часть холста внутри рисуемого в нем прямоугольника, добавив еще одну команду, создавая при этом код примера 7.5. Результат показан на рис. 7.4, где можно увидеть, что прямоугольник в середине только что нарисованного прямоугольника теперь восстановлен до исходных значений холста, и поэтому в нем отображается голубой — цвет по умолчанию, примененный в разделе стиля документа (чтобы отличать его от окружающего документа с белым фоном). Пример 7.5 context.clearRect(70, 70, 500, 180)
98 | Глава 7 Теперь, освоив приемы установки атрибутов strokeStyle, fillStyle, lineWidth, fillдавайте развлечемся применением градиентной заливки. Rect, strokeRect и clearRect, Рис. 7.4. Прямоугольная часть холста очищена Применение градиентной заливки Простой градиентный эффект уже встречался в главе 5 «Введение в HTML5». Теперь посмотрим, как его можно добиться с применением функции fillRect() для прямоугольников (или обычной функции fill(), рассматриваемой в главе 9 «Рисование на холсте») в сочетании с функцией createLinearGradient(). В качестве аргументов эта функция принимает две пары координат X, Y, определяющие начало и конец градиента на холсте. Способ рисования градиента на холсте заключается в указании группы цветов и позиций в градиенте, где они должны появляться. Это позволяет получать очень точный контроль над градиентами, при котором они не просто представляют собой переход от одного цвета к другому, но могут (при соответствующем выборе) быть проходом через множество цветов одновременно. Самый простой тип градиента имеет один начальный и один конечный цвет. А теперь давайте нарисуем четыре разных черно-белых градиента, используя пример 7.6, где первые три градиента линейные, а последний градиент радиальный. Но сначала следует заметить, что для упрощения редактирования назначаемых цветовых настроек в строках 1 и 2 используются переменные (концепция которых была рассмотрена ранее в этой главе) с именами color1 и color2.
Прямоугольники и заливки | 99 Пример 7.6 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. color1 = '#FFF' color2 = '#000' gradient = context.createLinearGradient(55, 10, 55, 160) gradient.addColorStop(0, color1) gradient.addColorStop(1, color2) context.fillStyle = gradient context.fillRect(10, 10, 90, 150) gradient = context.createLinearGradient(110, 85, 200, 85) gradient.addColorStop(0, color1) gradient.addColorStop(1, color2) context.fillStyle = gradient context.fillRect(110, 10, 90, 150) gradient = context.createLinearGradient(210, 10, 300, 160) gradient.addColorStop(0, color1) gradient.addColorStop(1, color2) context.fillStyle = gradient context.fillRect(210, 10, 90, 150) gradient = context.createRadialGradient(355, 85, 0, 355, 85, 100) gradient.addColorStop(0, color1) gradient.addColorStop(1, color2) context.fillStyle = gradient context.fillRect(310, 10, 90, 150) Для первой градиентной заливки в строке 4 в качестве начального положения градиента указываются параметры 55,10, а в качестве конечного — 55,160. Дело в том, что указывать параметры градиентов нужно на основе абсолютных координат холста, а не положения относительно взятых любых фигур, назначаемых к заполнению. Следовательно, если первая градиентная заливка (показанная в строке 8) имеет ширину 90 и высоту 150 пикселей, а ее верхний левый угол начинается в позиции 10,10, то точка 55,10 находится на полпути протяженности верхнего края области заполнения, а 55,160 — на полпути к нижнему краю. Получается, градиент будет начинаться в верхней части заполняемой области (прямо в центре, но распространяться по горизонтали), а затем будет стекать сверху вниз, к центру нижнего края. В строках 5 и 6 задается начальное местоположение, где начинается белый цвет (заданный переменной с именем color1, для которой в строке 1 установлено значение '#FFF', а для нижней точки задается черный цвет (заданный переменной color2, для которой в строке 2 установлено значение '#000'), благодаря чему обеспечивается равномерность градиента между этими двумя цветами. В строке 7 только что заданные характеристики градиента применяются к свойству контекста fillStyle.
100 | Глава 7 Затем в строке 8 для рисования заливки вызывается функция fillRect().В результате появляется левый прямоугольник, показанный на рис. 7.5, где, чтобы не загромождать (и не усложнять) код, показано, что нарисованы только заливки без обводки прямоугольников, присутствующей в некоторых предыдущих примерах. Рис. 7.5. Подборка из четырех различных градиентных заливок И теперь уже вы должны понять, что происходит в следующих двух областях заливки, где во второй области градиент, согласно значениям, заданным в строке 10 (от точки с координатами 110,85 до точки 200,85), идет слева направо с середины левой стороны до середины правой стороны прямоугольника. А градиент третьего прямоугольника (от точки с координатами 210,10 до точки 300,160) идет по диагонали от его верхнего левого вниз к его правому нижнему углу. Применение радиального градиента Четвертая заливка немного отличается от предыдущих, поскольку в ней показан радиальный градиент, идущий от центра к внешней стороне прямоугольника. Что здесь происходит, станет ясно, стоит лишь разобраться, что первые три аргумента — это координата X, Y и радиус начального цвета, а последние три аргумента — это конечная точка X, Y и радиус, в данном случае, из точки 355,85 с радиусом 0, в ту же точку (355,85), но с радиусом 100 пикселей. Для второго круга было выбрано значение радиуса 100, потому что его диаметр находится за пределами большей части прямоугольной области. В противном случае, если бы он, к примеру, был ограничен только шириной прямоугольника (возможно,
Прямоугольники и заливки | 101 с использованием значения 45 для радиуса, поскольку ширина прямоугольника составляет 90 пикселей), то верхняя и нижняя части прямоугольника были бы полностью черными, а заливка отображалась бы только в его центре. Но при 100 пикселях градиент виден до самых углов прямоугольника. Подытожим: начальное положение представляет собой точку нулевого размера, а не круг (из-за нулевого радиуса), а центр конечного круга находится в том же месте, что и начальный круг, но имеет больший радиус. Предоставление параметров двух окружностей (а не одной центральной точки X, Y и двух радиусов), обуславливается обеспечением гибкости проектов, позволяющей создавать не просто круглые радиальные заливки, но и такие, что, согласно задуманному, смогут распространяться по всей заливаемой области. Так создаются монохромные заливки. А теперь перейдем к разноцветным заливкам. Разноцветные градиентные заливки На данный момент изменение цвета проще всего показать путем замены черного и белого цвета из примера 7.6 на разные цвета. Если так и сделать, изменив следующим образом содержимое строк 1 и 2, то на рис. 7.5 отобразились бы различные оттенки желтого, оранжевого и, наконец, красного цвета. Не хотите сами в качестве простого упражнения попробовать это сделать, используя различные пары цветов? 1. 2. color1 = 'yellow' color2 = 'red' Но зачем останавливаться на достигнутом, когда можно создавать эффекты разноцветной радуги? Давайте так и сделаем с кодом примера 7.6, добавив в набор еще три цвета (и вставив ссылки на эти цвета в каждую из четырех заливок прямоугольника), чтобы получился код, показанный в примере 7.7, где показано, что порядок выбранных цветов для прямоугольников 2–4 перестроен, просто чтобы все немного перемешать. Пример 7.7 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. color1 color2 color3 color4 color5 = = = = = 'yellow' 'green' 'red' 'violet' 'blue' gradient = context.createLinearGradient(55, 10, 55, 160) gradient.addColorStop(0.0, color1) gradient.addColorStop(0.2, color2) gradient.addColorStop(0.5, color3) gradient.addColorStop(0.8, color4) gradient.addColorStop(1.0, color5)
102 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. | Глава 7 context.fillStyle = gradient context.fillRect(10, 10, 90, 150) gradient = context.createLinearGradient(110, 85, 200, 85) gradient.addColorStop(0.0, color1) gradient.addColorStop(0.2, color3) gradient.addColorStop(0.5, color5) gradient.addColorStop(0.8, color2) gradient.addColorStop(1.0, color4) context.fillStyle = gradient context.fillRect(110, 10, 90, 150) gradient = context.createLinearGradient(210, 10, 300, 160) gradient.addColorStop(0.0, color3) gradient.addColorStop(0.2, color4) gradient.addColorStop(0.5, color1) gradient.addColorStop(0.8, color5) gradient.addColorStop(1.0, color2) context.fillStyle = gradient context.fillRect(210, 10, 90, 150) gradient = context.createRadialGradient(355, 85, 0, 355, 85, 100) gradient.addColorStop(0.0, color4) gradient.addColorStop(0.2, color2) gradient.addColorStop(0.5, color1) gradient.addColorStop(0.8, color5) gradient.addColorStop(1.0, color3) context.fillStyle = gradient context.fillRect(310, 10, 90, 150) Результат загрузки кода примера 7.7 в браузер можно увидеть на рис. 7.6, где будет заметно существенное отличие от предыдущих монохромных заливок. Несложно заметить, что дополнительные цвета добавляются в виде дополнительных вызовов функции addColorStop() со значениями первого параметра в диапазоне от 0 до 1. Например, когда для градиента задавалось всего два цвета, этот параметр был либо 0 для первого цвета, либо 1 для второго, но в строках с 8 по 12 примера 7.7 можно увидеть, что пять цветов были добавлены с использованием для этого параметра аргументов с плавающей точкой со значениями между 0.0 и 1.0. Все это работает следующим образом: нужно представить, что вся градиентная заливка занимает пространство, заданное значением с плавающей точкой между 0.0 и 1.0. Если требуется, чтобы определенный цвет появлялся в градиенте на протяжении 25% пространства, тогда его параметр начального расстояния addColorStop() нужно установить равным 0.25, аналогичным образом для цвета, который должен отображаться на одну треть градиентной заливки, следует воспользоваться значением 0.33.
Прямоугольники и заливки | 103 Рис. 7.6. Четыре разных заливки разноцветным градиентом В примере видно, что для цветового решения вдоль градиента выбраны значения 0%, 20%, 50%, 80% и 100%, поскольку аргументы расстояний, предоставленные для пяти цветов, равны 0.0, 0.2, 0.5, 0.8 и 1.0. Позиционирование может быть любой желаемой точности, например, если нужно, для начала цвета можно выбрать расстояние 0.3145927. И вот еще что: поскольку цветовые значения определены в первых пяти строках примера, чтобы посмотреть, каких других эффектов можно достичь, рекомендуется применить другие названия того или иного цвета (или воспользоваться строковыми значениями с использованием символа # в стиле CSS) и изменить порядок, используемый в четырех прямоугольниках, а также расстояния, с которых каждый цвет появляется вдоль каждого градиента. По сути, к градиенту можно добавлять сколько угодно цветовых значений, и от экспериментов с кодом примера можно получить массу удовольствий. Разобравшись с этим примером и с градиентами, давайте посмотрим на заполнение областей узорами. Использование заполнения узором Конечно, одной лишь простой или градиентной заливкой возможности не ограничиваются, поскольку можно также выбрать заполнение областей холста заранее выбранным узором с использованием различных способов заполнения. Сделать это можно с помощью функции createPattern(), передав ей два аргумента: используемое изображение и тип повторения, применяемый для заполнения.
104 | Глава 7 В примере 7.8 показан код предыдущего примера с несколькими дополнительными строкам, предназначенными для заполнения пятого прямоугольника большего размера. Но будьте готовы к тому, что разобраться с кодом JavaScript удастся не с первого раза. Пример 7.8 43. 44. 45. 46. 47. 48. 49. 50. 51. image = new Image() image.src = 'tile.png' image.onload = function() { pattern = context.createPattern(image, 'repeat') context.fillStyle = pattern context.fillRect(410, 10, 220, 300) } По нумерации строк понятно, что они являются продолжением кода примера 7.6. Давайте разберемся в их назначении. Сначала в строке 43 из пустого несуществующего изображения создается новый объект JavaScript. Объект подобен переменной, но он может содержать более широкий набор типов данных (в данном случае это изображение). Как только объект создан, атрибуту источника src (аналогичному src из HTML) присваивается имя файла tile.png, и JavaScript получает указание на начало извлечения изображения и размещения его в объекте изображения. Пока что объект изображения в JavaScript очень похож на элемент изображения в HTML или CSS. Но порой в результате этой операции создается проблема, поскольку JavaScript, будучи в основном чистым текстом, зачастую загружается гораздо быстрее, чем другие, более крупные элементы страницы, например изображения. И при попытке использования такого элемента до его загрузки ничего не происходит, и код со своей задачей не справляется. Поэтому требуется дополнительный фрагмент JavaScript, позволяющий выполнять инструкции только после загрузки объекта. Это делается путем присоединения так называемой безымянной функции (функции, которой не было присвоено имя) к событию onload объекта изображения. В JavaScript существует множество различных событий, на которые можно реагировать, например, нажатие клавиши или перемещение мыши. В этом случае нужно лишь узнать о моменте загрузки изображения в память, поэтому в строке 46 безымянная функция присоединяется к событию onload вместе с соответствующими открывающей { и закрывающей } фигурными скобками. Они сообщают JavaScript о местонахождении тех инструкций, которые будут выполняться после загрузки изображения. А выполняться в тот момент будут только те инструкции, которые заключены в фигурные скобки. Внутри них находятся всего три строки кода. В строке 48 путем вызова функции createPattern() в контексте создается объект pattern, которому присваивается имя
Прямоугольники и заливки | 105 используемого изображения и требуемый тип повтора. В данном случае это то самое изображение, которое только что было загружено в объект image, а значение repeat для параметра повторения устанавливает выкладывание узоров в направлениях X и Y (вдоль и вниз). Загружаемое изображение можно увидеть на рис. 7.7, а результат добавления всего этого кода в пример показан на рис. 7.8. Рис. 7.7. Изображение, хранящееся в файле tile.png Рис. 7.8. Добавление на холст заполнения узором
106 | Глава 7 Использование перемещения В строке 48 примера 7.8 в качестве типа повторения указано просто значение repeat, что означает повторение в обоих направлениях: X и Y. Для получения того же результата по умолчанию тип повторения также может быть опущен. Но можно также выбрать повторение только в горизонтальном направлении X или вертикальном направлении Y. И все же при использовании любого из них можно столкнуться с неожиданностью, поскольку заполнение узором начинается точно с координаты 0,0 в верхнем левом углу холста. И хотя заполнение можно будет увидеть только в пределах области, заданной инструкцией заполнения, узор все еще будет невидимо отрисовываться и после нее. Когда заполнение узором отрисовывается в определенной области, это сродни открытию окна мозаичного узора для части полного холста. Итак, если сначала обратить внимание на ось Y, можно понять, что, выкладывая узоры на холсте от левого верхнего угла, можно указать заполнение по этому краю в любом месте холста, и станет видна часть мозаики, нарисованная кодом примера 7.9, являющегося продолжением кода примера 7.8, помещенным после первых трех строк кода в безымянной функции, что рисовала правый прямоугольник, показанный на рис. 7.8. Пример 7.9 53. 54. 55. pattern = context.createPattern(image, ‘repeat-y’) context.fillStyle = pattern context.fillRect(10, 170, 190, 140) Единственное отличие этих строк кода — то, что в строке 53 устанавливается значение повторения repeat-y, а в строке 55 в левом нижнем углу холста рисуется прямоугольник, показанный на рис. 7.9. И все же это неидеальное решение, если нужно, чтобы левый край первой плитки в каждом ряду не обрезался. Кроме того, интересно, что же произойдет, если захочется воспользоваться значением повторения repeat-x, не заполняя узором направление Y? В принципе, все получится, но только для заполнений, сделанных в верхней части экрана, и все равно можно будет не увидеть весь узор, если область для заполнения смещена сверху вниз на произвольную величину. Чтобы избавиться от этих проблем и применить заполнение, начиная с верхнего левого угла области, можно выполнить действие, называемое перемещением холста, которое вызывает временное перемещение исходной точки или начальной точки рисования в верхнем левом углу в то исходное положение, которое вам требуется. Затем рисуется узорчатый фон, после чего холст перемещается обратно в его надлежащее положение с началом в его же верхнем левом углу.
Прямоугольники и заливки | 107 Не пугайтесь, все это, исходя из кода примера 7.10, намного проще, чем может показаться: Пример 7.10 57. 58. 59. 60. 61. 62. context.save() context.translate(210, 170) pattern = context.createPattern(image, ‘repeat-x’) context.fillStyle = pattern context.fillRect(0, 0, 190, 140) context.restore() Рис. 7.9. Вертикальное заполнение узором, примененное к левой нижней части холста Перемещение контекста из его исходного местоположения может создать путаницу, если позже забыть о сделанном, поэтому в JavaScript для сохранения всех деталей контекста в безопасной части памяти доступна функция сохранения save() с соответствующей ей функцией восстановления restore(), возвращающей предыдущие настройки. В строках 57 и 62 задано сохранение, а затем восстановление состояния контекста, позволяющее делать между ними все, что угодно. В строке 58 верхний левый угол холста перемещается в позицию, где нужно разместить верхний левый угол области заполнения — 210,70. Иными словами, холст остается там же, где и был, но все последующие команды будут перемещены для применения в местах со смещением от нового местоположения на величину перемещения. Это перемещение координат теперь будет применяться до тех пор, пока код не закончится, и не произойдет другое перемещение или же не будет восстановлено предыдущее состояние контекста.
108 | Глава 7 В строках 59 и 60 создается узор с использованием значения повторения repeat-x. Затем, в строке 61 для угла заполнения просто указывается значение 0,0, поскольку верхний левый угол области заполнения уже перемещен, а также указывается ширина и высота 190 x 140 пикселей. Поскольку холст временно переведен в позицию 210,170, то координата 0,0 верхнего левого угла области заполнения фактически находится в изначально желаемой позиции 210, 170. И наконец, при выполнении вызова функции restore() в строке 61 все возвращается в нормальное состояние, и в результате, показанном на рис. 7.10, угол первого узора соответствует верхнему левому углу области заполнения. Рис. 7.10. Горизонтальное заполнение, нарисованное в перемещенном месте Для сравнения, при заполнении узором по обеим осям и заполнении по вертикальной оси в двух предыдущих примерах отсутствуют части у одного или обоих левого и самого верхнего узора. Возможно, у вас появится желание самостоятельно воспользоваться техникой перемещения в качестве упражнения по исправлению этих примеров заполнения узором, чтобы приспособить заполнение под начало узора, как в самом последнем примере. Да, кстати, для заполнений узорами есть также вариант без повторов, когда изображение не складывается в мозаику. Больше всего это подходит для создания сплошного фона, полностью заполняющего область без нежелательного появления мозаики. Можно, конечно, возразить, что в таких случаях зачастую можно было бы в соответствии с приемами, рассматриваемыми в главе 10 «Управление холстом», обойтись отрисовкой узора обычным способом, не беспокоясь о переносах.
Прямоугольники и заливки | 109 Заключение В этой главе охвачено немало вопросов: от заполненных и незаполненных прямоугольников, толщины обводки контура, монохромных и многоцветных градиентов (как линейных, так и радиальных) и до различных типов заполнения узором. Попутно также были получены дополнительные сведения о JavaScript, в том числе о том, как загружать изображения непосредственно из кода без использования HTML, и даже о том, как можно дождаться загрузки изображения, прежде чем получить к нему доступ. Более того, теперь известно, как перемещать контекст холста в разные места для достижения желаемых эффектов, а также, как сохранять и восстанавливать состояние контекста. Это действительно солидный багаж новых знаний. Но, надеюсь, эта глава помогла все усвоить, поскольку в ней были достаточно подробно изложены новые знания об управлении холстом HTML5. В следующей главе предстоит изучить различные методы, которыми можно воспользоваться для создания надписей на холсте.
ГЛАВА 8 Надписи на холсте Введение В этой главе рассматриваются различные способы записи текста на холсте HTML5 с использованием разных стилей, цветовых решений, семейств шрифтов и многого другого. Также показываются способы применения к надписям различных заливок, градиентов и узоров, рассмотренных в предыдущей главе. Разумеется, текстовая часть в языке гипертекстовой разметки (HTML) имеется, поскольку он изначально предназначался для создания текстовых веб-страниц и обладал способами включения различных шрифтов, средств выразительности, цветовых решений и стилей. А CSS существенно расширяет оформительские возможности. Используя средства HTML и CSS, текст можно накладывать на холст, но записать его в пиксели изображения холста не получится. Также невозможно получить все предлагаемые холстом интересные эффекты градиента и заливки. Следовательно, имеются весьма веские основания для создания текстовых эффектов с использованием холста, и здесь будет показано все, что нужно для создания целого ряда впечатляющих приемов работы с надписями. Структура В этой главе рассматриваются следующие темы:  Применение различных способов написания текста на холсте HTML5.  Приемы выравнивания текста и применение базовых линий.  Приемы обводки или заполнения текста разными способами.  Порядок использования любых шрифтов и применения узоров в качестве залив- ки текста. Цели Изучив предлагаемый материал, вы сможете делать на холсте HTML5 любые текстовые надписи, используя для этого широкий диапазон шрифтов, цветовых реше-
112 | Глава 8 ний и стилей, включая линейные и радиальные цветные и монохромные градиенты, одноцветные заливки или обводки, а также узнаете, как загружать изображения, чтобы использовать их в качестве заливки текста узором. Создание надписей Один из способов создания шрифтовых надписей на холсте заключается в использовании функции strokeText(). Она принимает три аргумента: текст надписи и координаты X, Y ее нижнего левого угла. Для этого можно воспользоваться следующей инструкцией: context.strokeText('To be, or not to be...', 50, 50) Но с исходными установками, без внесения изменений в какие-либо другие атрибуты контекста, результат, наверное, не сильно впечатлит, и надпись может быть сделана не тем шрифтом, который вы бы выбрали, поэтому, прежде чем продолжить, нужно посмотреть, как можно наряду с другими атрибутами получить текст с нужным размером и шрифтом, в желаемом цветовом решении и с выбранной шириной линии. Изменение способа отображения текста Наверное, первое, что захочется изменить, задавшись целью отобразить на холсте некий текст, будет шрифт, и этого можно легко добиться путем присвоения соответствующих значений свойству контекста под названием font. Более того, можно тут же выбрать нужный размер шрифта, и сделать это, используя привычные по работе с CSS единицы измерений. Например, не вызывает сомнений работоспособность всех следующих инструкций: context.font context.font context.font context.font context.font = = = = = '3em Helvetica' '16px Impact' '150% Courier' '10mm Times' '50pt Arial' Так давайте же возьмем некоторые из этих инструкций и воспользуемся ими для создания текстовых надписей на холсте, применив код, показанный в примере 8.1, где ради экономии места пятикратно повторяемый текст присвоен переменной output, значение которой затем, как показано на рис. 8.1, отображается с использованием шрифтов с разными именами и размерами, неизменно начинаясь с отступом в 10 пикселей по горизонтали, но довольно равномерно распределяясь по вертикальной оси с учетом разной высоты шрифтов. Пример 8.1 1. 2. 3. output = 'To be, or not to be...' context.font = '3em Helvetica'
Надписи на холсте 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. | 113 context.strokeText(output, 10, 50) context.font = '16px Impact' context.strokeText(output, 10, 100) context.font = '150% Courier' context.strokeText(output, 10, 150) context.font = '10mm Times' context.strokeText(output, 10, 210) context.font = '50pt Arial' context.strokeText(output, 10, 300) Рис. 8.1. Множество различных шрифтов и размеров Никаких контуров для этого примера не создавалось, поскольку каждая строка текста, отображаемая с помощью функции strokeText(), ведет себя как самостоятельный контур, открывая и закрывая различные контуры, используемые в ее прорисовке. Выравнивание текста Зачастую, как, например, в случае обработки текста, возникает желание выровнять текст не по левому краю, а по правому или по центру, и сделать это можно с помощью свойства контекста textAlign, в котором на данный момент поддерживаются пять значений: start, end, left (по умолчанию), right и center.
114 | Глава 8 Но по своей сути и назначению left и start, а также right и end весьма похожи друг на друга, за исключением того, что при использовании start выводимый текст для региональных настроек с направлением написания текста слева направо выравнивается по левому краю, а для таких же настроек с направлением справа налево — по правому. А при использовании end текст для региональных настроек с направлением написания текста слева направо выравнивается по правому краю, а для таких же настроек с направлением справа налево — по левому. Тем самым обеспечивается поддержка языков, где текст читается справа налево, но новичкам лучше возможность применения этих настроек игнорировать, чтобы не возникла путаница (подробнее в примечании ниже). Итак, посмотрим на рис. 8.2, где увидим, как изменит ситуацию добавление в подборку из примера 8.1 некоторых из предлагаемых выравниваний, показанное в примере 8.2, где к каждой из пяти пар инструкций было добавлено новое назначение свойства textAlign. Рис. 8.2. Выравнивание текста в соответствии с пятью поддерживаемыми свойствами Пример 8.2 1. 2. 3. 4. 5. 6. 7. output = 'To be, or not to be...' context.font = '3em Helvetica' context.textAlign = 'right' context.strokeText(output, 630, 50) context.textAlign = 'left'
Надписи на холсте 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. | 115 context.font = '16px Impact' context.strokeText(output, 10, 100) context.textAlign = 'center' context.font = '150% Courier' context.strokeText(output, 320, 150) context.textAlign = 'start' context.font = '10mm Times' context.strokeText(output, 10, 210) context.textAlign = 'end' context.font = '50pt Arial' context.strokeText(output, 630, 300) Здесь для хранения отображаемой строки также используется переменная output. После этого в пять разделов внесены изменения для выравнивания в следующем порядке: по правому краю, левому краю, центру, началу и концу (right, left, center, start и end). Чтобы поддержать эти настройки, для первой и пятой группы инструкций, где задается выравнивание по правому краю (right) и концу (end), горизонтальное смещение от левого края холста было перемещено до отступа всего в 10 пикселей от правого края. А для текста, выравниваемого по центру в третьей группе, задано горизонтальное смещение точно в центре холста, поскольку текст будет отцентрован вокруг любой предоставленной координаты, а нам нужно, чтобы он находился точно посередине холста. П РИМЕЧАНИЕ Если бы свойства start и end из последних двух инструкций применялись в условиях изменения направления письма на «справа налево» путем добавления в тег <HTML> в примере 8.2 атрибута dir="rtl", возник бы хаос, и основная часть текста стекла бы с холста. Попробуйте так сделать, чтобы увидеть результат, а затем попытайтесь исправить отображение, чтобы оно приобрело должный вид, изменив для этих двух групп инструкций значения смещения по горизонтали. После этого нетрудно будет понять, что новичкам по причине множества потенциальных проблем вряд ли стоит связываться с этими свойствами. Изменение толщины обводки Толщину обводки текста, нарисованного с помощью функции strokeFont(), можно изменить точно так же, как и толщину обводки прямоугольников из главы 7 «Прямоугольники и заливки». Давайте внесем изменения в предыдущий пример, чтобы получить код, показанный в примере 8.3, и посмотрим, какие можно создать эф-
116 | Глава 8 фекты. По мере раскрытия темы примеры становятся все длиннее, поэтому в следующем номера не проставлены, и показаны только новые строки, добавленные в начале каждой из пяти групп (не забывайте, что полный пример включен в прилагаемый к книге архив). Пример 8.3 context.lineWidth context.lineWidth context.lineWidth context.lineWidth context.lineWidth = = = = = 2 .5 .8 .25 7 В этом примере для линий пяти групп инструкций указывается толщина 2, .5, .8, .25 и 7. Результат применения этого кода показан на рис. 8.3, где можно увидеть наличие выбора между очень мелким и светлым текстом, чрезмерно жирным шрифтом и довольно уродливыми результатами в самом последнем тексте, где ширина линии составляет 7 пикселей. Рис. 8.3. Результат применения различной толщины линий Как видите, ограничений на применение дробных значений здесь нет. А вот значения 0 нужно остерегаться, поскольку оно, похоже, игнорируется (да и как можно себе представить линию нулевой толщины?), и все ранние назначения параметру linewidth остаются в силе. Если же действительно нужен текст с заливкой (и с приглядным видом), есть более подходящий способ, подробно рассмотренный в следующем разделе «Надписи с
Надписи на холсте | 117 заполнением», но сначала нужно разобраться с еще одним свойством под названием textBaseline, которое используется для указания горизонтальной линии, относительно которой текст будет выравниваться тем или иным образом. Есть четыре варианта выравнивания основания текста: сверху (top), посередине (middle), по символам (alphabetic) (по умолчанию) и снизу (bottom). Значение этих терминов в примере 8.4 выражено в виде текста, наложенного на горизонтальную направляющую линию и показывающего, где именно будет отображаться текст относительно линии для каждого применяемого термина. Пример 8.4 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. context.strokeStyle context.moveTo(0, context.lineTo(640, context.stroke() context.strokeStyle context.lineWidth context.font = "blue" 160) 160) = "red" = 2 = '26pt Helvetica' context.textBaseline = 'top' context.strokeText('Top', 20, 160) context.textBaseline = 'middle' context.strokeText('Middle', 150, 160) context.textBaseline = 'bottom' context.strokeText('Bottom', 300, 160) context.textBaseline = 'alphabetic' context.strokeText('Alphabetic', 450, 160) В этом примере в строках с 1 по 4 дается наш первый пример рисования отдельной линии. После отрисовки множества прямоугольников уже должно быть понятно, как это работает. В строке 1 задается синий цвет рисунка, в строке 2 он перемещается в положение от левой кромки холста на половину расстояния вниз, в строке 3 задается горизонтальная линия, направленная к правой кромке, а затем в строке 4 рисуется линия, указанная в предыдущих инструкциях. После этого в строках с 5 по 7 цвет меняется на красный, устанавливается толщина линии в 2 пикселя и выбирается размер и название шрифта. Затем следуют четыре пары инструкций, каждая из которых устанавливает значение для свойства textBaseline, после чего на его основе записывается тот или иной текст. Результат всего этого можно увидеть на рис. 8.4, где смутить может только один третий элемент, который смотрится парящим над базовой линией.
118 | Глава 8 Но в действительности ничего подобного нет, поскольку в тексте нет нисходящих символов нижнего регистра. Если бы там, к примеру, были слова с буквой y или g, текстовая строка располагалась бы прямо на базовой линии. Есть еще два других значения, применяемых к свойству textBaseline: подвешенного текста (hanging) (аналогичного значению top) для тибетских и других индийских шрифтов, и идеографического текста (ideographic) (аналогичного значению bottom) для китайских, японских и корейских шрифтов. Объяснение порядка их использования можно найти в Интернете. Рис. 8.4. Применение различных свойств базовой линии Надписи с заполнением Как и к прямоугольникам, к тексту можно применять все заливки, градиенты и заполнения узорами. Давайте посмотрим на ряд возможных результатов, и начнем с примера 8.5, где очень крупно шрифтом Impact написано слово ART, заполняющее основную часть холста. Пример 8.5 1. 2. context.font = '290pt Impact' context.fillText('ART', 30, 312) Как показано на рис. 8.5, по умолчанию для любой заливки используется черный цвет.
Надписи на холсте | 119 Рис. 8.5. Слово, написанное во весь холст А теперь поэкспериментируем с этой надписью, изменив, как показано в примере 8.6, заливку на градиент, применив самый простой градиент от белого к черному, и посмотрим на результат, показанный на рис. 8.6. Рис. 8.6. Теперь заливка градиентная, и добавлен контур
120 | Глава 8 Пример 8.6 1. 2. 3. 4. 5. 6. 7. context.font = '290pt Impact' gradient = context.createLinearGradient(320, 0, 320, 320) gradient.addColorStop(0, 'white') gradient.addColorStop(1, 'black') context.fillStyle = gradient context.fillText( 'ART', 30, 312) context.strokeText('ART', 30, 312) Как и прежде, в строке 1 задается размер и начертание шрифта. Но затем в строке 2 устанавливается эффект градиента от середины верхней части холста по вертикали до нижней части холста. Затем в строках 3 и 4 применяются две точки остановки цвета, после чего для свойства контекста fillStyle устанавливается заданный градиент, и в строке 6 для отображения текста вызывается функция fillText(). Чтобы получше выделить текст и придать ему очертания, в строке 7 делается вызов функции strokeText(). Внешний вид улучшился, но теперь давайте изменим надпись, перейдя сразу же к радиальному градиенту в цветах радуги, и сделаем слово ART по-настоящему артистичным. Один из способов достижения этой цели показан в примере 8.7, где на помощь приходит знание аббревиатуры цветов радуги ROYGBIV для красного (red), оранжевого (orange), желтого (yellow), зеленого (green), синего (blue), индиго (indigo) и фиолетового (violet), при задании их равномерного распределения по градиенту с интервалами между ними всего лишь в 0.16 или около 1/6 градиента. Пример 8.7 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. context.font = '290pt Impact' gradient = context.createRadialGradient(320, 320, 30, 320, 320, 400) gradient.addColorStop(0.00, 'red') gradient.addColorStop(0.16, 'orange') gradient.addColorStop(0.33, 'yellow') gradient.addColorStop(0.50, 'green') gradient.addColorStop(0.66, 'blue') gradient.addColorStop(0.83, 'indigo') gradient.addColorStop(1.00, 'violet') context.fillStyle = gradient context.fillText( 'ART', 30, 312) context.strokeText('ART', 30, 312) Помимо использования вместо предыдущих двух целых семи цветовых остановок, еще одно отличие заключается в том, что градиент радиальный и настроен на начало круга радиусом 30 пикселей с центром в нижней середине холста, расширяющимся до круга радиусом 400 пикселей с использованием того же центра. В результате получается великолепная радужная заливка, показанная на рис. 8.7.
Надписи на холсте | 121 Рис. 8.7. Надпись заполнена эффектом радужного радиального градиента Использование узора для заполнения надписи Для заполнения надписи можно не только выполнять одноцветную, монохромную, градиентную и радиальную заливку текста, но и любой выбранный узор. Если он достаточно крупный, то может просто отображаться полностью внутри текста, или же может получиться мозаика, составленная из такого количества узоров, которое необходимо для заполнения текста. В примере 8.8 показан узор, использовавшийся в главе 7 «Прямоугольники и заливки», перенацеленный, как показано на рис. 8.8, на заполнение слова ART. В строках со 2 по 5 находится уже знакомый по предыдущей главе код, предназначенный для загрузки изображения из файла tile.png, и ожидания готовности браузера к его использованию. Затем в фигурных скобках безымянной функции создается объект узора, назначаемый свойству контекста fillStyle, при этом код в строках 9 и 10 совпадает с кодом последних строк предыдущего примера, с помощью которых на холсте рисуется заполненное и обведенное слово. Пример 8.8 1. 2. 3. 4. 5. 6. context.font = '290pt Impact' image = new Image() image.src = 'tile.png' image.onload = function() {
122 7. 8. 9. 10. 11. | Глава 8 pattern = context.createPattern(image, 'repeat') context.fillStyle = pattern context.fillText( 'ART', 30, 312) context.strokeText('ART', 30, 312) } Рис. 8.8. Слово, заполненное мозаичным узором Вот и все, теперь на холсте HTML5 практически так же, как и с ранее освоенными прямоугольниками, можно будет работать и с текстом. Заключение Как оказалось, научиться написанию текста ничуть не сложнее, чем рисованию прямоугольников, и это одно из преимуществ последовательного изучения материалов книги. Каждая новая глава, как правило, основывается на знаниях, изложенных в предыдущих главах, и по мере расширения кругозора все более очевидным становится то, что следует изучить, поскольку подобные приемы уже были пройдены. Итак, надписи и прямоугольники освоены; в следующей главе предстоит научиться рисовать более тонкие и точные детали, используя линии и кривые на основе создания контуров.
ГЛАВА 9 Рисование на холсте Введение Сейчас уже пройдена практически половина пути к изучению порядка создания рисунков и надписей на холсте HTML5. В этой главе будет раскрыта основная часть оставшихся тонкостей рисования, а также получены начальные сведения о том, когда можно будет игнорировать ряд команд, поскольку во многих случаях они могут подразумеваться. Можно будет также при освоении различных способов рисования и заливки дуг, кривых и окружностей освежить в памяти подзабытые начала геометрии. Кроме этого, можно будет узнать способы маскировки областей холста с целью сохранения внешних областей при рисовании внутри отсеченной области. Также можно будет узнать, что дуги рисуются как по часовой стрелке, так и против нее, и понять, когда и почему тот или иной способ может пригодиться. Структура В этой главе рассматриваются следующие темы:  Изучение оставшихся функций рисования линий.  Приемы рисования всевозможных дуг и кривых линий.  Способы создания маски с помощью функции clip().  Приемы работы с линиями, путями, заглушками и соединениями (lines, paths, end caps и joins). Цели После изучения предлагаемого материала станут известны все основные методы рисования линий, заливок, кривых, дуг и текста, рассматриваемые в этой и предыдущих главах. В вашем арсенале окажутся все основные инструменты, необходимые для рисования на холсте HTML5, за исключением манипулирования изобра-
124 | Глава 9 жениями, прозрачностью и другими новыми методами, изучение которых предстоит в следующих двух главах. Рисование линий с использованием путей Работа с холстом HTML5 во многом зависит от использования путей для рисования. Основной смысл заключается в предоставлении возможности предварительного создания всевозможных путей с последующей быстрой прорисовкой всего пути с помощью одной команды. Это обеспечивает очень быстрое рисование, которое можно использовать даже в целях анимации. Такой порядок рисования может показаться странным, поскольку порой кажется, что можно обойтись и без предварительного создания пути, как это было в предыдущей главе при рисовании горизонтальной линии для иллюстрации использования с текстом базовой линии. Этот пример работал потому, что ничего другого на холсте не рисовалось, поэтому и не было никаких случайных линий или ошибок. Однако когда дело дойдет до рисования замкнутых фигур любого вида, которые, возможно, захочется заполнить тем или иным способом, то вскоре, если не придерживаться правил открытия и закрытия путей в нужных местах, придется столкнуться со странными и неожиданными результатами. Поэтому всем новичкам рекомендуется всегда открывать и закрывать пути всякий раз при рисовании чеголибо, что можно рассматривать как отдельную фигуру или того, что чуть позже, возможно, захочется рассматривать в качестве единой фигуры. Рис. 9.1. Пара фигур, нарисованных на холсте
Рисование на холсте | 125 Давайте немного углубимся в этот вопрос, обратившись к примеру 9.1, где, как показано на рис. 9.1, создается последовательность линий, образующих фигуру в виде очерченного знака плюс, наложенную на фигуру ромба. Пример 9.1 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. context.moveTo( 10, context.lineTo( 10, context.lineTo(290, context.lineTo(290, context.lineTo(350, context.lineTo(350, context.lineTo(630, context.lineTo(630, context.lineTo(350, context.lineTo(350, context.lineTo(290, context.lineTo(290, context.lineTo(10, 130) 190) 190) 310) 310) 190) 190) 130) 130) 10) 10) 130) 130) context.moveTo(100, context.lineTo(320, context.lineTo(540, context.lineTo(320, context.lineTo(100, 160) 50) 160) 270) 160) context.stroke() Рис. 9.2. Применение заливки привело к весьма неожиданным результатам
126 | Глава 9 Казалось бы, все выглядит здорово! А теперь давайте посмотрим, почему все может быть не так, как кажется на первый взгляд, добавив, как показано ниже, после вызова функции stroke() в строке 21 всего лишь одну дополнительную инструкцию, и посмотрим, что получится (рис. 9.2). 22. context.fill() К более подробному рассмотрению инструкции fill() мы вскоре вернемся, но что можно сделать, чтобы получить более ожидаемый результат? Ответ прост: нужно разбить две фигуры на отдельные пути. В примере 9.2 можно увидеть, что теперь есть две отдельных и независимых части, и результат их применения, показанный на рис. 9.3, более похож на то, что, вероятно, и планировалось создать. Рис. 9.3. После разбиения фигур с помощью путей заливка работает в соответствии с ожиданиями Пример 9.2 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. context.beginPath() context.moveTo( 10, context.lineTo( 10, context.lineTo(290, context.lineTo(290, context.lineTo(350, context.lineTo(350, context.lineTo(630, context.lineTo(630, context.lineTo(350, context.lineTo(350, 130) 190) 190) 310) 310) 190) 190) 130) 130) 10)
Рисование на холсте 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. | 127 context.lineTo(290, 10) context.lineTo(290, 130) context.lineTo(10, 130) context.closePath() context.stroke() context.fillStyle = 'yellow' context.fill() context.beginPath() context.moveTo(100, context.lineTo(320, context.lineTo(540, context.lineTo(320, context.lineTo(100, context.closePath() 160) 50) 160) 270) 160) context.stroke() context.fillStyle = 'red' context.fill() Рис. 9.4. В отсутствие путей заливка опять становится непредсказуемой Давайте разберемся, почему все это работает. Сначала в строках с 1 по 15 создается фигура плюса, помещенная на свой собственный путь. Затем в строках с 17 по 19 появляется обводка, выбирается желтый цвет заливки, которая затем и применяется к фигуре. Во второй части примера, в строках с 21 по 28, по своему собственному
128 | Глава 9 пути создается фигура ромба. Затем в строках с 29 по 31 применяется обводка, выбирается красный цвет заливки, которая затем тоже применяется (рис. 9.4). Получились две различные заполненные фигуры, причем более новая перекрывает предыдущую; все очень похоже на ожидаемый нами рисунок. А теперь, ради интереса, давайте закомментируем строки инструкций пути 1, 15, 21 и 27 (чтобы они не выполнялись), поместив перед инструкциями, как показано в примере 9.4 (где в целях экономии приведены только измененные строки), по паре слэшей (//). Затем посмотрим на результат, показанный на рис. 9.4, который снова дал не то, что предполагалось увидеть. Пример 9.3 (только закомментированные строки): 1. 15. 21. 27. // // // // context.beginPath() context.closePath() context.beginPath() context.closePath() Конечно, эффект, показанный на рис. 9.4, по-своему интересен. Но если он не соответствует желаемому, то пользы от него никакой. И пусть этот пример яcно даст понять, почему все рисуемые на холсте фигуры нужно заключать в их собственные пути, по крайней мере, пока вы не приобретете достаточный опыт рисования на холсте. Применение заполнений Пару раз в этой главе функция fill() уже применялась, а теперь давайте выясним, как она работает и используется. Сложностей в этом разделе не предвидится, поскольку использование функции очень похоже на использование инструкции fillRect(), подробно разобранной в предыдущей главе. Основное сходство fill() и fillRect()в том, что любые выбранные вами свойства fillStyle будут применяться как к одной, так и к другой функции. Разница в том, что fill() применяется к самому последнему пути. При создании нового пути fill() применится только к нему, а любой предыдущий путь будет забыт. Зная это, вы теперь понимаете, как нарисовать любую желаемую фигуру, составленную из прямых линий, а затем заполнить ее любым сплошным цветом, линейным или радиальным градиентом или любым выбранным узором. Все подробности этих заполнений рассматриваются в главе 8 «Надписи на холсте». Ограничения областей холста Иногда при рисовании с помощью графической программы полезно настроить маску таким образом, чтобы рисунок был только внутри маски. Аналогичного эффекта
Рисование на холсте | 129 можно добиться и при рисовании на холсте, выбрав ограниченный подраздел, внутри которого будет появляться будущий рисунок или заполнение (пока не будет создан новый обрезанный путь), но за его пределами ничего происходить не будет. Чтобы проиллюстрировать этот эффект, давайте сравним простое рисование фигуры на холсте с предварительно установленной областью ограничения и последующим рисованием, задаваемым кодом примера 9.4 (в нем нумерация строк намеренно начинается с 12, чтобы осталось место для дополнительного кода), где сначала рисуется закрашенный зеленый ромб, а затем над ним располагается диагональный крест толщиной в одну линию (рис. 9.5). Рис. 9.5. Пара фигур, нарисованных на холсте Пример 9.4 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. context.beginPath() context.moveTo(320, context.lineTo(630, context.lineTo(320, context.lineTo( 10, context.lineTo(320, context.closePath() 10) 160) 310) 160) 10) context.fillStyle = 'green' context.fill() context.beginPath() context.moveTo(0, 0)
130 25. 26. 27. 28. 29. 30. | Глава 9 context.lineTo(639, 319) context.moveTo(0, 319) context.lineTo(639, 0) context.closePath() context.stroke() Все это должно быть предельно ясно, т. е. имеются две части кода: в первой задается путь для ромбовидной фигуры, после чего выполняется заполнение ее зеленым цветом, а во второй над ромбом рисуется простой диагональный крест в одну линию. А теперь давайте посмотрим, что произойдет, если код из примера 9.5 вставить перед кодом из примера 9.4, чтобы сначала создать ограниченную область холста в форме прямоугольника. В строке 9 делается дополнительный вызов stroke(), потому что граница обрезки невидима, но после вызова stroke() ее можно увидеть. Добавлять вызов stroke() для ограниченной области или нет — зависит от намерений при каждом рисовании. Пример 9.5 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. context.beginPath() context.moveTo(170, context.lineTo(470, context.lineTo(470, context.lineTo(170, context.lineTo(170, context.closePath() context.lineWidth = context.stroke() context.clip() 10) 10) 310) 310) 10) 1 В результате предварительной настройки этой ограниченной области изображение теперь выглядит так, как показано на рис. 9.6, где виден шестиугольник с двумя диагональными линиями. Как видите, все, что нарисовано за пределами ограниченной области, было проигнорировано, независимо от того, чем оно было нарисовано: вызовом функции stroke() или fill(). Самое важное — при задании ограниченной области холста следует помнить, что она будет действовать только до тех пор, пока не будет задана новая ограниченная область или не будет достигнут конец инструкций. Поэтому, как только использование ограниченной области будет завершено, можно выполнить перенастройку маски ограничения на весь холст (или, в случае необходимости, на новую область) или же гораздо проще будет вспомнить порядок использования в контексте функций save() и restore(), как это делалось при перемещении координат холста в главе 7 «Прямоугольники и заливки»?
Рисование на холсте | 131 Рис. 9.6. Все рисунки за пределами ограниченной области игнорируются Ведь эти две функции позволяют сохранить все, что касается текущего контекста, поэтому при использовании ограниченных областей зачастую бывает полезно сначала выполнить инструкцию context.save(), а когда работа с ограниченной областью завершится, все прежние настройки контекста можно будет восстановить с помощью простого вызова context.restore(). Теперь для сброса ограниченной области уже не нужно вспоминать полный размер холста. Вообще-то, следует взять в привычку использование save() и restore() при каждом внесении в контекст холста больших изменений, так как это самый простой и легкий способ вернуться к предыдущим значениям. Рисование кривых линий Если нужно нарисовать окружность или любую кривую линию, то первым делом следует воспользоваться функцией arc(), но для ее эффективного применения нужно слегка разбираться в геометрии, поскольку эта функция принимает целый ряд различных аргументов. Первые два аргумента X и Y задают горизонтальную и вертикальную координату центра дуги. Затем следует задание радиуса дуги, а также начального и конечного углов. Именно здесь и нужны познания в геометрии, поскольку начальный и конечный углы задаются в радианах, являющихся угловыми единицами измерения, основанными на константе PI. Наверное, нетрудно вспомнить, что PI имеет значение примерно 3,1416, а длина окружности в 2 раза больше PI, или примерно 6,2832. А в окружностях 360 градусов.
132 | Глава 9 Теперь представьте, что нужно пройтись по большой окружности. Для этого следует пройти 360 градусов или 6,2823 радиана. Но, поскольку 360 градусов — слишком большое число, когда в обиходе только половина или четверть окружности, придется применять значения 180 или 90 градусов, а также, исходя из того, что 6,2823 — слишком неудобное число с плавающей точкой, было придумано значение радиана, где 1 радиан равен 180 градусам, поделенным на PI, что примерно составляет 57 градусов. Если использование радиана представляется сложнее, чем использование градусов, то это всего лишь пока дело не дойдет до рисования дуги в половину окружности, где можно будет просто сказать, что хотите, чтобы в радианах она была равна числу PI. Или для полного круга в радианах понадобится просто умножить PI на 2, а для четверти круга в радианах — разделить PI на 2. Как видим, обычно сами по себе радианы не используются. Чаще всего они используются в сочетании с числом PI. Просто следует запомнить, что полная окружность в радианах равна двум, умноженным на PI, и этого будет вполне достаточно. Выбор направления Есть один последний (необязательный) аргумент, который можно передать функции arc(), он задает направление рисунка: по часовой стрелке или против нее. По умолчанию устанавливается значение false, означающее направление по часовой стрелке, а чтобы рисовать в направлении против часовой стрелки, можно указать значение true. Рис. 9.7. Четыре разные дуги
Рисование на холсте | 133 Давайте посмотрим на сочетание этих шести аргументов, нарисовав набор из четырех дуг, используя код примера 9.6, где каждый набор инструкций рисует по очереди ¼, ½, ¾ и, наконец, полный круг. Результат загрузки этого примера в браузер показан на рис. 9.7. Пример 9.6 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. context.beginPath() context.arc(128, 160, 60, 0, Math.PI / 2) context.stroke() context.beginPath() context.arc(256, 160, 60, 0, Math.PI) context.stroke() context.beginPath() context.arc(384, 160, 60, 0, Math.PI / 2 * 3) context.stroke() context.beginPath() context.arc(512, 160, 60, 0, Math.PI * 2) context.stroke() П РИМЕЧАНИЕ Заметили кое-что интересное насчет пути в примере 9.6? В этом коде используется тот факт, что с началом каждого нового пути предыдущий автоматически закрывается, позволяя обойтись без вызова функции closePath(). Здесь ни одна из фигур не подвергалась заполнению, и для закрытия путей, исходящих из их начальных точек, вызывать closePath() не потребовалось. По сути, если вас устраивает автоматическое соединение начальной и конечной точки, или же вы сами для закрытия фигуры вызываете moveTo() или lineTo(), то никакой практической нужды в закрытии пути нет. Но если в результате незакрытого пути появится нечто неожиданное, то это, скорее всего, ваш просчет. Если сравнить строки 2, 6, 10 и 14, в которых рисуются дуги, можно увидеть, что в строке 2 последний аргумент, задающий значение PI (в JavaScript обозначается как Math.PI), делится на 2, т. е. функция arc() получает указание рисовать только четверть окружности. Затем в строке 6 для рисования половины окружности просто используется PI, а в строке 10 сначала вычисляется значение значение PI / 2, чтобы получить значение для четверти круга, которое затем умножается на 3, чтобы получить значение, необходимое для трех четвертей окружности. И наконец, в строке 10 для получения полной окружности используется число PI, умноженное на 2. Радиус каждой из этих дуг составляет 60 пикселей, но вы заметили, что все дуги начинаются в положении «на 3 часа», под углом 90 градусов от вершины окружно-
134 | Глава 9 сти? Дело в том, в качестве начального значения в каждом случае был установлен всегда задающий начало в самой правой точке окружности или на 3 часа. 0, Кроме того, поскольку шестой аргумент для направления рисования не указан, все дуги рисуются по часовой стрелке. Если, как показано в примере 9.7 (где для экономии места показаны только измененные строки) для каждой из этих строк указать значение true, отображаемый результат будет выглядеть, как показано на рис. 9.8, что должно помочь прояснить важность выбора правильного направления рисования при использовании функции arc(), поскольку теперь все части окружностей, кроме полной окружности, выглядят как инвертированные. Рис. 9.8. Направление рисования было изменено, и теперь оно против часовой стрелки Пример 9.7 (только те строки из примера 9.6, которые были изменены): 2. 6. 10. 14. context.arc(128, context.arc(256, context.arc(384, context.arc(512, 160, 160, 160, 160, 60, 60, 60, 60, 0, 0, 0, 0, Math.PI / 2, true) Math.PI, true) Math.PI / 2 * 3, true) Math.PI * 2, true) Теперь давайте посмотрим, как происходит заполнение этих путей, но не от начальной точки к конечной, поскольку это получилось бы не очень аккуратно, а с использованием центральной точки каждой дуги, чтобы они, как показано на рис. 9.9, выглядели бы как целый торт, или как торт с вырезанными кусочками, как в при-
Рисование на холсте | 135 мере 9.8, где вызов функции moveTo() выполняется перед каждым вызовом arc(), чтобы установить центр каждой дуги для вызовов функции fill(). Рис. 9.9. Теперь дуги заполнены в виде кусочков торта Пример 9.8 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. context.beginPath() context.moveTo(128,160) context.arc( 128, 160, 60, 0, Math.PI / 2) context.fill() context.beginPath() context.moveTo(256,160) context.arc( 256, 160, 60, 0, Math.PI) context.fill() context.beginPath() context.moveTo(384,160) context.arc( 384, 160, 60, 0, Math.PI / 2 * 3) context.fill() context.beginPath() context.moveTo(512,160) context.arc( 512, 160, 60, 0, Math.PI * 2) context.fill()
136 | Глава 9 П РИМЕЧАНИЕ В примере 9.8 также не было необходимости закрывать каждый путь, поскольку с помощью вызовов moveTo() для каждой дуги предварительно выбиралась начальная точка, и когда вызывалась функция fill(), она, как и предполагалось, автоматически закрывала тот путь, который в обратном направлении привел бы к начальной точке. Рисование дуги к конкретной точке Пока мы рассматривали только рисование дуг на основе заданной центральной точки, но дугу на холсте HTML5 можно рисовать и другими способами, один из которых предполагает использование функции arcTo(). С его помощью дуга рисуется на основе текущего местоположения пути и пары воображаемых касательных линий к периметру дуги, как будто она является полной окружностью. По сути, нужно представить себе две линии, сходящиеся в одной точке, с единственной точкой на каждой линии в месте ее примыкания к внешнему краю дуги. Теперь представьте, что между этими двумя точками рисуется дуга, окружность которой обращена к воображаемому углу. Рис. 9.10. Рисование дуги к определенному месту В примере 9.9 путем рисования двух таких воображаемых линий создается картина, при которой они становятся видимыми, с кружками, нарисованными вокруг начальной и последующих двух точек, и все это в красном цвете. Затем в нем исполь-
Рисование на холсте | 137 зуется функция arcTo(), чтобы, как показано на рис. 9.10, нарисовать синим цветом дугу, представленную начальной точкой и двумя точками пути. Пример 9.9 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. context.strokeStyle = 'red' context.lineWidth = 2 context.beginPath() context.arc( 500, context.moveTo(500, context.arc( 430, context.lineTo(430, context.arc( 50, context.lineTo(50, context.stroke() 30, 3, 0, Math.PI * 2) 30) 270, 3, 0, Math.PI * 2) 270) 270, 3, 0, Math.PI * 2) 270) context.beginPath() context.strokeStyle = 'blue' context.moveTo(500, 30) context.arcTo( 430, 270, 50, 270, 300) context.stroke() Рис. 9.11. Дуга без воображаемых направляющих линий Здесь в строках 1 и 2 задается цвет и толщина линий, подготавливаемых к рисованию воображаемых линий и кругов вокруг трех точек. Затем в строках с 4 по 11
138 | Глава 9 рисуются две красные линии с начальной точкой в правом верхнем углу и конечной точкой в левом нижнем углу. И наконец, в строках с 13 по 17 выполняется перемещение в начальное положение 500,30, а затем с использованием этого начального положения через следующие две точки с координатами 430,270 и 50,270, рисуется синяя дуга с радиусом 300 пикселей. Без этих направляющих линий результат выглядел бы так, как показано на рис. 9.11. Использование аттракторов И наконец, в наборе функций рисования кривых линий имеется возможность выводить на холст кривые любого типа, которые только можно себе представить, используя квадратичные кривые и кривые Безье. В определенном смысле они работают так же, как и функция arcTo(), но больше похожи на гравитационный аттрактор, притягивающий к себе кривую линию. Квадратичная кривая имеет один аттрактор, а для кривой Безье используется два. Начнем с применения одного аттрактора и функции quadraticCurveTo(). Для этого потребуется два набора аргументов: в первом задается размещение воображаемого аттрактора, а во втором — конечных точек дуги. Но перед вызовом функции необходимо переместить текущий путь туда, где должна начинаться кривая. Аттрактор может располагаться даже где-то за пределами холста, чтобы кривая получалась сильно вытянутой, или где-нибудь внутри холста, чтобы эффект вытянутости был слабее. Рис. 9.12. Квадратичная кривая, притягиваемая воображаемым аттрактором
Рисование на холсте | 139 В примере 9.10 красным цветом специально рисуется воображаемая базовая линия и круг в воображаемой точке аттрактора. Затем, как показано на рис. 9.12, в нем с этими параметрами синим цветом рисуется квадратичная кривая. Пример 9.10 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. context.strokeStyle = 'red' context.lineWidth = 2 context.beginPath() context.moveTo( 10, 160) context.lineTo(630, 160) context.stroke() context.beginPath() context.arc(10, 10, 3, 0, Math.PI * 2) context.stroke() context.strokeStyle = 'blue' context.beginPath() context.moveTo(10, 160) context.quadraticCurveTo(10, 10, 630, 160) context.stroke() В строках 1 и 2 примера 9.10 задается цвет и толщина воображаемой линии и аттрактора. Затем в строках с 4 по 10 через центр холста проводится горизонтальная линия и рисуется круг в точке аттрактора в левом верхнем углу. После этого в строках с 12 по 16 выполняется перемещение к левой стороне воображаемой линии, а затем вправо вдоль линии рисуется квадратичная кривая синего цвета, но с аттрактором, притягивающим к себе кривую. Как уже ранее упоминалось, у кривой Безье имеется второй аттрактор, помещаемый на холст кодом примера 9.11, который отличается от кода примера 9.10 добавлением второй точки аттрактора с координатами 630,310. В результате на холст помещается двойная кривая, показанная на рис. 9.13. Пример 9.11 1. 2. 3. 4. 5. 6. 7. 8. context.strokeStyle = 'red' context.lineWidth = 2 context.beginPath() context.moveTo( 10, 160) context.lineTo(630, 160) context.stroke() context.beginPath()
140 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. | Глава 9 context.arc(10, 10, 3, 0, Math.PI * 2) context.stroke() context.beginPath() context.arc(630, 310, 3, 0, Math.PI * 2) context.stroke() context.strokeStyle = 'blue' context.beginPath() context.moveTo(10, 160) context.bezierCurveTo(10, 10, 630, 310, 630, 160) context.stroke() Рис. 9.13. Кривая Безье с двумя воображаемыми аттракторами Как и в предыдущем примере, код примера 9.11 начинается со строк 1 и 2, задающих красный цвет и толщину линии 2 для воображаемой линии и аттракторов. Затем в строках с 4 по 13 рисуется горизонтальная линия и два круга для аттракторов в левом верхнем и правом нижнем углу экрана. И наконец, в строках с 15 по 19 осуществляется перемещение в позицию 10,160, а затем рисуется синяя кривая линия, нацеленная на позицию 630,160. На своем пути она сначала притягивается вверх и влево аттрактором на позиции 10,10, а затем вниз аттрактором на позиции 630,310. Разумеется, прорисовка всех этих кривых не обошлась без применения функции stroke(), но при желании можно было бы также воспользоваться любым из поддерживаемых методов заполнения.
Рисование на холсте | 141 Завершение и схождение линий Осталось уложить последний фрагмент пазла рисования линий, отвечающий на вопрос: что делать, когда две линии сходятся? Должна ли вершина схождения быть ровной? Должна ли она закругляться? Или же ее лучше заострить? А чем должна завершаться линия? Должны ли она быть с квадратными, обрубленными или закругленными краями? К счастью, благодаря свойству lineCap, предлагающему все три варианта краев линии при предоставлении ему аргументов butt, round или square, и свойству lineJoin, поддерживающему значения round, bevel и miter, можно выбрать любую нужную форму как края линии, так и вершины схождения. Давайте посмотрим, как эти свойства можно использовать в примере 9.12, где в строках с 1 по 7 создаются две опорные линии красного цвета, обозначающие нижнюю и верхнюю часть рисуемых линий. Затем в строках с 9 по 11 их толщина увеличивается со значения по умолчанию до 20 пикселей и задается использование синего цвета. Все это, как показано на рис. 9.14, сделано для того, чтобы можно было легко заметить различные эффекты применения новых свойств. Рис. 9.14. Выбор форм завершений и схождений линий Пример 9.12 1. 2. 3. 4. context.strokeStyle = 'red' context.beginPath() context.moveTo(30, 70) context.lineTo(610, 70)
142 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. | Глава 9 context.moveTo(30, 250) context.lineTo(610, 250) context.stroke() context.beginPath() context.lineWidth = 20 context.strokeStyle = 'blue' context.beginPath() context.lineCap = 'round' context.moveTo( 91, 250) context.lineTo( 91, 70) context.stroke() context.beginPath() context.lineCap = 'butt' context.moveTo(183, 250) context.lineTo(183, 70) context.stroke() context.beginPath() context.lineCap = 'square' context.moveTo(274, 250) context.lineTo(274, 70) context.stroke() context.beginPath() context.lineCap = 'round' context.lineJoin = 'round' context.moveTo(335, 250) context.lineTo(365, 70) context.lineTo(395, 250) context.stroke() context.beginPath() context.lineCap = 'butt' context.lineJoin = 'bevel' context.moveTo(427, 250) context.lineTo(457, 70) context.lineTo(487, 250) context.stroke() context.beginPath() context.lineCap = 'square' context.lineJoin = 'miter' context.moveTo(518, 250) context.lineTo(548, 70) context.lineTo(578, 250) context.stroke()
Рисование на холсте | 143 В каждом из первых трех наборов инструкций, в строках с 13 по 17, в строках с 19 по 23 и в строках с 25 по 29, задается рисование линии с краями, и в них поочередно используются свойства lineCap со значениями round (закругленные), butt (обрубленные) и square (квадратные). На рис. 9.14 показано, что как закругленные, так и квадратные края линий выходят за границы опорных линий. А вот обрубленные края получаются в соответствии с ожиданиями и обрубаются точно по опорным линиям. В следующих трех наборах инструкций, в строках с 31 по 37, с 39 по 45 и с 47 по 53, в краях каждой пары линий повторяются те же самые свойства lineCap, но также к местам соединений применяются свойства lineJoin, в которых поочередно задается закругленная (round), плоская (bevel) и заостренная (miter) вершина соединения. Здесь опять же можно увидеть, как закругленные и заостренные вершины выходят за границу опорной линии, при этом заостренная вершина для достижения нужного эффекта должна получить существенное удлинение. А вот плоская вершина опять обрубается по опорной линии. Надеюсь, здесь все понятно, но можно задаться вопросом: насколько далеким может быть вылет заостренной вершины соединения, особенно при очень тонких линиях в сочетании с довольно острыми углами? Ответ таков: вылет может оказаться слишком большим, но его можно изменить, воспользовавшись свойством по имени miterLimit, к которому применяется ограничивающее значение в пикселях. Оно позволяет всем заостренным вершинам иметь вылет до заданного количества пикселей, но, если удлинение продолжится, вершина станет плоской. Рис. 9.15. Самая правая заостренная вершина стала плоской
144 | Глава 9 Давайте попробуем перед последним вызовом stroke() в строке 53 добавить следующее: context.miterLimit = 6 Тогда станет видно, что заострение теперь ограничено только 6 пикселями, а поскольку фактический вылет составляет не менее 7 пикселей, вершина, как показано на рис. 9.15, становится плоской. Заключение Эта глава завершает курс последних нескольких глав, посвященный рисованию прямых и кривых линий, а также криволинейных фигур, рассматривающий варианты соединения и завершения линий. Также уделено внимание заполнению фигур, надписям на холсте и использованию всевозможных градиентов и узоров. Следующая глава будет посвящена работе с изображениями, добавлению теней и преобразованиям.
ГЛАВА 10 Работа с холстом Введение Итак, на пути изучения материалов книги достигнута важная веха. Изучены почти все функции рисования на холсте HTML5, и бонусом при изучении холста освоены азы написания кода на JavaScript. Теперь уже можно будет перейти к нескольким оставшимся, более сложным операциям работы с холстом, куда входят рисование изображений непосредственно на холсте, которое уже было показано при создании заполнений мозаичными узорами, и будут показаны приемы произвольного изменения размеров изображений или даже создания новых изображений из частей холста, а также использования прозрачности и теней для получения более высоких результатов. Будет даже показано, как хранятся данные изображения холста, что позволит переходить к их непосредственному изменению, возможно, с переменой цвета, осветлением или переводом в палитру с оттенками серого цвета. Конечно, это повлечет за собой дальнейшее изучение приемов работы с кодом JavaScript, но вы уже давно готовы к этому, и сможете во всем разобраться в ходе работы над материалом главы. Структура В этой главе рассматриваются следующие темы:  Применение различных способов рисования на холсте с использованием изображений.  Освоение приемов извлечения частей изображений, а также увеличения и изменения их размеров.  Способы прикрепления теней ко всем типам рисунков на холсте.  Основные приемы непосредственного управления данными холста. Цели Здесь, перед переходом к следующей, заключительной главе, призванной поднять ваши навыки на следующую ступень мастерства, будет завершено изучение основных функций холста HTML5.
146 | Глава 10 Рисование с использованием изображений У холста HTML имеется возможность загружать изображение в JavaScript, а затем размещать его различными способами, применяя для этого функцию drawImage(), которая обычно принимает три аргумента: имя объекта изображения и координаты верхнего левого угла, где оно должно быть вставлено в холст. При желании можно также предоставить пару дополнительных аргументов, указывающих новую ширину и высоту изображения. Из предыдущих глав известно, что загрузка изображений и управление ими с помощью JavaScript требует особого обращения, поскольку изображения намного больше сценариев, и поэтому к моменту запуска сценария могут быть еще не загружены. Чтобы справиться с этой проблемой, используется принадлежащее объекту изображения событие onload объекта изображения, позволяющее выполнять инструкции сценария только после обеспечения полной загрузки изображения в память. В примере 10.1 показано создание нового (пустого) объекта изображения. Затем, чтобы приступить к загрузке изображения, свойству src этого объекта присваивается его имя. Сразу после этого присваивания вызывается безымянная функция, код которой помещается между фигурными скобками функции и запускается после готовности изображения к использованию. Результат показан на рис. 10.1. Рис. 10.1. Рисование с использованием изображения Пример 10.1 1. 2. image = new Image() image.src = 'smiley.png'
Работа с холстом 3. 4. 5. 6. 7. | 147 image.onload = function() { context.drawImage(image, 10, 10) } Изображение в файле smiley.png имеет размеры 160 × 160 пикселей и использует такую же степень прозрачности, что и у всех пикселей за пределами области изображения. Оно загружается на холст с установкой левого верхнего угла в позицию 10,10. Но давайте посмотрим, что произойдет, если добавить два дополнительных аргумента к трем дополнительным вызовам функции drawImage(), задавая в коде примера 10.2 один больший и два меньших размера изображений, причем один из них еще меньше самого первого изображения. Результат показан на рис. 10.2. Рис. 10.2. Рисование изображений разных размеров Пример 10.2 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. image = new Image() image.src = 'smiley.png' image.onload = function() { context.drawImage(image, context.drawImage(image, context.drawImage(image, context.drawImage(image, } 10, 200, 460, 560, 10) 10, 240, 240) 10, 80, 80) 10, 40, 40)
148 | Глава 10 Если присмотреться к рис. 10.2, можно заметить один из недостатков такого изменения размера изображений: при сильном увеличении изображения могут стать слегка размытыми, а при слишком сильном уменьшении — становятся крапчатыми в тех местах, где должны состоять из сплошных линий. Как бы то ни было, пока размер исходного изображения достаточно близок к тому, в котором вы собираетесь его использовать, зачастую можно смириться с небольшими изменениями размера и с небольшими едва заметными эффектами. Но когда нужные размеры существенно отличаются от исходных, лучше воспользоваться графической программой и создать изображения разного размера, сохраняя их под разными именами файлов. Извлечение частей изображений При рисовании изображения на холсте можно также решить, нужно ли использовать все изображение целиком или же можно обойтись только какой-либо из его частей. Но для этого требуется переосмыслить передачу аргументов функции drawImage(), поскольку вместо добавления дополнительных аргументов к уже переданным нужно вставить их между именем объекта изображения и координатами и размерами рисования изображения. Можно удивиться и спросить: «А откуда JavaScript узнает о моих намерениях?» Дело в том, что JavaScript ищет после указания изображения два, четыре или восемь аргументов. Если их два, изображение помещается в указанное верхнее левое положение без изменений. Если их четыре, изображение по-прежнему размещается в указанном месте, но изменяется в соответствии с размерами, указанными в последних двух аргументах. Но если переданы восемь аргументов, то первые два берутся для представления места на изображении, откуда извлекается его часть, а следующие два задают ширину и высоту извлекаемой области. И наконец, четыре оставшихся аргумента задают пару координат, определяющих позицию верхнего левого угла извлеченной части изображения, а последние два определяют ширину и высоту, до которых нужно изменить размер этой части. Ввести только шесть аргументов в ожидании, что выбранная область будет нарисована в извлеченном размере, не получится, поэтому нужно обязательно указать используемую на холсте ширину и высоту. С учетом всего вышеизложенного, в примере 10.3 изображение снова рисуется в исходном размере в верхнем левом углу холста. В строке 7 задается рисунок версии, извлеченной вокруг изображения глаз, в тех же размерах 160 × 160, что и исходное полное изображение, а в строке 8 делается то же самое, но с увеличением рисунка. Пример 10.3 1. 2. image = new Image() image.src = 'smiley.png'
Работа с холстом 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. | 149 image.onload = function() { context.drawImage(image, 10, 10) context.drawImage(image, 43, 12, 75, 75, 200, 10, 160, 160) context.drawImage(image, 43, 12, 75, 75, 380, 10, 240, 240) context.strokeStyle = 'blue' context.strokeRect(10 + 43, 10 + 12, 75, 75) stroke() } Строки с 10 по 15 были добавлены в код примера только для того, чтобы нарисовать над исходным изображением прямоугольник синего цвета, показывающий извлекаемую часть со смещением на 10 пикселей по горизонтали и вертикали, чтобы компенсировать смещение изображения на эту величину от верхнего левого угла. Результат выполнения кода можно увидеть на рис. 10.3. Рис. 10.3. Размер части изображения изменен Использование холста в качестве исходного изображения В качестве исходного изображения можно даже использовать сам холст, после чего создать с его помощью рисунок, как показано в примере 10.4, где холст захватывается и рисуется обратно на холсте в левом нижнем углу с измененным размером.
150 | Глава 10 Пример 10.4 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. image = new Image() image.src = 'smiley.png' image.onload = function() { context.drawImage(image, 10, 10) context.drawImage(image, 43, 12, 75, 75, 200, 10, 160, 160) context.drawImage(image, 43, 12, 75, 75, 380, 10, 240, 240) context.drawImage(canvas, 10, 10, 620, 300, 10, 200, 270, 130) } По сути, в примере 10.4 содержится первая часть примера 10.3, за которой в строке 10 следует последняя инструкция, предписывающая захват области холста, начинающейся с позиции 10,10 и имеющая ширину и высоту 620 × 300, а затем ее перерисовку обратно на холст, начиная с позиции 10,200 и с размерами 270 × 130 пикселей. Результат показан на рис. 10.4. Рис. 10.4. Использование в качестве исходного изображения самого холста Нетрудно представить, что этот прием позволяет многократно захватывать и возвращать холст, создавая эффекты вроде того, когда лицо находится между двух направленных друг на друга зеркал, и кажется, что появляется бесконечный туннель.
Работа с холстом | 151 Прикрепление теней Чтобы продемонстрировать возможность добавления к изображениям эффекта теней, в приводимых примерах использовалось изображение, содержащее параметр прозрачности. Конечно же, тени, добавленные к прямоугольным фигурам, таким как фотографии, могут выглядеть впечатляюще, но, если изображение имеет непрямоугольную форму, возникает желание применить тень не ко всему изображению, а к его основному содержимому. Поэтому давайте посмотрим, что получится, если присвоить значения четырем свойствам, позволяющим создавать тени: shadowOffsetX, shadowOffsetY, shadowBlur и shadowColor. Нетрудно догадаться, что в первых двух свойствах задается смещение от основного изображения в пикселях по горизонтали и вертикали, а в двух остальных — степень размытия и цвет, применяемый к тени. Без размытия тень может выглядеть слишком резкой и нереальной, а если тень просто черная (или серая), она может выглядеть непривлекательно, и добавление слабого оттенка цвета изображения может сделать ее гораздо выигрышнее. В примере 10.5 этим четырем свойствам тени присваиваются значения, после чего на холсте вместе с тенью рисуется уже знакомый нам смайлик. Чтобы проиллюстрировать различные типы получаемых эффектов, в примере используются четыре набора инструкций, в каждом из которых применяется немного более сильное смещение, более высокая степень размытости и более желтый оттенок тени. Результат показан на рис. 10.5. Рис. 10.5. Прикрепление теней к изображениям
152 | Глава 10 Пример 10.5 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. image = new Image() image.src = 'smiley.png' image.onload = function() { context.shadowOffsetX = 4 context.shadowOffsetY = 4 context.shadowBlur = 4 context.shadowColor = '#000' context.drawImage(image, 10, 10, 140, 140) context.shadowOffsetX = 6 context.shadowOffsetY = 6 context.shadowBlur = 6 context.shadowColor = '#220' context.drawImage(image, 160, 10, 140, 140) context.shadowOffsetX = 8 context.shadowOffsetY = 8 context.shadowBlur = 8 context.shadowColor = '#440' context.drawImage(image, 310, 10, 140, 140) context.shadowOffsetX = 10 context.shadowOffsetY = 10 context.shadowBlur = 10 context.shadowColor = '#660' context.drawImage(image, 460, 10, 140, 140) } Давайте сначала рассмотрим в этом примере строки с 6 по 10. Здесь можно заметить, что все четыре свойства тени были установлены на весьма низкие значения, а затем с этими настройками в строке 10 задана отрисовка изображения. В каждом последующем наборе инструкций значения немного увеличиваются. Наверное, не вызывает сомнений, что самые удачные настройки применены для двух средних изображений. Иными словами, хорошие результаты получаются при задании для теней смещения примерно в 68 пикселей, и при задании весьма незначительного оттенка в сторону одного из основных цветов, от которого идет смещение, или же в сторону цвета фона позади рисунка. Это поможет тени выглядеть более реалистично. Но теперь, когда известен способ добавления теней, это уже вопрос вкуса, поскольку могут быть выбраны абсолютно любые предпочтительные настройки.
Работа с холстом | 153 Тени прикрепляются не только к изображениям Вообще-то, объект можно прикрепить не только к изображению, а практически ко всему, что рисуется на холсте. Рассмотрим в качестве иллюстрации пример 10.6, где рисуется затененный прямоугольник с тенью без смещения (показанный на рис. 10.6), а затем рисуется надпись с тремя строками текста, к которым прикреплены тени с различными смещениями. Рис. 10.6. Прикрепление теней к тексту и к линиям с использованием различных смещений Пример 10.6 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. context.shadowOffsetX = 0 context.shadowOffsetY = 0 context.shadowBlur = 10 context.shadowColor = '#000' context.strokeStyle = 'blue' context.lineWidth = 10 context.strokeRect(15, 15, 605, 285) context.fillStyle context.font = 'red' = '60pt Arial' context.fillText('Shadowed Text', 40, 190) context.shadowOffsetX = -5
154 15. 16. 17. 18. 19. 20. | Глава 10 context.shadowOffsetY = -5 context.fillText('Shadowed Text', 40, 100) context.shadowOffsetX = 5 context.shadowOffsetY = 5 context.fillText('Shadowed Text', 40, 280) Первая часть инструкций уже должна быть знакома. Задаются все свойства тени, затем толщина и цвет линии, после чего рисуется большой прямоугольник вместе с несмещенной тенью. А в остальных трех частях к строкам текста применяются разные тени, сначала смещенные вверх и влево, затем по центру и, наконец, со смещением вниз и вправо. Какие бы свойства теней не выбирались, они продолжают применяться до тех пор, пока не будут указаны новые или не закончатся все инструкции. А теперь самое время вспомнить о наших старых друзьях — функциях save() и restore(), которые в двух строках, помещаемых до и после использования теней (или же чего-либо еще, где потом требуется быстро и легко восстановить контекст до исходных значений), могут вызываться в контексте, позволяя быстро отключать тени, когда они больше не нужны: context.save() context.restore() Непосредственное редактирование пикселей Если углубленное изучение JavaScript не планируется или же преследуются вполне конкретные цели, достижимые с помощью холста HTML5, этот раздел, наверное, будет менее интересен. И все же для полноты картины необходимо рассмотреть все особенности холста, чтобы дать вам возможность быть во всеоружии. Если эта часть книги вызовет затруднения, можно пока ограничиться беглым просмотром, чтобы при возникновении потребностей в этих приемах работы с холстом можно было к ней вернуться, а в ходе просмотра можно будет, по крайней мере, понять, чего можно достичь при непосредственной работе с данными изображения. А теперь давайте посмотрим, как можно напрямую манипулировать данными, формирующими изображение на холсте, с помощью следующих трех новых функций: getImageData(), putImageData() и createImageData(), которые, как следует из их названий, позволяют читать, записывать и создавать данные изображения. Чтобы продемонстрировать все возможности, в примере 10.7 загружается фотография, отображаемая на холсте, а затем перебираются все данные изображения с усреднением установок красных, зеленых и синих компонентов цвета изображения с целью преобразования фотографии в монохромную, а затем, как показано на рис. 10.7, новые данные возвращаются на холст в его другую часть.
Работа с холстом Рис. 10.7. Левое изображение было преобразовано в монохромное и показано в правой части холста Пример 10.7 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. canvas = document.getElementById('canvas') context = canvas.getContext('2d') // Начало разбора кода примера в книге image = new Image() image.src = 'painting.png' image.onload = function() { context.drawImage(image, 0, 0) imagedata = context.getImageData(0, 0, 320, 320) width = 320 height = 320 ypos = 0 while (ypos < height) { xpos = 0 while (xpos < width) { colorpos = ypos * width * 4 + xpos * 4 | 155
156 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. | Глава 10 average = (imagedata.data[colorpos ] + imagedata.data[colorpos + 1] + imagedata.data[colorpos + 2]) / 3 // Эта строка намеренно оставлена пустой imagedata.data[colorpos ] = average imagedata.data[colorpos + 1] = average imagedata.data[colorpos + 2] = average xpos = xpos + 1 } ypos = ypos + 1 } context.putImageData(imagedata, 320, 0) } Да, пример несколько длиннее предыдущих, и в нем есть некоторые новые функции JavaScript, но вы уже готовы к этому, и следующее объяснение должно быть понятным, если в него вникать, изучая код примера. Результат выполнения этого кода можно увидеть на рис. 10.7. Строки с 1 по 6 должны быть уже хорошо знакомы. В них создается новый пустой объект изображения, а затем указывается, что в него должен быть загружен файл painting.png. Затем к объекту прикрепляется событие загрузки изображения onload, чтобы код между фигурными скобками в следующей безымянной функции выполнялся только после полной загрузки изображения в память. Первым делом следует обратить внимание на вызов функции getImageData(), которая запрашивает все данные изображения, начиная с позиции 0,0 с шириной и высотой 320 пикселей, для загрузки в объект с простым названием imagedata. Это будут данные, подвергаемые обработке. Далее присваиваются значения трем переменным: width и height получают значения ширины и высоты изображения в пикселях (оба 320), а переменной ypos присваивается значение 0. Эта переменная будет использоваться в качестве счетчика перемещений по строкам данных изображения. Она будет увеличиваться на 1 при каждой последующей обработке строки данных, пока не достигнет значения 320 (представляющего строку за нижней частью изображения), после чего она уже не будет использоваться, и выполнение кода завершится. Как хранятся данные о цвете Прежде чем рассматривать цикл while(), выполняющий эту обработку данных, сначала нужно понять, как данные изображения выкладываются в память. Не волнуй-
Работа с холстом | 157 тесь, здесь нет ничего сложного и непонятного. Цвета в изображении холста состоят из четырех различных значений, каждое из которых может находиться в диапазоне от 0 до 255 (или от 0x00 до 0xFF в шестнадцатеричной системе счисления, где также используются буквы от A до F, которые позволяют обозначить 16 цифр от 0 до F, необходимых для работы с числами по основанию 16). Эти четыре значения представляют количество красного, зеленого, синего компонентов и степень прозрачности цвета. В сочетании все они отображаются как цвет с любой установленной прозрачностью, что позволяет просвечивать в этой степени любые цвета в любых находящихся под изображением элементах. Пока прозрачность нас не интересует, но мы все равно вынуждены пропускать за раз все четыре значения, чтобы попадать на каждое новое значение цвета. Затем берутся только первые три значения, чтобы выявить красный, зеленый и синий компоненты этого цвета, а четвертое значение игнорируется. Последовательный перебор данных Теперь, выяснив все эти обстоятельства, можно вернуться к примеру, где в строке 13 вводится цикл while(), позволяющий выполнять содержимое, заключенное в фигурные скобки только в том случае, если значение ypos меньше, чем значение height. Эта проверка гарантирует продолжение обработки до тех пор, пока значение ypos не станет меньше значения height (составляющего высоту в 320 пикселей), что и будет причиной завершения обработки. Пока все хорошо. Есть возможность последовательно перебрать все строки данных изображения. Затем во время каждого прохода цикла ypos нужно обрабатывать каждую из строк, проходя каждый раз по четыре значения. Для этого создается новый счетчик циклов с именем xpos, который инициализируется значением 0 и готов ко входу во второй цикл, начинающийся со строки 21. Здесь уже содержимое цикла будет выполняться только до тех пор, пока xpos будет меньше ширины изображения, доходя до значения width (равного 320). Пока значение счетчика меньше, сердцевина обоих циклов будет доходить до выполнения кода в строке 23. Обработка данных изображения Все серьезные манипуляции с данными выполняются в строках с 23 по 33, но работа организована довольно просто, путем создания переменной с именем colorpos, указывающей на точное начало трех текущих компонентов цвета интересующего нас пикселя. Значение colorpos вычисляется перемножением значений ypos и width с целью получения числа, представляющего пиксель в начале текущей строки. То есть, если, к примеру, очередь дошла до начала 30 строки, а в каждой строке 320 пикселей, то просмотрено уже 9600 пикселей, и, следовательно, ypos, умноженное
158 | Глава 10 на width, будет равно 9600. Но следует помнить, что цвет каждого пикселя составлен из четырех элементов данных, поэтому, чтобы найти точную позицию в данных изображения для начала строки, это значение умножается на 4. В примере со строкой 30 это будет 30 × 320 × 4, или 38 400. Далее нужно знать, где мы находимся в текущей строке, поэтому следующим берется значение в xpos, которое с учетом четырех значений цвета на каждый пиксель также умножается на 4. Итак, если это 42 пикселя в строке, то 42 × 4 равняется 168. И наконец, чтобы узнать точное начало данных изображения, представляющих как строку, так и столбец, эти два результата складываются. В случае примера с местоположением 30, 42 весь расчет будет 20 × 320 × 4 + 42 × 4 или, как указано в строке 23: 23. colorpos = ypos * width * 4 + xpos * 4 Усреднение данных о цвете Теперь уже точно известно, где в объекте imagadata можно найти данные изображения для текущего пикселя, поэтому в строках с 24 по 27 извлекается каждое из трех значений в позициях colorpos, colorpos + 1 и colorpos + 2, затем они складываются, делятся на 3, чтобы получить среднее значение красного, зеленого и синего компонентов цвета, а результат помещается в переменную с именем average. Это делается с помощью квадратных скобок после ключевого слова data, которые сообщают JavaScript, что данные следует извлекать из данных изображения по заданным смещениям. А строка 29 остается пустой, чтобы вскоре вас можно было кое-чем позабавить. Затем в строках с 31 по 33 среднее значение возвращается в imagedata, заменяя три различных значения красного, зеленого и синего компонента одним и тем же средним значением, что означает, что цвет пикселя превращается в оттенок серого цвета. И наконец, нужно закрыть два цикла: как вложенный, так и основной. Это делается путем увеличения значения xpos на 1 для внутреннего цикла с его закрытием фигурной скобкой, а затем увеличения значения ypos на 1 для внешнего цикла, также с его закрытием фигурной скобкой. Эти увеличения значений на единицу происходят по завершении всех вычислений, когда либо внутренний цикл готов перейти к следующему пикселю (или вернуться к нулевому пикселю в строке), либо внешний цикл готов двигаться вниз по строке, либо, если он уже завершен и готов к выходу, чтобы передать выполнение последней команде примера, которая помещает измененные данные изображения на холст справа от исходного изображения. Другие эффекты Отлично! Если раньше пользоваться JavaScript не приходилось, то теперь из этой главы уже усвоено множество приемов программирования на этом языке. Надеюсь,
Работа с холстом | 159 можно согласиться с тем, что это не так уж и сложно, и фактически нет более простого способа, позволяющего достичь таких эффектов. Кроме того, может удивить и скорость работы кода. Загрузка, обработка и прорисовка нового монохромного изображения происходят мгновенно. Код примера можно оптимизировать разными способами, но он был преподнесен в простой и слегка избыточной форме, чтобы можно было показать, как все это работает. А теперь представьте, насколько быстрее он станет работать, если применить более эффективные приемы программирования. Все уже сказано и сделано, и теперь давайте немного развлечемся и, исходя из уже усвоенных знаний, слегка изменим эффект, добавив всего одну строку кода в именно для этого оставленную пустой строку 29. Первым делом инвертируем монохромное изображение, просто, как показано ниже, вычитая значение, полученное в переменной average, из ее максимального значения 255 (шестнадцатеричное 0xFF). 29. average = 0xFF – average // Инвертирование цветовых настроек Результат показан на рис. 10.8. Рис. 10.8. Изображение превращено в монохромное и инвертированное Давайте попробуем осветлить изображение, заменив код в строке 29 (такое использование оператора += — сокращение кода average = average + 0x50). 29. average += 0x50 // Осветление Результат должен быть таким, как на рис. 10.9.
160 | Глава 10 Рис. 10.9. Изображение превращено в монохромное и осветленное А теперь давайте заменим содержимое строк с 31 по 33 следующим кодом, чтобы увеличить красную и уменьшить синюю составляющую нового монохромного изображения, и посмотрим, приведет ли это к своеобразному оттенку сепии? 31. 32. 33. imagedata.data[colorpos ] = average + 0x50 imagedata.data[colorpos + 1] = average imagedata.data[colorpos + 2] = average – 0x50 Теперь результат выполнения кода примера должен выглядеть так, как показано на рис. 10.10. И для получения завершающего эффекта давайте добавим к изображению случайный шум, изменив эти строки кода следующим образом: 31. 32. 33. imagedata.data[colorpos ] = average + Math.random() * 0x80 imagedata.data[colorpos + 1] = average + Math.random() * 0x80 imagedata.data[colorpos + 2] = average + Math.random() * 0x80 Результат этих изменений должен выглядеть так, как показано на рис. 10.11. Здесь случайное значение в диапазоне от 0 до 0x80 (в десятичном исчислении — 128) было добавлено к каждому из красных, зеленых и синих цветовых компонентов в оттенках серого, для чего была использована функция random() из JavaScriptбиблиотеки Math. Эта функция возвращает значение с плавающей точкой в диапазоне от 0 до 1, поэтому при его умножении на любое значение возвращается число от 0 до 128. Понаблюдайте за происходящим при многократной перезагрузке примера. Всякий раз будет получен совершенно другой набор шумов, показывающий, что результат имеет по-настоящему случайную природу (на самом деле псевдослучайную, дос-
Работа с холстом | 161 тупную конкретному компьютеру без посторонней помощи). Попробуйте поэкспериментировать с содержимым строк с 29 по 33 и посмотреть, можно ли придумать свои собственные эффекты. Рис. 10.10. Создание тона сепии Рис. 10.11. Добавление к монохромному изображению случайного шума
162 | Глава 10 Создание собственных данных изображения Объект imagedata необязательно создавать непосредственно из содержимого холста, поскольку можно просто создать новый объект с пустыми данными, вызвав показанную ниже функцию createImageData(), которая словно из воздуха создает пустой объект шириной 320 и высотой 240 пикселей: imagedata = createImageData(320, 240) Кроме того, новый объект можно создать из любого уже существующего объекта: newimagedataobject = createImageData(imagedata) Затем уже вам решать, что сделать с этими объектами, добавляя к ним пиксельные данные, и как их нарисовать на холсте или создать из них другие объекты. Как бы то ни было, но это упражнение все же больше подходит для пользователей, более сведущих в программировании на JavaScript. Заключение Итак, вы почти что добрались до самого конца учебника по работе с холстом HTML5. Вы не только освоили все основные навыки, необходимые для получения максимальной отдачи от холста, но и, если вы еще не причисляли себя к программистам, работающим на JavaScript, то теперь можете уверенно считать, что достигли в этом деле уровня опытного новичка. В следующей главе после изучения таких дополнительных функций, как компоновка и прозрачность, вам предстоит превратиться в настоящего мастера работы с холстом.
ГЛАВА 11 Расширенные возможности работы с холстом Введение Наше последнее проникновение в сокровищницу функций, предлагаемых холстом HTML5, будет посвящено оставшимся более сложным эффектам, достигаемым с применением прозрачности, выбором типа композиции и использованием перемещений, преобразований, поворотов и масштабирования для получения наилучших результатов. Рассмотрение местами будет принимать в некотором смысле чисто технический оборот, но при этом не слишком сильно отходя от использования новой графической программы, разве что в этих отступлениях станут известны новые функции, которые можно будет вызывать из кода JavaScript. Самое главное, здесь можно будет ясно понять, как при использовании сочетаний из всех функций холста можно добиться практически любого желаемого результата, и что, даже не имея особых художественных талантов, можно за счет четко запрограммированной графики достичь поразительных эффектов. Структура В этой главе рассматриваются следующие темы:  Получение сведений о выстраивании композиций и прозрачности и порядке их совместной работы.  Освоение двенадцати новых разнообразных способов рисования на холсте.  Приобретение навыков применения еще нескольких функций JavaScript.  Освоение приемов манипуляции изображениями с помощью поворотов и других преобразований. Цели Изучение предлагаемого материала завершит обучение работе с холстом HTML5. Вы станете специалистом по применению большинства его самых распространен-
164 | Глава 11 ных функций и узнаете о возможностях, открываемых его наиболее совершенными функциями. Также вы пополните знания о циклах и структурах данных и об управлении объектной моделью документа (DOM) из сценариев JavaScript. Выстраивание композиции и прозрачность Здесь предстоит рассмотреть множество вопросов, в которых по большей части используется выстраивание композиции и прозрачность, поэтому именно с них лучше всего и начать изучение. И не стоит забывать, что при внесении в контекст холста серьезных изменений для быстрого возврата к предыдущему состоянию больше всего подходит применение функций save() и restore(). Возможно, вас заинтересует, что именно подразумевается под понятием выстраивания композиции. Это способ описания порядка размещения элементов рисунка на холсте. Например, должен ли элемент выходить на первый план, или же появляться за уже существующим объектом и т. д. Чтобы управлять выстраиванием композиции, можно воспользоваться свойством globalCompositeOperation, позволяющим полностью изменить способ рисования объекта в зависимости от переданного этому свойству значения. По умолчанию для этого свойства используется значение source-over, которое просто предписывает JavaScript перезаписать все, что уже находится на холсте, а вообще существует целых двенадцать возможных значений этого свойства, поэтому их, наверное, лучше представить вам в виде списка:  source-over: Как уже упоминалось, это значение по умолчанию. Исходное изо- бражение копируется поверх целевого, иными словами, все, что находится под объектом, перезаписывается.  source-in: Видны только части исходного изображения, которые будут появ- ляться в целевом изображении, а само оно удаляется. Любая альфа-прозрачность в исходном изображении приводит к удалению целевого объекта под ним.  source-out: Видны только те части исходного изображения, которые не появля- ются в целевом изображении, а само оно удаляется. Любая альфа-прозрачность в исходном изображении приводит к удалению целевого объекта под ним.  source-atop: Исходное изображение видно там, где оно перекрывает целевое. Целевое изображение видимо там, где оно непрозрачно, а исходное наоборот. Остальные области прозрачны.  destination-over: Исходное изображение рисуется под целевым изображением.  destination-in: Целевое изображение видно в местах перекрытия исходного и целевого изображений, но не в областях прозрачности исходного изображения. Исходное не отображается.  destination-out: Видны только те части целевого изображения, которые находят- ся за пределами непрозрачных областей исходного. Исходное изображение не отображается.
Расширенные возможности работы с холстом | 165  destination-atop: Исходное изображение видно там, где не отображается целе- вое. Там, где целевое и исходное изображения перекрываются, показывается целевое изображение. Любая прозрачность в исходном изображении предотвращает отображение этой области целевого изображения.  Lighter: Сумма исходного и целевого изображений применяется таким образом, что там, где они не перекрываются, они видны как обычно, а там, где перекрываются, отображается сумма обоих изображений, но с осветлением.  Darker: Сумма исходного и целевого изображения применяется таким образом, что там, где они не перекрываются, они видны как обычно, а там, где перекрываются, отображается сумма обоих изображений, но с затемнением.  Copy: Исходное изображение копируется поверх целевого. Любая прозрачная область исходного изображения приводит к тому, что любая перекрытая им область целевого изображения не отображается.  Xor: Там, где исходное и целевое изображение не перекрываются, они отобра- жаются как обычно. Там, где они перекрываются, их цветовые значения подвергаются операции XOR (Исключающего «ИЛИ»). Теперь разобраться с композицией может быть не так-то и просто, поэтому давайте обратимся к примеру 11.1, в котором в качестве исходного изображения, нарисованного поверх закрашенных кругов двенадцатью различными способами, используется круглая картинка земного шара с прозрачным фоном, показанная на рис. 11.1, и создадим документ для проверки всех этих свойств, чтобы посмотреть на полученные результаты. Рис. 11.1. Изображение земного шара для использования с выстраиванием композиций Пример 11.1 1. 2. 3. 4. 5. 6. 7. <!DOCTYPE html> <html> <head> <title>Compositing Examples</title> </head> <body> <script>
166 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. | Глава 11 image = new Image() image.src = 'globe.png' types = ['source-over', 'source-out', 'destination-over', 'destination-out', 'lighter', 'copy', image.onload = function() { for (j = 0 ; j < 12 ; ++j) { canvas = canvas.width = canvas.height = canvas.style.background = canvas.style.margin = context = 'source-in', 'source-atop', 'destination-in', 'destination-atop', 'darker', 'xor'] document.createElement('canvas') 120 120 '#ddd' '5px' canvas.getContext('2d') context.arc(50, 50, 50, 0, Math.PI * 2) context.fillStyle = 'orange' context.fill() context.globalCompositeOperation = types[j] context.drawImage(image, 20, 20, 100, 100) document.body.appendChild(canvas) } } </script> </body> </html> Этот пример немного отличается от примеров из предыдущих глав тем, что при использовании атрибут globalCompositeOperation применяется ко всему холсту, и поэтому для отображения всех двенадцати различных значений атрибута необходимо создать двенадцать независимых холстов. И чтобы укоротить код, использовано несколько более совершенных методов JavaScript. В данном конкретном случае пример показан целиком. Давайте разберем программу, начиная со строк с 1 по 6, являющихся стандартными для HTML-документа. Стало быть, разбору подлежит только содержимое между тегами сценария в строках с 8 по 36. Строки 8 и 9 узнаваемы, поскольку это уже известные инструкции по загрузке изображения. В данном случае используется изображение из файла globe.png. Далее в
Расширенные возможности работы с холстом | 167 строках с 10 по 15 есть кое-что совершенно новое. В них показано сохранение всех возможных имен значений атрибутов в так называемом массиве. Массив похож на пачку переменных, ссылки на которые идут по порядку номеров. К примеру, в types[0] содержится значение source-over, а в types[11] — xor, а все остальные значения содержатся в элементах от types[1] до types[10]. Порядок использования массива будет показан ниже. Строки 17 и 18 также известны из предыдущих примеров. В них просто создается безымянная функция, позволяющая запускать код внутри фигурных скобок только после того, как наступит событие загрузки изображения, означающее, что изображение загружено в память в полном объеме. Использование цикла В строках с 19 по 35 содержится новая функция, впервые представляемая в данной книге — цикл иного рода под названием for(). Он похож на циклы while() из предыдущих глав, но более лаконичен, поскольку принимает три аргумента, позволяющих настроить счетчик цикла, используемый в качестве первого аргумента. В данном случае в качестве счетчика используется переменная j с начальным значением 0. Затем циклу указывается условие, при котором он может быть выполнен, в данном случае, если j имеет значение меньше 12 (поскольку существует 12 типов применяемых атрибутов композиции). И наконец, циклу указывается, что делать после каждой итерации. В данном случае циклу предписывается увеличить переменную j на 1, используя краткую форму оператора в виде сочетания символов ++, т. е. записи ++j и j = j + 1 — это одно и то же, но первая выбрана для краткости. Теперь, после захода в цикл в строке 21, показанные в нем инструкции будут выполняться в общей сложности 12 раз со значениями j от 0 до 11. Первом делом при каждом проходе цикла с помощью функции document.createElement() будет создаваться новый объект холста, называемый просто canvas. Это куда проще создания двенадцати различных холстов в HTML-документе, поскольку все можно сделать, как говорится, «на лету», в JavaScript. Затем в строках 22 и 23 задаются ширина и высота нового объекта холста, после чего в строках 24 и 25 применяется цветовая стилизация CSS, представленная значением #ddd для фона холста, и задается отступ в 5 пикселей. Теперь в строке 26 можно из холста создать контекст, как это делалось во многих недавних примерах. Рисование изображения Далее, в строках с 28 по 30, на текущем холсте рисуется закрашенный оранжевый круг, который будет объектом, поверх которого рисуется изображение земного шара
168 | Глава 11 с использованием текущего выстраивания композиции. Для этого в строке 32 из массива типов, в соответствии с ранее изложенными описаниями, извлекается текущее имя атрибута композиции, которое присваивается атрибуту globalCompositeOperation. Теперь все готово к тому, чтобы в строке 33 выполнить рисунок на холсте с использованием текущей настройки композиции, а затем завершить текущий проход цикла. В строке 34 помощью вызова функции appendChild() только что созданный новый холст присоединяется к телу текущего документа. Надеюсь, все понятно, и вам удалось существенно пополнить свои знания JavaScript (если все это еще не было известно). А теперь давайте посмотрим на результат выполнения этого кода на рис. 11.2, где показаны в действии все 12 типов композиции в том порядке, что был указан в массиве в строке 10 примера. Рис. 11.2. Демонстрация 12 возможных атрибутов композиции в действии Как видите, все эти значения атрибута, предлагающие весьма интересные эффекты, позволяют воспользоваться множеством способов рисования на холсте. Если интересно, попробуйте изменить пример, используя различные типы исходных и целевых изображений, особое внимание уделив применению различных форм и цветовых настроек, чтобы расширить свое представление о возможностях выстраивания композиций. Изменение прозрачности При рисовании на холсте вы можете выбрать точную настройку желаемой степени прозрачности, указав для принадлежащего контексту свойства globalAlpha значение от 0 до 1. Давайте, к примеру, изменим оставленную пустой строку 27, записав в нее следующий код: 27. context.globalAlpha = 0.5
Расширенные возможности работы с холстом | 169 Значение 0.0 означает отсутствие прозрачности, а значение 1.0 указывает, что должна применяться сплошная прозрачность. Следовательно, введенное выше значение 0.5 устанавливает полупрозрачность, а результат показан на рис. 11.3, где вам, возможно, будет легче понять суть эффектов выстраивания различных композиций, поскольку они применяются всего лишь наполовину, и любые части изображения, которые были бы стерты, стираются лишь наполовину. Рис. 11.3. Эффекты выстраивания композиции становятся более понятными, если вдобавок к ним применяется прозрачность Применение преобразований При рисовании на холсте HTML5 с целью изменения способа рисования можно применять три преобразования: масштабирование, поворот и перемещение. Давайте рассмотрим по очереди каждый из них. В примере 11.2 ромбовидная фигура семь раз рисуется в цикле, где меняется только цвет и используется значение масштабирования, что приводит к результату, показанному на рис. 11.4. Пример 11.2 1. 2. 3. 4. 5. 6. 7. 8. 9. colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'] for (j = 0 ; j < 7 ; ++j) { context.save() context.beginPath() context.scale(1 + j, 1 + j)
170 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. | Глава 11 context.moveTo( 0, 40) context.lineTo(40, 0) context.lineTo(80, 40) context.lineTo(40, 80) context.lineTo( 0, 40) context.fillStyle = colors[j] context.fill() context.restore() } В этом примере опять же показан только основной код JavaScript (опущен даже тот фрагмент JavaScript, который создает объект контекста context), при этом полный HTML-документ доступен на прилагаемом к книге веб-сайте, а все, что не показано в примере, такое же, как в примерах из предыдущих глав. Что происходит в строке 1, уже не должно вызывать вопросов. В ней создается массив под названием colors, элементам которого присваиваются по порядку семь цветов радуги. Затем в строке 4 вводится цикл for() для перебора семи значений j (от 0 до 6). В строке 6 путем вызова функции save() сохраняются все свойства контекста, чтобы позднее их можно было восстановить (возвратив любые настройки масштабирования к исходному значению). Затем в строке 7 создается новый путь, а в строке 9 как к горизонтальным, так и к вертикальным координатам, предоставляемым с этого момента через вызов функции scale(), применяется значение масштабирования 1 + j. Когда j имеет значение 0, выражение вычисляется в 1, и для масштабирования устанавливается нормальное отношение один к одному в обоих измерениях. Но когда j увеличивается до 1, то 1 + 1 имеет значение 2. Затем 1 + 2 вычисляется в 3, и масштаб растет до 1 + 6, что равно 7. Таким образом, цикл создает эффект увеличения значений масштабирования с 1 до 7. Затем в строках с 11 по 15 создается путь, необходимый для рисования ромба, после чего в строке 16 к свойству fillStyle применяется один из имеющихся в массиве цветов, а в строке 17 выполняется заливка ромба. И наконец, в строке 18 вызывается функция restore(), возвращающая коэффициент масштабирования к исходному значению. Если этого не сделать, текущее масштабирование останется неизменным для следующего прохода цикла, после чего будет выполнен прирост коэффициента масштабирования, и так при каждом проходе, приводя к экспоненциальному увеличению масштаба. На рис. 11.4 видно, что ромбы нарисованы друг над другом, и с каждой итерацией размеры ромба становятся больше, хотя координаты, указанные в строках с 11 по 15, не меняются, в отличие от коэффициента масштабирования.
Расширенные возможности работы с холстом | 171 Получается, что при рисовании на холсте можно создавать пути и фигуры одного размера, а затем масштабировать их до любой желаемой величины. Рис. 11.4. Фигура одного и того же размера, увеличенная в несколько раз Просто не нужно забывать, что при желании восстановить масштабирование или изменить его для возвращения к предыдущим настройкам лучше воспользоваться вызовами функций save() и restore(). Не забудьте также, что эти две функции сохраняют и восстанавливают все свойства контекста: от стилей заливки и прозрачности до толщины линий, теней, выравнивания текста, преобразований и многого другого. Использование поворотов Лучше всего проследить эффект поворотов путем применения их к уже имеющемуся примеру, поэтому давайте создадим пример 11.3, изменив строку 10 примера 11.2, и добавив в нее значение поворота: Пример 11.3 (показана только измененная строка): 10. context.rotate(j / 7) В результате будет получен эффект поворота рисунка объекта на небольшую величину при каждом проходе цикла, показанный на рис. 11.5.
172 | Глава 11 Поскольку радиан имеет значение 180/PI, или около 57 градусов, фактическая используемая здесь величина поворота представляет собой число от 0 до 6 радиан, поделенное на 7. Разделив радианы на 7, можно получить поворот каждой новой формы при каждом проходе цикла на чуть более чем на 8 дополнительных градусов. Рис. 11.5. Многократное масштабирование и поворот объекта Применение перемещений Очевидная проблема при выполнении кода примера 11.3 — исчезновение части фигуры, подвергаемой вращению, за левой границей экрана. Поэтому давайте добавим к каждой итерации перемещение, вставив в строку 8 примера 11.3, превращая его в код примера 11.4, следующую инструкцию: Пример 11.4 (показана только измененная строка): 8. context.translate(j * 40, 0) Как при задании масштабирования, перемещение принимает два аргумента, представляющие собой величину в пикселях, на которую выполняется перемещение как в горизонтальном, так и в вертикальном направлении. В данном случае, чтобы вернуть большие ромбы обратно на холст, требуется только перемещение по горизонтали, и при каждом проходе цикла это делается всего лишь на 40 дополнительных пикселей (j * 40). Результат добавления этой инструкции показан на рис. 11.6.
Расширенные возможности работы с холстом | 173 Рис. 11.6. Объекты все больше масштабируются, перемещаются и вращаются Применение сразу нескольких преобразований Можно получить весьма странные и удивительные результаты, используя одну или обе функции transform() и setTransform(), но их применение основано на матрицах преобразования размером 3 × 3, где содержатся различные параметры, на рассмотрение которых уйдет слишком много времени, и поэтому оно не вписывается в формат этой книги. Но заинтересованный читатель сможет найти довольно много дополнительной информации на сайте tinyurl.com/canvastransforms. Заключение Дело сделано! Теперь вам известно все, что нужно знать об использовании холста HTML5. Да, есть целый ряд еще не полностью раскрытых более сложных способов работы с холстом, но основную часть из того, что они позволяют сделать, можно реализовать (хотя и более пространно) с использованием уже освоенных вами функций. Теперь настало время продолжить изучение всей инфраструктуры HTML5, перейдя в следующей главе к изучению геолокации.
ГЛАВА 12 Применение геолокации Введение С невероятным ростом популярности смартфонов возможность определения местоположения устройства стала практически обязательной, особенно для запуска интерактивных карт, работы навигационного программного обеспечения и даже для поиска локальных точек доступа Wi-Fi или мест предоставления разных услуг: ресторанов, пунктов выдачи наличных, проката машин и т. д. Геолокация также все шире используется в попытках предоставления платных услуг, выражающихся в предложениях принять участие в рекламных акциях находящихся поблизости магазинов, и в чуть более приятных делах, позволяя узнать, есть ли поблизости друзья или знакомые. К счастью, разрешение на раскрытие информации о своем местоположении можно контролировать, поэтому любые риски конфиденциальности или безопасности, которые может повлечь за собой применение той или иной технологии, можно свести к минимуму. Здесь рассматриваются приемы использования JavaScript для определения местоположения любого устройства с поддержкой геолокации, если пользователь разрешает это и браузер поддерживает эту функцию. В случае успеха будут предоставлены долгота и широта местонахождения пользователя в виде максимально точной, в соответствии с возможностями браузера, пары координат (обычно на мобильном устройстве это делается через спутниковый чип GPS). Структура В этой главе рассматриваются следующие темы:  Что такое геолокация, предоставляемая GPS или другими средствами.  Способы проверки, поддерживает ли браузер пользователя геолокацию.  Управление блокировкой пользователей и согласием на предоставление их ме- стонахождения.  Преобразование местонахождения пользователя в широту и долготу с целью отображения его на карте.
176 | Глава 12 Цели Здесь предстоит изучить все тонкости геолокации HTML5, узнать о ее составляющих, об извлечении пользы от ее применения в различных обстоятельствах и даже освоить способы преодоления любых ошибок, с которыми можно столкнуться при ее применении. Изучение материалов главы позволит полностью освоить геолокацию и получать точные координаты широты и долготы местонахождения пользователя в том случае, если к ним будет открыт доступ. Что такое GPS Служба спутникового глобального позиционирования (Global Positioning Satellite, GPS) состоит из нескольких спутников, вращающихся вокруг Земли, положение которых определено с весьма высокой точностью. Когда устройства с поддержкой GPS настраиваются на эти спутники, разница во времени поступления сигналов от разных спутников позволяет устройству узнать его местоположение с точностью до нескольких метров. При этом используется тот факт, что скорость света (и радиоволн) — известная постоянная величина, а время, необходимое сигналу, чтобы добраться от спутника до устройства GPS, точно указывает на расстояние до спутника. При записи разного времени поступления сигналов от разных спутников простой расчет позволяет устройству определить положение каждого спутника относительно друг друга и, следовательно, очень точно произвести триангуляционные вычисления положения устройства относительно них. Многие мобильные устройства, включая телефоны и планшеты, имеют чипы GPS и могут предоставлять эту информацию пользователям. Но у некоторых устройств их нет, у других они отключены, а третьи могут использоваться в помещении, где не проходит сигнал от спутников GPS. В таких случаях для попытки определения местоположения устройства могут использоваться дополнительные методы. Альтернативы применению GPS Если в устройстве присутствует оборудование для мобильной связи, но отсутствует GPS (что маловероятно) или же GPS отключен, оно может попробовать провести триангуляционные вычисления своего местоположения, проверив синхронизацию сигналов, полученных от различных вышек мобильной связи, с которыми оно может связываться (и чьи позиции известны с высокой точностью). При наличии нескольких вышек местоположение может быть вычислено с точностью, почти не уступающей точности GPS. Но если привязка возможно только к одной вышке, для определения радиуса окружности, в очерчиваемой области которой, вероятно, и находится устройство,
Применение геолокации | 177 можно использовать силу сигнала. То есть данные могут указывать на любую точку на удалении от 1,5–3 км и до нескольких десятков метров от фактического местоположения. Если нет и такой возможности, в радиусе действия вашего устройства могут быть точки доступа Wi-Fi с известным местоположением, а, поскольку все точки доступа имеют уникальный идентификационный адрес, называемый адресом управления доступом к среде (Media Access Control, MAC), местоположение может быть достаточно точно определено в пределах одной или двух улиц. И если этот способ будет недоступен, можно запросить адрес интернет-протокола (IP), используемого вашим устройством, который затем можно использовать в качестве приблизительного индикатора вашего местоположения. Но зачастую это дает только местоположение основного коммутатора, принадлежащего вашему интернет-провайдеру, который может находиться в десятках или даже сотнях километров от вас. Но, по крайней мере, ваш IP-адрес позволяет (как правило) уточнить страну, а иногда и регион нахождения, предоставляя возможность подобраться к вашему местоположению как можно ближе через главный узел провайдера, чего обычно вполне достаточно для решения большинства задач. П РИМЕЧАНИЕ Ваш IP-адрес обычно используется медиакомпаниями, ограничивающими воспроизведение своего контента на той или иной территории. Но можно настроить прокси-серверы, использующие IP-адрес пересылки в той стране, которая блокирует свой контент, чтобы получать и передавать контент, минуя блокировку, непосредственно в используемый вами браузер. Поэтому следует понимать, что поиск кого-то по IP-адресу не дает 100%-ной уверенности правильного определения его страны пребывания. Проверка доступности геолокации Из предыдущих глав уже известно, что возможности HTML5 иногда настолько расширены, что к ним нельзя получить доступ с помощью простого HTML, поэтому, чтобы воспользоваться ими, не говоря уже об эффективных способах работы с ними, требуется определенное знание языка JavaScript. Мало знакомые с программированием на JavaScript люди смогут на примерах главы расширить познания в этом языке. Постепенно приемы вырезания и вставки фрагментов кода из примеров войдут в привычку, и они перестанут быть для вас некими заранее упакованными частями кода, вы досконально разберетесь в их назначении и использовании и сможете создавать свои собственные процедуры для доступа к различным функциям наиболее удобными для вас и всецело подходящими для ваших проектов способами.
178 | Глава 12 Итак, давайте прямо сейчас приступим к работе с кодом примера 12.1, который просто определяет, поддерживает ли ваш браузер геолокацию, выдавая всплывающее сообщение с помощью функции alert(). Пример 12.1 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Testing for Geolocation</title> </head> <body> <script> // Начало разбора кода примера в книге if (typeof navigator.geolocation == 'undefined') { alert("Извините, геолокация не поддерживается".) } else { alert("Отлично, геолокация поддерживается".) } // Конец разбора кода примера в книге </script> </body> </html> В этом примере холст не используется, поэтому код немного короче примеров из предыдущих глав и приведен в полном объеме. Далее по главе в примерах будут показаны только строки, находящиеся между комментариями (здесь они в строках 9 и 18). Надеюсь, основная часть кода вопросов не вызывает, остается только объяснить содержимое строк с 10 по 17. Здесь проводится проверка свойства navigator.geolocation, которое должно быть у всех браузеров, поддерживающих геолокацию. Если выяснится, что оно не определено, значит, его не существует, равно как и функции геолокации. В наше время функция геолокации поддерживается практически всеми браузерами, но пожертвовав парой дополнительных строк кода, можно предупредить пользователей вашего веб-сайта, запускающих его на устаревшем браузере, о том, что эта функция на нем недоступна. Оповещение — информирование пользователя о наличии или отсутствии функции геолокации в небольшом всплывающем окне с текстом. Оно проводится путем вызова функции alert(), приостанавливающей выполнение сценария, пока пользователь не щелкнет на кнопке OK (или, в случае мобильного браузера, не коснется ее изображения).
Применение геолокации | 179 Для проверки используется инструкция if() с выражением внутри скобок, вычисление которого в true приводит к выполнению инструкций, заключенных в фигурные скобки. Проверка отсутствия свойства navigator.geolocation может привести только к результату true или false. Если получен результат true, выполнение кода в строке 12 приводит к отображению оповещения об отсутствии поддержки геолокации. Затем следует инструкция else, для которой, как и следовало ожидать, размещаются инструкции, выполняемые при вычислении условной инструкции в false. В этом случае будет выполнен любой код внутри ее фигурных скобок. На рис. 12.1 показан браузер, поддерживающий геолокацию, поэтому выражение вычисляется в false, и, следовательно, выполняется код строки 16, выводящий второе окно оповещения об успешном проведении проверки. Рис. 12.1. Этот браузер поддерживает геолокацию, о чем свидетельствует появление всплывающего окна с оповещением об успешном завершении проверки Использование консоли разработчика Для тестирования кода разработчикам лучше воспользоваться не окнами оповещения, а отправкой сообщений в консоль разработчика JavaScript. Тогда не будет никаких отвлекающих всплывающих окон, а информацию можно будет просто увидеть в консоли. Так, например, вместо показа двух оповещений в примере 12.1 в ходе разработки результат выполнения следующего кода мог бы выглядеть, как на рис. 12.2. if (typeof navigator.geolocation == 'undefined') { console.log("Извините, геолокация не поддерживается".) } else { console.log("Отлично, геолокация поддерживается".) } Более подробные сведения о настройке и использовании консоли разработчика приведены в главе 3 «Visual Studio Code». Теперь уже можно убедиться и в том,
180 | Глава 12 насколько полезна консоль не только для пошагового просмотра и изучения документов и их стилей, но и для получения в ходе разработки сообщений, не мешающих запуску тестируемого кода. Рис. 12.2. Сообщение отображается в консоли разработчика Перенаправление пользователей Если код определяет, что браузер не поддерживает геолокацию, то, наверное, захочется сделать нечто большее, чем просто вывести окно с оповещением (от которого фактически мало толку) или отправить сообщение в консоль разработчика. По всей видимости, лучше было бы направить пользователя на другую вебстраницу, где для него есть более подходящее содержимое. Это делается простым указанием нового URL-адреса в настройках местоположения браузера. Соответствующие действия показаны в примере 12.2, где приводится только та часть документа, которая связана с применением JavaScript. Пример 12.2 1. 2. 3. 4. if (true == true) { window.location = 'http://google.com' } Чтобы обеспечить постоянную работу примера, вместо прежней инструкции проверки условия применена новая, которая всегда будет возвращать значение true, поскольку true всегда равно true. Если же оставить проверку на поддержку геолокации, перенаправление по URL-адресу (в строке 3) можно будет протестировать только в браузерах без геолокации. Как показано на рис. 12.3, результатом выполнения кода примера станет немедленное перенаправление пользователя на веб-сайт Google.
Применение геолокации | 181 Рис. 12.3. Пользователь с помощью JavaScript был перенаправлен на другой URL-адрес Разумеется, на вашем собственном веб-сайте инструкция проверки наличия функции геолокации в браузере будет настоящей, а URL-адрес, на который вы отправляете пользователей браузеров без геолокации, будет созданным заранее по вашему выбору. Рис. 12.4. Стандартная заготовка страницы для случаев отсутствия геолокации Возможно, после перенаправления по этому новому URL-адресу пользователь получит предложение ввести в веб-форму свое местоположение, которым затем можно было бы воспользоваться с соответствующей базой данных, чтобы вернуть на-
182 | Глава 12 вигационные данные в виде пары координат долготы и широты наподобие того, как это сделала бы функция геолокации, если бы ее поддерживал браузер. Здесь вопрос создания страницы с таким кодом рассматриваться не будет, но ее заготовка, выводящая сообщение, показанное на рис. 12.4, содержится в прилагаемом к книге архиве примеров в файле по имени no_geo.html. При желании в качестве дополнительного упражнения можете сделать эту страницу намного полезнее. Тогда вам понадобится веб-форма, возвращающая информацию о местоположении, которую пользователь готов вам предоставить. Получение сведений о местоположении пользователя Вместо кода секции else, ранее показанного в примере 12.1 и выполняющегося при наличии поддержки геолокации, теперь нужно разместить код, который будет гораздо полезнее простого вывода окна оповещения. Для начала нужно запросить у браузера текущее местоположение пользователя. Если пользователь наложил ограничения, ему придется отвечать либо Да, либо Нет, решая, нужно вашей странице предоставлять эту информацию или нет. Поэтому следует предусмотреть возможность реагирования по двум вариантам.  Если пользователь дает разрешение, вам нужно что-то сделать с возвращенным местоположением или…  Если в доступе отказано, то пользователя можно было бы отправить по URL- адресу, заготовленному на случай отсутствия в браузере поддержки геолокации. Затем на той странице, куда был перенаправлен пользователь, он может самостоятельно ввести произвольное местоположение, или же получить возможность ничего не вводить и заняться чем-то другим, не зависящим от информации о местоположении. При вызове сервиса геолокации есть весьма удобный способ перенаправления, предусматривающий применение двух именованных функций JavaScript. Первая из них будет вызываться, если пользователь предоставит доступ, а вторая — если доступ отклонен. Эта функция сервиса называется getCurrentPosition(), а программа для ее использования может выглядеть примерно так, как показано в примере 12.3, где теперь в строках с 1 по 5 сценарий конкретно разбирается с тем, поддерживает браузер геолокацию или нет. Пример 12.3 1. 2. 3. 4. 5. 6. if (typeof navigator.geolocation == 'undefined') { console.log('Геолокация отсутствует') window.location = 'no_geo.html' } else
Применение геолокации 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. | 183 { navigator.geolocation.getCurrentPosition(granted, denied) function denied(error) { switch(error.code) { case 1: message = 'В разрешении было отказано'; break case 2: message = 'Позиционирование недоступно'; break case 3: message = 'Превышено допустимое время ожидания'; break case 4: message = 'Неизвестная ошибка' } console.log("Ошибка геолокации: " + message) window.location = 'no_geo.html' } function granted(position) { console.log('Геолокация разрешена') // Сюда помещается все, что нужно сделать } } При этом на консоль отправляется сообщение о том, что произошло, а затем местоположение страницы меняется на веб-страницу, ранее показанную на рис. 12.4, сохраненную в файле no_geo.html, который приводится здесь просто для иллюстрации, чтобы указать пункт назначения для примера. В примере выше в строке 8 у браузера запрашивается разрешение на получение сведений о его местоположении. Чтобы протестировать код в ситуации возможного предшествующего запуска примера, получения разрешения и его сохранения, браузер, как показано на рис. 12.5, был переведен в режим инкогнито (режим, поддерживаемый всеми браузерами, в котором все файлы cookie и другая идентифицирующая информация скрыта), что позволяет увидеть запрос на определение вашего местоположения. Если пользователь решает заблокировать геолокацию, то выполняется код функции с именем denied(). Функции уже встречались в главах, посвященных холсту, но там речь шла о безымянных функциях, потому что они запускались в месте своего определения, и присваивать им имена не имело смысла. А в строке 8 возникает необходимость знать о тех двух местах, куда должно передаваться управление сценарием в зависимости от решения пользователя заблокировать или же принять геолокацию, поэтому теперь используются функции, которым даются имена, позволяющие указать их в этой инструкции.
184 | Глава 12 Рис. 12.5. Браузер запрашивает у пользователя разрешение на раскрытие своего местоположения Именованные функции Наличие имен позволяет размещать такие функции практически в любом месте кода, поскольку интерпретатор JavaScript всегда сможет их найти. Но, чтобы не усложнять ситуацию и облегчить чтение кода при его сопровождении, такие функции лучше размещать рядом с вызывающим их кодом. Поэтому определение функции denied() находится в строке 10, сразу же за строкой ее вызова. В эту функцию включена новая (для этой книги) конструкция JavaScript по имени switch(). Это весьма компактный и понятный способ проверить значение, а затем выполнить соответствующие ему те или иные действия. В данном случае проверяемое значение представляет собой объект по имени error, который был отправлен функции JavaScript, чтобы точно сообщить ей о причине ее вызова. Объект ошибки error имеет свойство по имени code, у которого, как указано в строках с 14 по 17, может быть значение в диапазоне от 1 до 4, где значение code равное 1 гласит, что в разрешении было отказано, 2 — что позиция была недоступна, 3 — что операция превысила допустимое время ожидания и 4 — что причина ошибки неизвестна. В конце строк с 14 по 16 стоят ключевые слова break (после точки с запятой, разделяющей инструкции), сообщающие JavaScript, что далее в конструкции switch для него нет ничего интересного, и из нее нужно выходить с переходом на строку ниже. А в строке 17 ключевое слово break ставить не нужно, поскольку далее выполнение сценария может продолжаться только в следующей строке, находящейся ниже всей конструкции. И наконец, в строке 20 этой функции на консоль отправляется сообщение об ошибке, чтобы поспособствовать отладке, и, поскольку больше здесь делать нечего, код в строке 21 отправляет браузер на URL-адрес no_geo.html, где, надеюсь, ситуация может проясниться, предоставив пользователю подсказку о его дальнейших действиях.
Применение геолокации | 185 Когда получено разрешение Если же выполнение сценария дойдет до функции, объявленной в строке 24, стало быть, разрешение было дано, и вся необходимая информация содержится в объекте, переданном под именем position. И здесь пример заканчивается отправкой на консоль сообщения и комментарием в строке 28, напоминающим о необходимости предоставления дополнительного кода! Можно решить эту задачу, обновив код до примера 12.4, в котором показано только содержимое функции granted, поскольку остальная часть примера идентична коду примеру 12.3. Пример 12.4 (только код функции granted) 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. function granted(position) { console.log('Geolocation granted') lat = position.coords.latitude lon = position.coords.longitude map = "https://www.google.com/maps/@" window.location = map + lat + "," + lon + ",8z" } Результат выполнения этого примера для условного пользователя из Нью-Дели будет выглядеть, как показано на рис. 12.6. Как уже говорилось, код в строке 3 отправляет сообщение на консоль в целях облегчения отладки, но для уже готового кода он будет не нужен. Затем в строках 5 и 6 путем считывания значений из принадлежащих объекту position свойств coords.latitude и coords.logitude из него извлекаются данные, которые помещаются в переменные let и lon. Фактически в этом нет особой необходимости, поскольку этими свойствами можно воспользоваться непосредственно в строке 9, но лаконичность и разборчивость кода — достойная цель, особенно для новичка. А использование этих имен временных переменных делает строку 9 короче и понятнее. Можно также обойтись и без кода в строке 7, поскольку строковое значение, присваиваемое переменной map, также может быть передано непосредственно в строке 9. Но теперь, используя эти сокращенные имена переменных при анализе содержимого строки 9, будет гораздо проще дать точное описание всему, что в ней происходит. И наконец, в строке 9 встретится уже знакомое присваивание значения объекту window.location, поскольку именно это делалось при отправке пользователя на страницу no_geo.html. А здесь, по сути, происходит то же самое, но теперь уже пользователь отправляется на сайт Google Maps, а к URL-адресу для карты добавляется (через запятую) широта и долгота. И последнее значение, 8z, сообщает Google Maps степень
186 | Глава 12 увеличения масштаба. Чем меньше это число, тем меньше будет увеличение, поэтому для получения других результатов с числом можно поэкспериментировать. Рис. 12.6. Создание с помощью геолокации локального URL-адреса Google Maps Применительно к строковым значениям JavaScript-оператор + приводит к объединению строк, так что, к примеру, 'geo' + 'location' и 'geolocation' — это одно и то же. Именно так создается и присваивается полноценная строка URL-адреса. Заключение Хотя при работе с числами, используемыми в значениях долготы и широты, без JavaScript не обойтись, уже понятно, насколько легко можно будет предложить вашим пользователям карту их местности, для чего нужно будет просто согласиться принять геолокацию, после чего обойтись всего лишь несколькими строками кода. В этой главе рассмотрены способы обхода отсутствия в браузере поддержки геолокации или же блокировки доступа к ней. В следующей главе будут рассмотрены расширенные функции форм, предлагаемые HTML5, часть из которых может пригодиться для обеспечения контролируемой пользователем альтернативы применению геолокации.
ГЛАВА 13 Работа с формами Введение Читатели этой книги, по-видимому, уже достаточно осведомлены об использовании HTML-форм, поэтому чтение этой главы не должно вызывать затруднений: в ней на основе ранее полученных знаний объясняются все расширения, добавленные в язык с целью создания форм в соответствии со всеми современными требованиями. Например, теперь в языке есть средства выбора даты по принципу «укажи и щелкни», есть проверка типов данных, гарантирующая, что ввод, предоставленный пользователем, соответствует ожиданиям, есть специальные типы данных для телефонных номеров и адресов электронной почты и есть даже возможность сопоставления с шаблонами, использующими регулярные выражения. С обновлениями, привнесенными в HTML5, формы превратились из функциональных, но неуклюжих методов ввода в сложные и ориентированные на пользователя функции сбора данных, которые больше не будут отбивать у ваших пользователей желание зарегистрироваться и присоединиться к сайту или вводить другие данные, потому что теперь этот процесс стал интуитивно понятен и прост. Структура В этой главе рассматриваются следующие темы:  Изучение всех новых функций форм, добавленных в HTML5.  Освоение работы со средствами выбора даты, времени и цвета.  Освоение приемов включения (и отключения) автозаполнения.  Приобретение навыков использования расширенных функций переопределения и диапазонов. Цели Цель главы — собрать все новые функции форм HTML5 в одном месте и рассмотреть каждую из них, даже если какие-то из функций пока что не нашли широкого
188 | Глава 13 применения. Изучив предлагаемый материал, вы станете специалистом по повышению эффективности использования форм. Атрибуты формы HTML5 С 2015 года, когда спецификация HTML5 наконец стабилизировалась и начала одинаково работать в разных браузерах, все, что ранее было известно как Web Forms 2.0, было полностью поглощено HTML5 во всех основных версиях браузеров и на всех платформах: как стационарных, так и мобильных. Значит, все следующие функции можно использовать без всяких беспокойств времен первых дней внедрения HTML5, связанных с тем, что их могут не поддерживать средства пользователей. Для форм появилось множество новых атрибутов и тегов, и здесь предстоит знакомство с ними с подробными объяснениями, для чего предназначен каждый из них и как его использовать. Начнем с новых атрибутов формы, и первым будет autofocus. Атрибут autofocus Атрибут autofocus может применяться к любому тегу <input> для автоматического попадания его поля в фокус при загрузке страницы. При этом курсор помещается в поле в готовности к вводу данных или к выбору любого другого типа поля в готовности к изменению. Как происходит активация, показано в примере 13.1. Пример показан целиком, поскольку в этой главе они отличаются от тех, что были в предыдущей. Но после этого примера будут, как видно на рис. 13.1, показываться только те инструкции, которые заключены в документе в пару тегов <body>. Рис. 13.1. Фокус на второе поле ввода был направлен автоматически Пример 13.1 -. 2. 3. <!DOCTYPE html> <html lang="en"> <head>
Работа с формами 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. | 189 <meta charset="utf-8" /> <title>Testing for Geolocation</title> </head> <body> <form method='post' action='myform.php'> Some text <input type='text' name='text1'><br> More text <input type='text' name='text2' autofocus='autofocus'> <input type='submit'> </form> </body> </html> Это обычный документ HTML5, в котором создана форма с двумя полями ввода: text1 и text2. Но из-за указания атрибута autofocus='autofocus' фокус получает не первое поле, что было бы по умолчанию, а второе. Признаками этого служит, как показано на рис. 13.1, выделение жирными линиями контура поля ввода и наличие в нем курсора ввода. Чтобы пример работал, для отправки формы должен также присутствовать PHPфайл myform.php, получающий отправленные значения. Хотя эта книга не про PHP, в некоторых местах возникают потребности в использовании и этого языка, когда, к примеру, как и в нынешней ситуации, требуется изучить результат пользовательского ввода. Поэтому код PHP для этого файла показан в примере 13.2. Пример 13.2 1. 2. 3. 4. <?php echo "text1: '" . $_POST["text1"] . "'<br>"; echo "text2: '" . $_POST["text2"] . "'<br>"; ?> Код этого примера просто приводит к отображению значений двух полей, полученных программой. Результат — на рис. 13.2. Рис. 13.2. Выполнение PHP-кода приводит к отображению полученных входных данных Поскольку выделено было только второе поле, именно в него и был введен текст, поэтому на рисунке ввод содержится только в text2, но если бы значения были заданы обоим полям, то были бы показаны оба значения.
190 | Глава 13 Есть также сокращенная форма установки атрибута autofocus, где вместо строки 10 примера 13.1 используется следующая строка, в которой часть ='autofocus' опущена, но результат выполнения кода остается таким же: 10. More text <input type='text' name='text2' autofocus> Атрибут autocomplete Этот атрибут может применяться к тегу <form> или к любым типам тега <input>: color, date, email, password, range, search, tel, text или url. Допустимый аргумент для этого атрибута — либо on (по умолчанию), либо off. Когда атрибут автозаполнения autocomplete имеет значение on, любое поле с идентификатором ID, ранее получившее фокус ввода, запомнит свое значение, и предложит его в качестве рекомендуемого даже на разных веб-сайтах, если имя идентификатора поля будет тем же самым, что избавит вас от необходимости повторного ввода. Но когда autocomplete имеет значение off, поле так себя не ведет. Как правило, автозаполнение хорошо подходит для таких полей, как имя пользователя, адрес, номер телефона или адрес электронной почты, но только не для паролей, номеров социального страхования, сведений о банковском счете или другой конфиденциальной информации. При применении к тегу <form> атрибут влияет на все поля, принадлежащие форме, а при применении к тегу <input> он применяется только к данному конкретному полю. Поэтому при создании форм, в которых может содержаться конфиденциальная информация, автозаполнение для всей формы лучше не разрешать, и применять его только к входным данным, где запрашивается несекретная информация. Дело в том, что при доступности компьютера третьим лицам может возникать угроза безопасности, связанная с возможностью их перехода на страницу с формой, где включено, к примеру, автозаполнение данных банковского счета, которые могут быть легко отслежены и скопированы посторонним лицом. В примере 13.3 показан вариант кода из примера 13.1, где функция автозаполнения применена ко всей форме. Пример 13.3 1. 2. 3. 4. <form action='myform.php' method='post' autocomplete='on'> Some text <input type='text' name='text1'><br> More text <input type='text' name='text2'> </form> Если ранее уже происходила отправка данных любого из полей, то при запуске этого примера результат может выглядеть, как показано на рис. 13.3. В этом примере (как и указывалось ранее) отображаются только строки HTML, заключенные в тело документа, остальная же часть документа остается прежней. К тому же в примере не устанавливается автофокус, поэтому единственное, что за-
Работа с формами | 191 служивает внимания, это код autocomplete='on' в строке 1. Если автозаполнение включено, раскрывающиеся окна со списками ранее введенных данных будут предоставляться обоими полями, объявленными в строках 2 и 3. Рис. 13.3. Во втором поле предлагается раскрывающийся список автозаполнения Чтобы отключить автозаполнение, можно убрать установку атрибута из строки 1 или добавить к одному или нескольким полям ввода установку autocomplete='off', что и будет сделано со вторым полем путем следующего изменения кода в строке 3: 3. More text <input type='text' name='text2' autocomplete='off'> В результате, когда фокус устанавливается на поле ввода, объявленном в строке 2, появляется раскрывающийся список. Вместо этого можно не включать автозаполнение для всей формы, а затем, как показано в примере 13.4, просто включить его для конкретных входных данных, получив точно такой же результат, что был показан на рис. 13.3. Пример 13.4 1. 2. 3. 4. <form action='myform.php' method='post' autocomplete='off'> Some text <input type='text' name='text1'><br> More text <input type='text' name='text2' autocomplete='on'> </form> Следует помнить, что автозаполнение включено по умолчанию во всех браузерах, поэтому, если нужно его отключить, следует предпринять определенные действия, показанные в строке 1. А затем в строке 3 автозаполнение специально включается для получения того же результата, что был показан на рис. 13.3. Сокращенного варианта настройки этого свойства, как для свойства autofocus, не существует. Атрибут form Использование этого атрибута позволяет размещать поля ввода в любом месте документа, при условии указания ID формы, к которой они применяются. Понять, за-
192 | Глава 13 чем это нужно, поможет знание о возможности использования с этим атрибутом, к примеру, нового тега <fieldset>, предназначенного создания набора (или группы, или коллекции) полей применительно к той или иной форме. Это может упростить создание более длинных и сложных форм и сделать их понятнее для других разработчиков. Но использовать атрибут формы в наборах полей необязательно, это всего лишь один из доступных вариантов. В примере 13.5 показаны три поля ввода, два из которых находятся в наборе полей, а третье — само по себе. Пример 13.5 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. <form id='myform' action='myform2.php' method='post'> <input type='submit'> </form><br> <fieldset form='myform'> Some text <input form='myform' type='text' name='text1'><br> More text <input form='myform' type='text' name='text2'> </fieldset><br> Even More <input form='myform' type='text' name='text3'> Кроме того, изменился цвет фона набора полей ввода. Это показывает, насколько удобны наборы полей для объединения данных, имеющих что-то общее и родственное, например, данных о номере телефона и адресе электронной почты. А в самой форме полей ввода нет (хотя при желании они могли бы быть). Результат загрузки этого примера в браузер показан на рис. 13.4, где видно, что одно из преимуществ размещения двух входных данных в наборе полей — то, что браузер выделил их, а также поместил вокруг них рамку: Рис. 13.4. Форма, созданная с использованием набора полей и одиночного поля ввода Теперь также можно сразу заметить, что кнопка отправки данных формы находится вверху, тем самым демонстрируется вновь приобретенная гибкость, позволяющая
Работа с формами | 193 разместить эту кнопку в любом месте. Если нужно, саму форму можно разместить под различными полями ввода, все зависит от вашего желания. Дело в том, что в строках с 1 по 3 этого примера теперь представлена просто оболочка формы, имеющая только кнопку отправки. Но к форме добавлен идентификатор, поскольку ее свойству id присвоено значение myform, что позволило присоединить к этой форме набор полей и отдельно взятое поле ввода. Чтобы форме стало известно, что нужно делать с набором полей ввода и отдельным полем ввода, нужно не забыть в обоих местах указать в атрибуте form имя формы. Чтобы подыграть этому примеру, файл myform.php был обновлен до myform2.php с добавлением еще одной строки кода для обработки ввода text3: 3. echo “text3: ‘” . $_POST[“text3”] . “’<br>”; Результат отправки данных этих полей показан на рис. 13.5. Рис. 13.5. Данные формы успешно отправлены Атрибут formaction Использование этого атрибута позволяет изменить адресат обработки типов submit и image тега <input> с целью отправки введенных данных на выбранный вами URLили иной адрес, переопределяя тем самым любое ранее указанное для формы назначение. Чтобы проиллюстрировать это, у нас как нельзя кстати уже имеются файлы myform.php и myform2.php, отображающие соответственно два и три значения. Итак, в примере 13.6 создается форма, данные которой отправляются в myform.php, но с дополнительной кнопкой отправки данных в myform2.php, на которой следует щелкнуть кнопкой мыши или изображения которой следует коснуться. Пример 13.6 1. 2. 3. 4. 5. <form action=’myform.php’ method=’post’> Some text <input type=’text’ name=’text1’><br> More text <input type=’text’ name=’text2’> <input type=’submit’><br>
194 6. 7. 8. | Глава 13 Even More <input type=’text’ name=’text3’> <input type=’submit’ formaction=’myform2.php’> </form> Результат загрузки в браузер будет иметь вид, показанный на рис. 13.6. Рис. 13.6. Форма с двумя кнопками отправки данных Эта форма очень похожа на ту, что была в примере 13.1, но с добавлением дополнительного ввода text3, заключенного в стандартные теги формы <form>, отправляющей свои данные в программу myform.php с инструкцией отправки в строке 4. Необычно здесь добавление второй инструкции отправки в строке 7, где вместо прежней установки данные отправляются в myform2.php, поскольку это значение присвоено атрибуту formaction. Если запустить код этого примера, можно будет увидеть, что первая кнопка выполняет отправку в одну форму с результатом, похожим на показанный на рис. 13.2, а вторая кнопка — в другую форму с результатом, похожим на показанный на рис. 13.5. Другие переопределения формы Наряду с изменением адресата обработки данных, привязанного к отдельно взятой кнопке, можно также изменить тип и метод кодирования данных. Например, форму можно настроить на отправку составных данных в prog.php, применив следующий код: 1. 2. 3. 4. <form action='prog.php' method='post' enctype='multipart/form-data'> <input type='file'> <input type='submit'> </form> Это позволит выложить файл на сервер. Но предположим, что имеется дополнительная кнопка отправки, которой нужно придать иное действие, например отправку только текстового поля, перенацелив отправку на другую программу, например
Работа с формами | 195 на prog2.php, и задав стандартную кодировку URL. Это можно сделать путем внесения в предыдущий код таких изменений: 1. 2. 3. 4. 5. 6. 7. <form action='prog.php' method='post' enctype='multipart/form-data'> <input type='file'> <input type='submit'><br> <input type='text' name='filename'> <input type='submit' formaction='prog2.php' formenctype='application/x-www-form-urlencoded'> </form> Теперь в строках с 4 по 6 заявлен текстовый ввод, названный filename, и этот ввод принимает только стандартную кодировку формы по щелчку или касанию применительно ко второй, а не первой кнопке отправки. Код в строке 6 показан с отступом, чтобы обозначить перенос инструкции, не поместившейся в одной строке. Это ни на что не влияет, поскольку HTML относится к этому вполне лояльно, позволяя оставлять для компоновки кода сколько угодно пустых мест (включая разрывы строк), поэтому и было решено сделать после 'prog2.php' переход на новую строку. Этот код не был помещен в пронумерованный пример из-за отсутствия файла, выкладываемого на сервер, а также файла PHP для обработки такого действия. Но теперь уже вам должно быть известно, что выкладывание файлов на сервер — стандартная функция HTML еще до появления HTML5, поэтому данные строки кода иллюстрируют возможность переопределения как типа кодировки, так и адресата обработки данных формы. Но это еще не все, поскольку при желании можно с помощью атрибута formmethod изменить и метод формы ввода. Например, в строке 5 можно изменить метод отправки с используемого по умолчанию метода post, указанного в первой строке кода, на метод get, который будет действителен только для данной кнопки отправки данных. 5. <input type='submit' formaction='prog2.php' formmethod='get' По аналогии с переопределением метода отправки и адресата обработки данных, с помощью атрибута formtarget можно изменить целевой фрейм или страницу ответа на отправку данных отдельно взятого ввода. Атрибут multiple Только что было показано, как файл выкладывается на сервер. При наличии на сервере программы обработки этого процесса на PHP или на другом языке с помощью атрибута multiple можно разрешить выложить на сервер сразу несколько файлов: <input type='file' name='docs' multiple='multiple'> Теперь, удерживая нажатой при выборе имен файлов клавишу Ctrl, ваши пользователи смогут выгрузить на сервер сразу несколько файлов.
196 | Глава 13 Атрибут novalidate Этот атрибут указывает, что данные формы при их отправке не должны проверяться (обычно так делается при наличии своей собственной программы проверки, которая, по мнению разработчика, больше соответствует потребностям). Он принимает значения true или false, применимые к тегу <form> и ко многим специальным новым типам тега <input>, например tel и num. Воспользоваться им можно следующим образом: <input type='text' name='field' novalidate='true'> Соответствующий атрибут formnovalidate позволяет переопределить атрибут novalidate непосредственно для отдельно взятого поля ввода. Атрибуты width и height Если вместо кнопки по умолчанию в качестве кнопки отправки данных используется изображение типа image, его ширину и высоту можно, как показано в примере 13.7, изменить с помощью атрибутов width и height. Пример 13.7 1. 2. 3. 4. <form method='post'> Name <input type='text' name='name'><br> <input type='image' src='submit.png' width='214' height='24'> </form> В этом примере создается форма без URL-адреса для отправки данных (то есть она отправляет их сама себе, не вызывая никаких действий) с изображением кнопки отправки, имеющим исходные размеры 220 x 66 пикселей, размер которого был изменен до 214 x 24 пикселей, чтобы, как показано на рис. 13.7, соответствовать ширине ввода. Рис. 13.7. Изменение размера изображения кнопки отправки данных. Конечно, вы будете использовать гораздо более интересные изображения и применять более изысканные стили, но здесь просто демонстрируется возможность изменения их размера прямо в инструкции ввода данных. Кроме того, при желании можно воспользоваться кодом CSS.
Работа с формами | 197 Атрибут list и теги <datalist> и <option> Выпадающие списки — великолепный прием улучшения пользовательского восприятия, который легко может быть реализован и без использования JavaScript или CSS, нужно просто поместить элементы списка в тег <datalist> в виде набора тегов <option>. Затем в теге поля ввода в качестве аргумента его атрибута list нужно указать значение атрибута id, принадлежащего списку, привязав тем самым список к полю ввода. Предположим, к примеру, что пользователям нужно задать вопрос о том, какой поисковой системе они отдают предпочтение, тогда одним из способов решения этой задачи может стать код, показанный в примере 13.8. Пример 13.8 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. <form method='post'> Select your favorite <input type='url' name='site' list='links'> <input type='submit'> </form> <datalist id='links'> <option label='Google' <option label='Yahoo!' <option label='Bing' <option label='Ask' </datalist> value='http://google.com'> value='http://yahoo.com' > value='http://bing.com' > value='http://ask.com' > Обратите внимание, что при отправке данных происходит перезагрузка той же самой страницы, поскольку здесь нам не нужен никакой PHP-код, обрабатывающий данные, акцент делается на то, что происходит перед отправкой и показано на рис. 13.8. В строках с 1 по 4 создается стандартная форма с кнопкой отправки, указанной в строке 3, и стандартным полем ввода, указанным в строке 2, где новое для нас — запрос типа ввода url, а не текст, а также предоставление атрибуту list идентификатора, присвоенного тегу <datalist> под формой в строке 6. Затем в строках с 7 по 10 идет череда тегов <option>, в которых указываются четыре разных имени поисковых систем, назначенных атрибуту label каждого тега, а соответствующие URLадреса назначаются в тех же строках атрибуту value. Включать этот список в тег <form> необязательно, поскольку он идентифицируется по имени. Полезная особенность такого списка — возможность проигнорировать все предложенные варианты и ввести свой собственный, например, https://duckduckgo.com или адрес альтернативного механизма поиска, т. е. здесь пользователю предлагается максимальная простота использования наряду с гибкостью выбора. Кроме того, здесь не нужно использовать тип ввода URL, поскольку допускаются все буквенноцифровые типы ввода.
198 | Глава 13 Рис. 13.8. Предложение предварительно заполненного выпадающего списка Атрибуты min, max и step Временами пользователи не вполне осознают, какие именно данные их просят ввести, поэтому им лучше дать подсказку. Например, можно указать минимальное и максимальное значения для входных данных, содержащих числа или даты. Подойдут все значения из представленного диапазона, но не только они: их в указанных пределах можно изменять клавишами со стрелками вверх и вниз, а мышь после щелчка на значке часов можно использовать с инструментом выбора времени. В примере 13.9 у пользователя запрашивается время встречи, которое должно быть между 14:00 и 17:00, и используется новый тип ввода времени, появившийся в HTML5. Пример 13.9 1. 2. 3. 4. 5. 6. <form method='post'> Choose a meeting time <input type='time' name='meeting' value='14:00' min='14:00' max='17:00'> <input type='submit'> </form> В строке 3 начальное время ввода установлено на 14:00, а потом указан доступный диапазон. Прокрутить эти числа с выходом за пределы этого диапазона невозможно, но можно выбрать часы и минуты, вызвав щелчком мыши на значке часов средство выбора времени, и при попытке выбрать время, выходящее за установленное,
Работа с формами | 199 будет выдано сообщение, похожее на то, что показано на рис. 13.10 (где запрошено время 19:07). Рис. 13.9. Появление окна выбора времени Рис. 13.10. Пользователю сообщается, что выбранное им время недоступно Если говорить о выборе времени с определенными интервалами, то поминутный выбор возможен при указании для атрибута step, количество секунд в интервале. Для 15-минутных интервалов значение будет 15 x 60 или 900, для 30-минутных — 1800 и т. д. А так выглядит код в строке 4, позволяющий вводить время только с часовым интервалом: 4. min='14:00' max='17:00' step='3600'> При этом пользователь не сможет изменять количество минут с помощью клавиатуры. А при попытке ввода времени, не соответствующего часовому интервалу, с помощью мыши в средстве выбора времени появится сообщение, показанное на рис. 13.11.
200 | Глава 13 Рис. 13.11. Запрошенное время не соответствует часовому интервалу, поэтому ввод отклонен Другие типы ввода даты и времени В HTML5 есть также и новый тип ввода даты, возвращающий значение в формате ГГГГ-ММ-ДД, который можно использовать аналогично системе ввода времени. Кроме того, есть тип ввода месяца, возвращающий значение ГГГГ-ММ, и тип ввода недели, возвращающий значение ГГГГ-Нnn, где ГГГГ — год, а Нnn — неделя в формате, к примеру Н23. Может также быть запрошен ввод даты и времени наряду с типом ввода datetime, возвращающий значение в формате ГГГГ-ММ-ДДTЧЧ:ММZ, которое, к примеру, для 2 мая 2027 года в 17 часов 56 минут может принимать следующий вид: 202705-02T17:56Z. Кроме того, с помощью свойства datetime-local можно запросить локальное время пользователя, возвращающее значение в формате ГГГГ-ММДДTЧЧ:ММ без символа Z на конце (который ставят в случае возвращения данных при типе ввода datetime). Порядок интерпретации и обработки этих возвращаемых значений зависит от программы, запущенной на внутреннем сервере. Атрибут pattern Современный подход к веб-разработке предполагает подсказку о допустимости ввода тех или иных данных наиболее простым и удобным для пользователя способом. Цель, к тому же, состоит в отслеживании и исправлении любого неприемлемого ввода до его отправки на сервер. Использование наряду с множеством других средств атрибута pattern позволяет, к примеру, не прибегая к использованию кода JavaScript и не дожидаясь проверки со стороны программы на сервере, понять, относятся ли введенные данные к допустимому адресу электронной почты. Этот атрибут можно применить к любому тегу <input>, в котором в качестве значений его атрибута type используется что-либо из перечня email, password, search, tel, text или url. В примере 13.10 показан запрос произвольного текста, состоящего только из букв, цифр и пробелов.
Работа с формами | 201 Пример 13.10 1. 2. 3. 4. 5. 6. <form method='post'> Enter alphanumeric text only <input type='text' name='text' pattern='[a-zA-Z0-9 ]+' title='Use letters, numbers and spaces only'> <input type='submit'> </form> На рис. 13.12 показана выводимая на экран информация в случае ввода данных, не соответствующих указанному шаблону. Рис. 13.12. Восклицательный знак запрещен, поэтому выводится сообщение об ошибке В шаблоне, используемом в строке 3, указаны буквы a-z и A-Z, а также цифры 0-9 и символ пробела, и все это заключено в квадратные скобки, за которыми следует знак +, указывающий, что в тексте должен присутствовать как минимум один из символов, относящихся к типам, указанным в скобках. В строке 4 пользователю даются в виде текста дальнейшие указания, присвоенные свойству заголовка поля ввода. Этот текст отображается либо когда пользователь наводит на поле ввода указатель мыши, либо, как показано выше на рис. 13.12, при попытке ввода недопустимых символов. Так как же все это работает? Дело в том, что здесь используется так называемое регулярное выражение — краткий способ представления текстовых типов. Сам механизм их работы — тема непростая и не вписывается в рамки этой книги. Но ответы на любые вопросы можно найти по адресу https://tinyurl.com/reg-expr. Кстати, для типов ввода email, num, tel и url атрибут pattern не понадобится, их проверка будет проводиться автоматически. Атрибут placeholder Использование этого атрибута предоставляет замечательные возможности улучшения пользовательского восприятия. Он позволяет помещать инструкцию в серых тонах, чтобы было понятно, что это не предлагаемый ввод, непосредственно в само поле ввода, и удалять ее сразу же, как только пользователь начинает вводить дан-
202 | Глава 13 ные. Для этого атрибуту placeholder нужно просто присвоить произвольный текст, как в примере 13.11, где в поле ввода запрашивается имя пользователя длиной от 5 до 15 символов. Пример 13.11 1. 2. 3. 4. 5. <form method='post'> Choose a username <input type='text' name='u' placeholder='Any 5-15 character name'> <input type='submit'> </form> Результат выполнения этого примера показан на рис. 13.13. Рис. 13.13. Подсказка в placeholder о том, что должно быть в поле ввода При желании к полю ввода можно также добавить контролирующий ввод атрибут pattern (присвоив ему соответствующее регулярное выражение) и, возможно, для дальнейших разъяснений атрибут title, но в целом для начала будет достаточно и этого. При длинном тексте подсказки не забудьте скорректировать в нужную сторону значение атрибута size. Атрибут required Использование атрибута required, показанное в примере 13.12, позволяет не оставлять поле незаполненным при отправке формы. Пример 13.12 1. 2. 3. 4. 5. <form method='post'> Choose a username <input type='text' name='username' required> <input type='submit'> </form> На рис. 13.14 показана подсказка, выводимая на экран при попытке отправки формы с незаполненным полем:
Работа с формами | 203 Рис. 13.14. Пользователю предлагается заполнить поле перед отправкой формы Предполагается, что синтаксис этого атрибута будет иметь вид required='required', но, как видно из примера, можно воспользоваться сокращенным вариантом required, что также будет работать. Тип ввода color Иногда нужно предложить пользователю выбрать цвет, и теперь, как показано на рис. 13.13, это весьма нетрудно сделать с помощью типа ввода color. Пример 13.13 1. 2. 3. 4. 5. <form method='post'> Choose a color <input type='color' name='color'> <input type='submit'> </form> На рис. 13.15 этот пример показан в действии с используемым вместо поля текстового ввода цветовым блоком и с окном выбора, в котором предлагаются различные варианты, в том числе пипетка выбора цвета, ползунковый движок по цветовой палитре, прямоугольное поле выбора цвета или обычный ввод прямых значений составляющих цвета в формате RGB. Пользователи могут даже щелкнуть в правом нижнем углу на значке стрелки вверх и вниз, чтобы изменить формат ввода на задание оттенка, насыщенности и яркости (HLS), или же на использование шестнадцатеричных значений составляющих цвета. Цвет, отправляемый с помощью палитры цветов, будет представлен не названием, а шестнадцатеричной строкой цвета в CSS-формате, начинающейся с символа #, например #8f9b31. Независимо от способа выбора цвета по щелчку пользователя на палитре или по указанию параметров HSL вместо RGB возвращаемое значение будет именно в этом шестнадцатеричном формате. Это можно проверить, изменив тип метода в строке 1 на get, отправив выбранный цвет и просмотрев URL-адрес, возвращаемый в адресную строку браузера, который должен завершаться чем-то
204 | Глава 13 вроде ?color=%238f9b31. Здесь, поскольку это часть URL-адреса, браузер преобразовал предыдущий символ # в объект HTML %23, но фактическое значение, если оно будет отправлено в программу, будет начинаться с #. Рис. 13.15. Открытая цветовая палитра Числа и диапазоны Работа с числами в HTML5 была существенно улучшена благодаря поддержке числового типа ввода number. При его указании при проходе над полем указателя мыши справа от поля ввода появляется пара значков со стрелками вверх и вниз, на которые можно щелкать для уменьшения или увеличения указанного в поле значения. Пользователь может также вводить свое значение напрямую. В примере 13.14 иллюстрируется использование такого поля с начальным значением 18, установленным по умолчанию. Пример 13.14 1. 2. 3. 4. 5. <form method='get'> How old are you? <input type='number' name='age' vajue='18'> <input type='submit'> </form> Результат выполнения примера после однократного щелчка на значке стрелки вверх показан на рис. 13.16.
Работа с формами | 205 Рис. 13.16. Пример использования числового типа ввода Если нужно запретить пользователю вводить значения, не имеющие никакого смысла, можно также указать тип ввода диапазона range, в результате чего на экране появится изображение ползунка. Этот тип, как показано в пример 13.15, можно использовать в сочетании с атрибутами min, max и step, именно это и показано в строке 3, разбитой надвое аккуратным переносом, поскольку она получилась довольно длинной. Пример 13.15 1. 2. 3. 4. 5. 6. <form method='post'> How old are you? <input type='range' name ='num' min ='1' max ='110' value='18' step='1'> <input type='submit'> </form> Результат загрузки этого примера в браузер показан на рис. 13.17, где можно заметить возникшую проблему: Рис. 13.17. Отображение ползунка диапазона Поняли, в чем проблема? Сам ползунок выглядит великолепно, но на нем отсутствует указание конкретного выбранного значения. Для типа ввода range это может стать серьезной проблемой, но тут весьма кстати имеется довольно хитрый и простой способ исправить это упущение, применив код, показанный в примере 13.16, где есть дополнительная инструкция JavaScript, вставленная в элемент ввода в строке 5, а также дополнительный тег <output> в строке 6.
206 | Глава 13 Пример 13.16 1. 2. 3. 4. 5. 6. 7. 8. <form method='post'> How old are you? <input type='range' name ='num' min ='1' max ='110' value='18' step='1' oninput= 'this.nextElementSibling.value = this.value'> <output>18</output> <input type='submit'> </form> Дело в том, что все HTML-элементы поддерживают присоединение событий, и здесь было присоединено событие ввода oninput. Благодаря этому инструкция JavaScript запускается при каждой выдаче события, возникающего при каждом перемещении ползунка. JavaScript — весьма хитрый язык, в нем используется псевдообъект по имени this, которым представлен текущий элемент. Поэтому при записи в свойство nextElementSibling значения псевдообъекта this это значение тут же записывает элемент <output>, следующий сразу же за текущим элементом. Сперва в <output> содержится начальное значение 18, чтобы соответствовать значению по умолчанию, предоставленному в строке 4. Затем при каждом перемещении ползунка в элемент <output> копируется this.value (текущее значение в поле ввода). Решение действительно элегантное, и результат его применения показан на рис. 13.18. Рис. 13.18. Теперь текущее значение из заданного диапазона отображается на экране Тип ввода search За все годы существования типа ввода search его польза сводилась только лишь к появлению справа от поля ввода значка х, позволяющего очистить ввод, и к применению немного другого стиля на компьютере Mac. Единственной причиной его использования может стать желание добиться лучшего семантического понимания вашей страницы поисковыми системами.
Работа с формами | 207 Даже в веб-документах утверждается, что этот тип ввода функционально идентичен типу ввода text. Но для полноты картины теперь известно и о нем. Заключение В этой главе была обрисована вся информация о новшествах, появившихся в HTML5 при использовании форм. Самое приятное, что все эти функции изначально работают автономно, не требуя никаких дополнительных сценариев JavaScript, и в совокупности играют немалую роль в улучшении пользовательского восприятия при работе с формами. В следующей главе мы снова немного обратимся к вопросам программирования на JavaScript при рассмотрении новых возможностей локального хранения данных в рамках концепции HTML5.
ГЛАВА 14 Локальное хранилище и многое другое Введение В HTML5 есть целый ряд дополнительных разносортных функций, поэтому они были собраны вместе в этой предпоследней главе, посвященной HTML5. Среди них — функции локального и сеансового хранилища; средства, упрощающие понимание ваших документов поисковыми роботами, использующими микроданные; функции передачи кода, требующего серьезных вычислительных ресурсов веб-воркеров и функции, позволяющие создавать автономные веб-приложения. Многие из этих функций требуют применения сценариев на JavaScript, поэтому основные положения по их использованию сопровождаются ссылками на источники дополнительной информации, которая может вас заинтересовать. Структура В этой главе рассматриваются следующие темы:  Приемы хранения данных на локальном устройстве пользователя.  Осознание важности предоставления роботам доступа к чтению веб-документов.  Приемы ускорения выполнения кода с помощью веб-воркеров.  Приемы превращения веб-страниц в автономные веб-приложения. Цели Здесь путем изучения целого ряда тонкостей HTML5, управляемых с помощью JavaScript, устранятся многие пробелы в ваших знаниях, изучатся средства упрощения понимания веб-документов поисковым роботом. Освоение предлагаемого материала позволит изучить приемы разгрузки сценариев JavaScript с помощью веб-воркеров и создания своих собственных веб-приложений.
210 | Глава 14 Использование локального хранилища В былые годы единственным способом хранения данных на компьютере пользователя были cookie-файлы, ограниченные как по количеству, так и по объему данных в каждом таком файле, не превышающем 4 Кб. Их также нужно было передавать в обе стороны при каждой перезагрузке страницы, и, если сервер не использовал шифрование Secure Sockets Layer (SSL), то при каждой своей передаче файлы cookie пребывали в открытом незашифрованном виде. Но с приходом HTML5 появился доступ к гораздо большему локальному пространству, предназначенному для хранения данных (обычно от 5 Мб до 10 Мб на домен в зависимости от применяемого браузера), которое не вычищается при загрузке страницы и между посещениями веб-сайта (и даже после выключения компьютера и повторного резервного копирования), и данные которого не отправляются на сервер при каждой загрузке страницы. Можно работать с данными, составляющими пары ключ/значение, где в качестве ключа выступает имя, назначенное для ссылки на данные, а значение может содержать данные любого типа, но сохраненные в виде строки. Все данные для текущего домена имеют уникальный характер. Любое локальное хранилище, созданное веб-сайтами с другими доменами, отделено от текущего локального хранилища по соображениям безопасности и недоступно для любого домена, кроме того, чьи данные в нем хранятся. П РИМЕЧАНИЕ Возможно, главная причина высокой популярности локальных хранилищ среди веб-разработчиков заключается в том, что файлы cookie могут создаваться только на веб-сервере и отправляться только на него. Без файлов cookie не было бы простого способа сохранить нужное состояние. А локальное хранилище управляется непосредственно в браузере, что позволяет создавать автономные вебприложения, способные в той или иной степени работать вне сети. Кроме того, файлы cookie могут иметь размер до 4 Кб, а размер веб-хранилища в большинстве браузеров может составлять до 5 Мб. Хранение и извлечение локальных данных Для доступа к локальному хранилищу можно воспользоваться методами объекта localStorage под названиями setItem(), getItem(), removeItem() и clear(). К примеру, чтобы сохранить имя пользователя и пароль на локальной системе, можно воспользоваться следующим кодом: localStorage.setItem('username', 'WHouston') localStorage.setItem('password', 'bodyguard1992') Если размер значения превышает оставшееся для хранилища место на диске, выдается исключение 'Out of memory' («Недостаточно памяти»). А получить эти данные
Локальное хранилище и многое другое | 211 при загрузке другой страницы или при возвращении пользователя на веб-сайт, чтобы исключить их повторный ввод, можно с помощью следующего кода: username = localStorage.getItem('username') password = localStorage.getItem('password') Если запрошенный ключ не существует, функция getItem(), как показано на рис. 14.2, возвращает значение null. П РИМЕЧАНИЕ Если бы все веб-сайты могли видеть данные, сохраненные другими веб-сайтами, локальное хранилище стало бы источником проблем безопасности. Поэтому отдельно взятый веб-сайт может получить только то локальное хранилище, которое сам и создал, а все остальные локальные данные будут для него невидимы, будто их и вовсе не существует. При этом некачественный код может оставлять лазейки для атак межсайтового скриптинга (XSS), позволяя злоумышленникам находить способы обмана браузера, заставляя его полагать, что данные поступают с одного сайта, хотя на самом деле они поступают с другого. Поэтому, несмотря на то что примеры в главе относятся к паре имени пользователя и пароля, сохранения этих элементов в локальном хранилище все же стоит избегать, если есть хоть малейшие опасения по поводу возможности попадания веб-сайта под огонь XSS-атак. Сложность вопросов, касающихся XSS, заставляет при любых сомнениях призывать к тому, чтобы в локальное хранилище помещались только неконфиденциальные данные, такие как пользовательская разметка и цветовые предпочтения. Использовать имена функций необязательно, поскольку доступ к объекту localStorage можно получить напрямую, и две следующих инструкции абсолютно эквивалентны: localStorage.setItem('key', 'value') localStorage['key'] = 'value' По аналогии с этим эквивалентны и следующие две инструкции: value = localStorage.getItem('key') value = localStorage['key'] Давайте все полученные только что знания сведем в исполняемый код, приведенный в примере 14.1, где показаны только те инструкции, которые заключены в раздел <script>. Пример 14.1 1. 2. 3. 4. 5. 6. if (typeof localStorage == 'undefined') { alert('Local storage unavailable.') } else {
212 7. 8. 9. 10. 11. 12. 13. 14. 15. | Глава 14 localStorage.setItem('username', 'WHouston') localStorage.setItem('password', 'bodyguard1992') username = localStorage.getItem('username') password = localStorage.getItem('password') alert("Data retrieved: username = '" + username + "', password = '" + password + "'.") } В строках с 1 по 4 выполняется проверка поддержки браузером локального хранилища. Если оно не поддерживается, объект localStorage будет иметь значение undefined, так что проверка особых трудностей не вызывает. Локальные хранилища должны поддерживать все современные браузеры, но, если у пользователя более старый браузер, эти несколько строк кода ему не помешают. Конечно, вместо окна оповещения, выводимого функцией alert(), было бы полезнее применить ряд более подходящих инструкций или даже внести изменение в свойство location объекта window для вызова новой страницы. Если локальное хранилище поддерживается, то выполняются строки с 5 по 15, при этом в строках 7 и 8 задается сохранение некоторых данных на локальное устройство пользователя, а в строках с 10 по 11 задается извлечение этих же данных. В строке 13 функция alert() задает появление всплывающего окна, показанного на рис. 14.1, позволяющего показать, что процесс действительно работает. Рис. 14.1. Данные были сохранены в локальном хранилище и извлечены из него После сохранения эти значения так и останутся в локальном хранилище, пока не будут удалены из него, в чем можно будет убедиться, закомментировав, как показано ниже, строки 7 и 8, а затем запустив пример еще раз. Результат должен быть тем же, что показан на рис. 14.1. 7. 8. // localStorage.setItem('username', 'WHouston') // localStorage.setItem('password', 'bodyguard1992')
Локальное хранилище и многое другое | 213 Удаление и очистка локальных данных Чтобы удалить элемент данных из локального хранилища, нужно всего лишь вызвать функцию removeItem(): username = localStorage.removeItem('username') password = localStorage.removeItem('password') Эта функция служит для извлечения элемента данных и помещения его в переменную (в данном случае это переменные username и password) с последующим удалением данных из локального хранилища. Если чтение удаляемых данных не требуется, можно просто вызвать функцию без присваивания: localStorage.removeItem('username') localStorage.removeItem('password') Можно также, вызвав функцию clear(), очистить все локальное хранилище для текущего домена: localStorage.clear() Давайте так и сделаем, применив код примера 14.2. Пример 14.2 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. if (typeof localStorage == 'undefined') { alert('Local storage unavailable.') } else { localStorage.removeItem('username') localStorage.removeItem('password') username = localStorage.getItem('username') password = localStorage.getItem('password') alert("Data retrieved: username = '" + username + "', password = '" + password + "'.") } Здесь в строках 7 и 8 задается удаление сохраненных данных, о чем свидетельствует изображение на рис. 14.2, где показано, что оба извлеченных значения равны нулю. В остальном код такой же, как и в примере 14.1, поэтому можно будет без труда разобраться в том, что здесь происходит. Разумеется, более широкое использование локального хранилища будет сводиться к написанию соответствующего кода JavaScript, но углубление в суть вопроса выходит за рамки тематики этой книги.
214 | Глава 14 Рис. 14.2. Локальные данные были стерты Использование взамен этого хранилища сеансов Преимущество локального хранилища в том, что хранящиеся в нем данные сохраняются в течение длительного времени, если только не будет очищен кэш браузера. Если же предпочтение отдается хранению данных только в ходе текущего сеанса просмотра, то эта задача решается легко и просто. Нужно всего лишь заменить все случаи использования термина localStorage на sessionStorage, и все получится, поскольку будет работать точно так же. Единственное отличие будет в том, что при закрытии пользователем текущей вкладки или окна браузера срок хранения всех данных хранилища сеанса истечет. Но если хранилище сеансов использовать только для поддержки настроек во время текущего сеанса пользователя на веб-сайте (например, для списка элементов корзины покупок), то все происходящее с этими данными после их проверки и завершения сеанса уже не играет никакой роли, поэтому их не следует даже пытаться сохранять в более долговременном локальном хранилище. П РИМЕЧАНИЕ Поскольку хранилище сеансов настраивается для каждой вкладки, то при открытии пользователем веб-сайта сразу в нескольких вкладках собственное отдельное хранилище сеансов будет у каждой вкладки. Это следует учитывать, если данные сеанса у некоторых пользователей продолжают теряться в ходе него, поскольку это может быть связано с переключениями между вкладками, когда они меняются местами, и с открытием сайта на новых вкладках. Отследить это можно, применив уникальный токен в виде случайной строки и сохранив его в хранилище сеансов. Считывая эту строку, можно определить, к какому из хранилищ осуществляется доступ. И опять же, рассматривать соответствующий сценарий JavaScript не позволяют рамки тематики этой книги. Микроданные Микроданные используются с целью вложения метаданных в существующий контент веб-страниц. Их затем можно извлечь и обработать поисковыми системами и
Локальное хранилище и многое другое | 215 поисковыми роботами с целью повышения удобства пользователей при просмотре информации. Более того, микроданные способствуют более четкой структуризации данных и более точной детализации информационного наполнения и назначения веб-документа при его анализе поисковыми системами. Иными словами, микроданные — это подмножество HTML, разработанное для придания документу смысла с целью облегчения машинного анализа, результаты которого совпадали бы с представлениями читателей о сути документа. Микроданные открывают доступ к следующим новым атрибутам тегов: itemscope, и itemprop. Их использование позволяет четко определять свойства документа, например книги, предоставляя информационный перечень, которым компьютер может воспользоваться для распознания, к примеру, ее автора, издателя, сути содержимого и т. д. itemtype, itemid, itemref В примере 14.3 показано, насколько легко микроданные можно применить к стандартному HTML-документу. Пример 14.3 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Incorporating Microdata</title> </head> <body> <section itemscope itemtype='http://data-vocabulary.org/Person'> <img itemprop='photo' src ='elon_musk.jpg' alt ='Elon Musk' align='left' style='margin-right:10px'> <h2 itemprop='name'>Elon Musk</h2> <p> Elon Musk is a South African-born American <span itemprop='role'>entrepreneur</span> and <span itemprop='title'>businessman</span>. He likes to call himself the <span itemprop='nickname'>Technoking</span> of Tesla, and his website is: <a itemprop='url' href='https://www.tesla.com/en_GB/elon-musk'>tesla.com</a>. </p> <p>Elon's address at SpaceX is:</p>
216 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. | Глава 14 <address itemscope itemtype='http://data-vocabulary.org/Address' itemprop='address'> <p> <span itemprop='street-address'>1 Rocket Road</span><br> <span itemprop='locality' >Hawthorne </span><br> <span itemprop='region' >California </span><br> <span itemprop='postal-code' >90250 </span><br> <span itemprop='country-name' >USA </span> </p> </address> </section> </body> </html> Результат загрузки этого примера в браузер показан на рис. 14.3. Рис. 14.3. При отображении микроданные, имеющиеся на веб-странице, не видны В качестве микроданных можно применять множество различных свойств. Их так много, что для сведений о всем перечне лучше будет посетить сайт tinyurl.com/html5md. Микроданные могут применяться для книг, музыки, телешоу, событий, людей, мест и многих других типов данных. В примере 3.4 использован тип микроданных person, обозначающий их отношение к человеку, и если изучить код, можно заметить тип photo для назначения элемента
Локальное хранилище и многое другое | 217 изображения itemprop в строке 10, тип role для описания entrepreneur (предприниматель) в строке 20, тип url в строке 25, и т. д. и т. п. Но все эти микроданные припрятаны исключительно для поисковых систем или других программ, которым нужно понимать суть данных. Сама веб-страница отображается точно также, как и в отсутствие микроданных. В этом и весь смысл — теперь машины могут быстро понять назначение веб-страницы по аналогии с ее восприятием со стороны людей. Но микроданные рекомендуется использовать только в тех случаях, когда для рассматриваемого документа важно, чтобы он был полностью понятен машинам. Современные поисковые системы и так уже достаточно умны, поэтому микроданные будет полезнее применять в области искусственного интеллекта при подготовке данных для программы по их обработке и изучению. Обычный веб-разработчик вряд ли будет слишком часто применять микроданные, но теперь вам уже известно, что это такое, как их использовать и где найти все типы микроданных. Веб-воркеры Применение JavaScript в этом разделе будет еще более насыщенным. Поэтому при излишней сложности можно смело переходить к изучению следующей главы, посвященной аудио и видео в HTML5. А текущий раздел будет дожидаться вашего возвращения к нему, если он когда-либо в будущем вам понадобится. Обычно для обработки данных в JavaScript в фоновом режиме нужно настроить таймер, и при инициируемых им постоянных вызовах некоторая часть процессорного времени будет предоставляться одной или нескольким функциям, которые затем должны быстро выполнять небольшие части работы и возвращать управление, чтобы не замедлять работу браузера и не снижать степень его отзывчивости. Ко всему прочему веб-воркеры предоставляют браузерам стандартный способ запуска в фоновом режиме сразу нескольких потоков JavaScript, способных обмениваться сообщениями подобно тому, как это делают потоки, работающие в операционной системе. Нужно просто вызвать новый рабочий сценарий, который будет находиться в фоновом режиме, ожидая отправки ему сообщений, на которые он затем будет реагировать. В общем, цель всего этого — добиться увеличения скорости выполнения в два-три раза по сравнению с обычным фоновым кодом JavaScript, хотя, чтобы овладеть приемами программирования, придется, наверное, пройти более длинный путь обучения. Чтобы воспользоваться веб-воркерами, нужны два фрагмента кода. Первый, как показано в примере 14.4 — это веб-документ, содержащий некий код JavaScript, который в данном случае – первая часть программы, максимально быстро генерирующей простые числа.
218 | Глава 14 Пример 14.4 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Running Webworkers</title> </head> <body> <p> The highest prime number discovered so far is: <output id='result'></output> <p> <button onclick='worker.terminate()'>STOP</button> </p> </p> <script> if (!window.Worker) { alert("Web workers not supported") } else { worker = new Worker('worker.js') worker.onmessage = function(event) { document.getElementById('result').innerHTML = event.data } } </script> </body> </html> Сам по себе этот документ HTML5 довольно прост. Но следует отметить наличие в строке 10 тега <output>, в котором будут отображаться найденные простые числа, и тега <button> в строке 12, изображающего кнопку, с помощью которой веб-воркер может быть остановлен, чтобы он не уходил в вечность, а также раздел кода script между строками 17 и 29. Кнопка STOP для объекта worker, созданного в разделе script, просто вызывает функцию terminate(), приводящую к немедленному прекращению его выполнения. В разделе сценария script в строках с 17 по 20 используется инструкция if(), позволяющая проверить, поддерживаются ли веб-воркеры браузером. Они должны поддерживаться всеми современными браузерами, но этот код убеждается в этом, и в противном случае выдает предупреждение.
Локальное хранилище и многое другое | 219 Затем в разделе else, куда управление передается, если веб-воркеры поддерживаются, создается новый объект worker, для чего вызывается функция Worker(), которой передается имя файла worker.js для его загрузки и запуска. Как выглядит код в файле worker.js, мы вскоре увидим. И наконец, событие onmessage объекта worker связывается с использованием безымянной функции, вход в которую происходит при каждом получении объектом worker этого документа сообщения из кода документа worker.js. Какое бы сообщение ни было получено, оно поступает в свойство data объекта event в строке 27, где оно немедленно копируется в элемент <output>, который был создан в строке 10 (так что теперь стало понятно, для чего он был нужен). А теперь давайте перейдем к программе worker.js, код которой показан в примере 14.5. Файл сохранен в прилагаемом к книге архиве под именами example_05.js и worker.js, поэтому ссылка на worker.js в строке 23 примера 14.4 будет работать. Пример 14.5 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. n = 1 search: while (true) { ++n for (i = 2 ; i <= Math.sqrt(n) ; ++i) { if (n % i == 0) continue search } postMessage(n) } Это короткая и элегантная программа, начинающаяся с инициализации переменной n значением 1. Затем в строке 3 вводится бесконечный цикл (поскольку значение true всегда равно true), который начинает непрерывный поиск простых чисел, увеличивая n при каждым проходе цикла в строке 5, а затем выполняя проверку на простоту в строках с 7 по 10. Эта проверка проводится в цикле for() в строке 7, перебирающем каждое значение между 2 и квадратным корнем из n (поскольку нет необходимости искать что-то большее), выискивая наличие делителей в строке 9. Если имеются какие-либо делители, то n не простое число, поэтому выдается инструкция continue, чтобы снова пройти цикл search в строке 3, проверяя следующее значение n. Если у n нет делителей, то n — простое число, поэтому выполнение переходит к строке 12, где сообщение отправляется обратно в основную часть пары программ веб-воркера с вызовом функции postMessage(), содержащей в качестве аргумента только что найденное простое число.
220 | Глава 14 И наконец, в строке 13 код возвращается к бесконечному циклу в строке 3, чтобы продолжить поиск. В результате все выглядит так, как показано на рис. 14.4, где кнопка STOP предназначена для быстрой остановки рабочего процесса, поскольку он находится в бесконечном цикле, и в противном случае его было бы очень непросто остановить. Рис. 14.4. Выполнение проверки на принадлежность к простым числам Автономные веб-приложения Идея автономного веб-приложения заключается в том, что при посещении вебсайта браузер узнает о всех используемых сайтом файлах, которые затем он может загрузить, после чего веб-приложение можно будет запускать локально без подключения к Интернету. Использование автономных веб-приложений не обошлось без некоторых трудностей. Им может потребоваться настроить веб-сервер с правильными MIME-типами (изначально эта аббревиатура означала Multipurpose Internet Mail Extensions — многоцелевые расширения электронной почты Интернета, но со временем слово «Mail» было заменено на «Media») для браузера, разбирающегося в автономных веб-приложениях, чтобы он смог воспользоваться функцией и извлекать нужные ему файлы. Если используется веб-сервер, отличный от Apache, узнайте из системного руководства, как добавить MIME-тип text/cache-manifest для расширений файлов .appcache, чтобы сервер отправлял файл манифеста, используя правильный тип. А для пользователей Apache (и вас в том числе, если используется сервер MAMP, настроенный в главе 3 «Visual Studio Code») есть более легкий путь, заключающийся в создании файла с именем .htaccess в той же папке, что и файлы с доступом в автономном режиме, со следующим содержимым: AddType text/cache-manifest .appcache Как работают автономные веб-приложения Рассмотрим порядок работы автономных веб-приложений. Можно начать с файла манифеста с перечислением всех предлагаемых вами для автономного использова-
Локальное хранилище и многое другое | 221 ния файлов, содержащий код, похожий на показанный ниже в примере 14.6 и сохраненный под именем clock.appcache. Пример 14.6 1. 2. 3. 4. 5. CACHE MANIFEST # clock.appcache clock.html clock.css clock.js В манифесте перечислены три файла: первым указан clock.html, показанный в примере 14.7 (в котором есть ссылка на clock.appcache), затем указаны файл сценария с именем clock.js и файл таблицы стилей с именем clock.css. А в теле документа имеется элемент <output>, в котором JavaScript впоследствии будет обновлять показания времени. Пример 14.7 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. <!DOCTYPE html> <!-- clock.html--> <html manifest='clock.appcache'> <head> <meta charset="utf-8"> <title>Offline Web Apps</title> <script src='clock.js'></script> <link rel='stylesheet' href='clock.css'> </head> <body> <p>The time is: <output id='clock'></output></p> </body> </html> В примере 14.8 показан код файла clock.css, представляющий собой CSS-таблицу, необходимую для стилизации вывода. Конечно, стилей в этом примере немного, но зато теперь имеются все файлы, необходимые для создания большинства автономных веб-приложений, и CSS-таблицу можно будет изменять и дополнять по мере необходимости. Пример 14.8 1. output { font-weight:bold; } /* clock.css */ В примере 14.9 показан JavaScript-код файла clock.js, устанавливающий с помощью функции setInterval() периодический интервал, позволяющий вызывать содержащийся в ней код каждые 1000 мс (или один раз в секунду). При каждом вызо-
222 | Глава 14 ве этого кода происходит простое копирование последних данных даты и времени в свойство innerHTML элемента clock, получаемых путем создания нового объекта с использованием кода new Date(). Пример 14.9 1. 2. 3. 4. 5. // clock.js setInterval(function () { document.getElementById('clock').innerHTML = new Date() }, 1000) Теперь имеются все части пазла, с помощью которых можно собрать автономное веб-приложение, поэтому давайте доведем дело до конца, загрузив файл clock.html (пример 14.7) в веб-браузер, и получим результат, похожий на тот, что изображен на рис. 14.5, где показаны полная дата и время, обновляемые каждую секунду. Рис. 14.5. Запущенное автономное веб-приложение Замысел автономных веб-приложений заключается в том, что благодаря манифесту все перечисленные файлы будут загружены и доступны для использования в автономном режиме в любой среде. Совместно они просто создают часы. Фактически, если разобраться в происходящем, здесь нет ничего сложного. Для получения подробных сведений о создании собственных автономных веб-приложений рекомендуется посетить следующие веб-сайты:  tinyurl.com/web-apps  tinyurl.com/web-apps2 Перетаскивание В HTML5 с технологией перетаскивания связано семь событий: dragstart, drag, dragover, dragenter, dragleave, drop и dragend. Сама технология предполагает использование весьма сложного и требующего глубокого понимания кода JavaScript, позволяющего решать, что нужно делать в зависимости от каждого действия, рассмотрение которого выходит далеко за рамки тематики этой книги. Но если есть интерес к использованию технологии, более подробную информацию можно найти по адресу tinyurl.com/drag-drop.
Локальное хранилище и многое другое | 223 Обмен сообщениями между документами Это еще одна высокоразвитая спецификация, предназначенная для облегчения взаимодействия документов друг с другом, которая также выходит за рамки тематики этой книги. Но теперь по крайней мере вы знаете о ее существовании, а подробности можно получить по адресу tinyurl.com /xdocmess. Заключение Эта глава завершает почти все повествование о новинках и улучшениях, присутствующих в HTML5, за исключением аудио- и видеосоставляющих HTML5, которые, возможно, представляют собой пару самых важных новых функций. Но лучшее оставлено напоследок, и подробности о них станут известны при изучении следующей главы.
ГЛАВА 15 Аудио и видео Введение Вот мы и добрались до последней главы, посвященной HTML5, где подробно рассматривается все, что нужно знать об аудио- и видеоматериалах, размещаемых на веб-сайтах. Соответствующие задачи решаются с помощью всего лишь нескольких строк HTML-кода, исключая использование всевозможных плагинов или создание сложных программ. И тем не менее, при желании можно улучшить воспроизведение мультимедиа вашими пользователями, прикрепив к аудио и видео функции JavaScript. Но, если параметры, используемые по умолчанию, вас устраивают, ничего этого делать не нужно. Практически все сводится к перетаскиванию нужных файлов форматов MP3 или MP4 в соответствующие места на вашем веб-сервере, добавлению пары строк кода в свой HTML, и к получению в результате этого своего собственного приложения по типу Spotify или YouTube. Все проще простого. Структура В этой главе рассматриваются следующие темы:  Знакомство с кодеками сжатия аудио и видео.  Выбор наиболее подходящих кодеков для ваших медиафайлов.  Приемы точной настройки воспроизведения аудио и видео.  Приемы улучшения условий воспроизведения мультимедиа с помощью JavaScript. Цели Здесь изучение особенностей HTML5 завершается ознакомлением с оставшимися двумя функциями: аудио и видео. Освоив предлагаемый материал, вы не только сможете применять приемы добавления мультимедиа на свои веб-страницы, но и завершите ознакомление со всем разделом книги, посвященным HTML5.
226 | Глава 15 Аудио в HTML5 Бурному развитию интернет-технологий не в малой степени поспособствовало стремление к поддержке воспроизведения аудио- и видеоматериала. Высокая стоимость трафика привела к разработке эффективных алгоритмов сжатия MP3-аудио и MPEG-видео, но даже при этом единственным способом загрузки файлов в разумные сроки было резкое снижение их качества. Вскоре появились предложения более высокого качества звука и видео, но для этого пользователю все же было необходимо загрузить и установить подключаемый проигрыватель, например Flash, что было далеко не самым изящным решением, сопряженным к тому же с угрозами информационной безопасности. Прогресс в этом деле зависел от разработки веб-стандартов поддержки мультимедиа непосредственно в браузере. Разумеется, у разработчиков браузеров Microsoft и Google были разные взгляды на эти стандарты, но, когда страсти улеглись, они все же договорились о подмножестве типов файлов, которые должны воспроизводиться всеми браузерами, и эти решения были введены в спецификацию HTML5. В конечном итоге появилась возможность (при условии, что кодировка аудио и видео ведется в нескольких разных форматах) загружать мультимедиа на веб-сервер, размещать пару тегов HTML на веб-странице и воспроизводить мультимедиа в любом основном браузере для настольных систем, смартфонов или планшетов, без принуждения пользователя к загрузке подключаемого модуля или к внесению каких-либо других изменений. Аудиокодеки Сам термин «кодек» означает КОдировщик-ДЕКодировщик. Им описываются функциональные возможности, предоставляемые программными средствами, выполняющими кодирование и декодирование медиаконтента, например аудио и видео. В HTML5, в зависимости от используемого браузера, доступно несколько различных наборов кодеков. Ниже перечислены кодеки, поддерживаемые тегом HTML5 <audio> (а также используемые при прикреплении звука к HTML5-видео):  AAC: Advanced Audio Encoding — это кодек с запатентованной технологией, обычно использующий файлы с расширением .aac (mime-тип: audio/aac).  FLAC: Free Lossless Audio Codec — бесплатный аудиокодек без потерь качест- ва, использующий файлы с расширением .flac (mime-тип: audio/flac).  MP3: MPEG Audio Layer 3 — кодек, использующий файлы с расширением .mp3 (mime-тип: audio/mpeg).  PCM: Pulse Coded Modulation — кодек без потерь качества, использующий фай- лы с расширением .wav (mime-тип: audio/wav или audio/wave).
Аудио и видео | 227  Vorbis: Ogg Vorbis — довольно редко поддерживаемый кодек, использующий файлы с расширением .ogg (mime -тип: audio/ogg или audio/webm). Эти типы аудио поддерживает большинство операционных систем и браузеров, за некоторыми исключениями, связанными с Safari, для Vorbis, поэтому при отсутствии веских причин для использования Vorbis лучше просто отдать предпочтение AAC или MP3 для сжатого звука с потерями, FLAC для сжатого звука без потерь или PCM для несжатого звука. В приводимых здесь примерах используются только файлы MP3, поскольку они прекрасно работают во всех современных браузерах. Воспроизведение аудио Чтобы вставить аудио на веб-страницы, можно воспользоваться новым тегом <audio> в сочетании с тегом <source>, сообщающим браузеру, где взять звук для воспроизведения. В примере 15.1 показана загрузка файла MP3 и добавление пользовательских элементов управления. Пример 15.1 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Playing Audio</title> </head> <body> <audio controls> <source src='music.mp3' type='audio/mpeg'> </audio> </body> </html> Результат выполнения кода этого примера показан на рис. 15.1. Рис. 15.1. Воспроизведение аудиофайла В строке 8 показано, что тег <audio> создается с видимыми пользовательскими элементами управления путем добавления к нему атрибута controls. Внутри тега нуж-
228 | Глава 15 но просто сообщить браузеру, откуда загрузить файл, в данном случае указан music.mp3. Дополнительно также предоставляется MIME-тип audio/mpeg, но в большинстве случаев его можно не указывать, поскольку браузер сам вырабатывает MIME-тип. Пользователи могут запускать и останавливать воспроизведение звука, перемещаться по аудиодорожке вперед и назад с помощью ползунка, изменять громкость с помощью значка динамика и, щелкнув на расположенном справа значке настроек с тремя вертикальными точками, выбрать другую скорость воспроизведения вплоть до ускоренной в два раза от исходной. Если нужно, чтобы воспроизведение медиафайла начиналось сразу же после загрузки, можно также добавить в код в строке 8 атрибут autoplay: 8. <audio controls autoplay> Можно также зациклить воспроизведение, воспользовавшись атрибутом loop: 8. <audio controls loop> Или же по мере необходимости все эти атрибуты можно указывать в сочетании и в произвольном порядке. Например, можно скрыть элементы управления, не указав атрибут controls управления, но в таком случае пользователям можно дать хотя бы способ остановки воспроизведения, если звук их начнет раздражать. В примере 15.2 показано, как можно добавить на веб-страницу пару кнопок для воспроизведения и приостановки звука. Пример 15.2 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Playing Audio with JavaScript</title> </head> <body> <audio id='music'> <source src='music.mp3' type='audio/mpeg'> </audio> <p> <button onclick='playaudio()'>Play Audio</button> <button onclick='pauseaudio()'>Pause Audio</button> </p> <script> function playaudio() { document.getElementById('music').play() }
Аудио и видео 23. 24. 25. 26. 27. 28. 29. | 229 function pauseaudio() { document.getElementById('music').pause() } </script> </body> </html> В данном случае музыка не настроена на автоматическое воспроизведение (autoplay), поэтому в строке 13 создается кнопка Play Audio, а в строке 14 — кнопка Pause Audio. Обе кнопки выдают при щелчке на них события, вызывающие либо функцию playaudio(), либо функцию pauseaudio(), определения которых приводятся в следующем разделе с кодом JavaScript. Определения этих двух функций начинаются в строках 18 и 23 соответственно, где их просто вызывают для элемента audio функции play() и pause(). Результат загрузки этого примера в браузер показан на рис. 15.2. Рис. 15.2. Теперь воспроизведение управляется с помощью кнопок Использование других атрибутов не зависит от того, задано отображение элементов управления или нет, поэтому атрибутами autoplay и loop можно воспользоваться без каких-либо ограничений. Кроме того, чтобы не было замедлений при старте воспроизведения более объемных медиафайлов, можно добавить атрибут предварительной загрузки preload, что приведет к началу загрузки файла в память при первой же возможности, подготавливая тем самым его к немедленному воспроизведению по желанию пользователя. Видео в HTML5 С видео, как и со звуком, стало понятно, что сжатие — один из основных приоритетов для развития Интернета, но здесь пришлось столкнуться с куда более существенными трудностями. Для сравнения, используя формат MP3, можно уменьшить размер аудиофайла, потребляющего 10 Мб данных в минуту, до половины мегабайта или и того меньше без заметной потери качества. К примеру, файл music.mp3, используемый в наших примерах, имеет продолжительность звучания 26 секунд и размер всего в 457 Кб. А вот видео высокого разрешения будет на порядок больше по размеру.
230 | Глава 15 Но к нашему удовольствию, имеется множество приемов уменьшения данных о цвете, поскольку наши глаза больше реагируют на контраст, чем на цвет, а также на разбиение изображения на фрагменты, похожие друг на друга. Представьте себе облачное небо, и согласитесь, что в нем будет масса частей, похожих друг на друга, позволяющих применить к его картинке эффективное сжатие. А за счет простой фиксации изменений между кадрами можно существенно увеличить экономию данных. То есть одноминутное видео формата 1080HD, 30 кадров в секунду, которое обычно имеет размер около 1,3 Гб, можно сжать примерно до 180 МБ или еще меньше, если разрешено дальнейшее снижение качества. Как ни удивительно, но, посмотрев телевидение по подписке, например Netflix, можно убедиться, что результат подобного сжатия при качественном подходе к делу едва заметен. И все это опять же достигается с помощью кодеков, основные представители которых рассматриваются в следующем разделе. Видеокодеки Наряду с аудиокодеками, имеется целый ряд доступных видеокодеков с разной степенью поддержки в разных браузерах. Эти кодеки поставляются в разнообразных, перечисленных ниже контейнерах:  MP4: Формат мультимедийного контейнера MPEG-4 (mime-тип: video/mp4).  Ogg: Формат открытого контейнера (mime-тип: video/ogg).  WebM: Аудио-видео формат (mime-тип: video/webm). Затем в них может содержаться один из следующих видеокодеков:  H.264 или H.265: Запатентованные видеокодеки — в H.265 используется поло- винный битрейт от H.264.  Theora: Запатентованный видеокодек.  VP8 или VP9: Кодеки, подобные Theora но с открытым кодом — в VP9 исполь- зуется половинный битрейт от VP8. Современные браузеры поддерживают все вышеперечисленное, за исключением того, что OGG не полностью поддерживается во всех версиях iOS и MacOS. Поэтому при отсутствии необходимости использования OGG стоит придерживаться либо MP4, либо WebM. В приводимых здесь примерах используются только файлы MP4, поскольку их поддерживают все современные браузеры. Воспроизведение видео Воспроизведение видео ничуть не сложнее, чем воспроизведение аудио, и устроено очень похоже. В примере 15.3 показана загрузка видео для воспроизведения с поддержкой пользовательского управления.
Аудио и видео | 231 Пример 15.3 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Playing Video</title> </head> <body> <video width='320' height='240' controls> <source src='bunny.mp4' type='video/mp4'> </video> </body> </html> В этом примере в строке 8 используется тег <video>, где задаются размеры изображения 320 × 240 пикселей и добавлены пользовательские элементы управления. Затем в строке 9 указывается имя воспроизводимого видеофайла bunny.mp4 и указывается необязательный тип файла video/mp4. Обычно браузеры сами определяют MIME-тип, поэтому указывать его необязательно. Результат загрузки кода примера в браузер показан на рис. 15.3. Как ни удивительно, но благодаря используемому кодеку все это двухминутное видео имеет размер всего 10 Мб. Рис. 15.3. Загрузка видео с пользовательскими элементами управления Пользовательские элементы управления для видео предоставляют больше возможностей, чем для аудио. Здесь имеется регулятор громкости, кнопка воспроизведения и паузы, а также значок для отображения видео в полноэкранном режиме. Более того, щелкнув на значке настроек (с тремя вертикальными точками справа), пользователи могут выбрать загрузку видео, изменение скорости воспроизведения
232 | Глава 15 с четверти от исходной скорости до ее двойного ускорения или даже выведение воспроизведения в режим «картинка в картинке» с уводом картинки в угол рабочего стола (хотя в мобильных браузерах эта последняя функция недоступна). Если нужно получить немедленный запуск медиафайла, можно также добавить в код строки 8 атрибут autoplay: 8. <video width='320' height='240' controls autoplay> Можно также зациклить видео, указав атрибут loop: 8. <video width='320' height='240' controls loop> Или же при необходимости можно указывать сочетание всех этих атрибутов в произвольном порядке. Например, можно скрыть элементы управления, не указав атрибут controls, и все же предоставить в этом случае своим пользователям хотя бы способ остановки воспроизведения. В примере 15.4 показан способ добавления на веб-страницу пары кнопок, с помощью которых можно запускать и приостанавливать воспроизведение видео. Пример 15.4 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Playing Video with JavaScript</title> </head> <body> <video id='bunny' width='320' height='240'> <source src='bunny.mp4' type='video/mp4'> </video> <p> <button onclick='playvideo()'>Play Video</button> <button onclick='pausevideo()'>Pause Video</button> </p> <script> function playvideo() { document.getElementById('bunny').play() } function pausevideo() { document.getElementById('bunny').pause() } </script> </body> </html>
Аудио и видео | 233 Структурно этот пример практически идентичен примеру 15.2, но с видео вместо аудио. В строках с 8 по 10 загружают видео без отображения пользовательских элементов управления, а в строках 13 и 14 добавляются кнопки для запуска и приостановки воспроизведения видео, а функции, определение которых начинается в строках 18 и 23, выполняют фактическое воспроизведение и приостановку, вызывая в свою очередь функции play() и pause() в отношении элемента video. Результат выполнения этого кода показан на рис. 15.4. Рис. 15.4. Теперь воспроизведение видеоконтента управляется с помощью кнопок, связанных с функциями JavaScript Использование других атрибутов не зависит от того, задано отображение элементов управления или нет, поэтому атрибутами autoplay и loop можно пользоваться без каких-либо ограничений. Кроме того, чтобы не было замедлений при старте воспроизведения более объемных медиафайлов, можно добавить атрибут предварительной загрузки preload, что приведет к началу загрузки файла в память при первой же возможности, подготавливая его тем самым к немедленному воспроизведению по желанию пользователя. Кроме того, при работе с видео имеется ряд дополнительных атрибутов, недоступных для аудио, от отключения звукового сопровождения с помощью атрибута muted, выбора изображения для заставки в окне последующего воспроизведения видео с помощью атрибута poster, и, как уже было показано, до задания ширины и высоты кадра, используемого для отображения видео с помощью атрибутов width и height . Стоит также напомнить, что для предоставления пользователям полноэкранного режима просмотра не нужен никакой код JavaScript, поскольку он уже встроен в программное средство воспроизведения видео. Предоставление пользователям элементов управления позволяет им, как показано на рис. 15.5, войти в этот режим по щелчку на соответствующем значке.
234 | Глава 15 Рис. 15.5. Видео в режиме полноэкранного воспроизведения При желании перевести видео в полноэкранный режим можно также с помощью простого кода JavaScript, показанного в примере 15.5, являющего скорректированной версией кода примера 15.4, но с наличием дополнительной кнопки в строке 15, на которой пользователь должен щелкнуть, чтобы перейти в полноэкранный режим, и соответствующей функции JavaScript, определение которой начинается в строке 29. Пример 15.5 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>JavaScript and Full Screen</title> </head> <body> <video id='bunny' width='320' height='240'> <source src='bunny.mp4' type='video/mp4'> </video> <p> <button onclick='playvideo()'>Play Video</button> <button onclick='pausevideo()'>Pause Video</button> <button onclick='fullvideo()'>Full Screen</button> </p> <script> function playvideo()
Аудио и видео 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. | 235 { document.getElementById('bunny').play() } function pausevideo() { document.getElementById('bunny').pause() } function fullvideo() { document.getElementById('bunny').requestFullscreen() } </script> </body> </html> Здесь интереснее всего то, что для выполнения задуманного будет вполне достаточно вызова для видео в строке 31 функции requestFullScreen(). Если загрузить эту версию примера в браузер, результат будет такой же, как на рис. 15.6. Рис. 15.6. На страницу добавлена кнопка полноэкранного режима «Full Screen» Странно, что даже если элементы управления в элементе <video> не были выбраны, и пользователи решат войти в полноэкранный режим, им в этом режиме также будет представлен полный набор элементов управления, и, похоже, изменить такое поведение не представляется возможным.
236 | Глава 15 Заключение Ну вот и все! Теперь изучены все нововведения, добавленные в HTML спецификацией HTML5, включая высокоэффективные аудио- и видеофункции, которых раньше очень не хватало. Вы должны гордиться освоением новых знаний и овладением практическими навыками, позволяющими усовершенствовать ваши собственные проекты. А теперь настал черед освоения другой важной части современной веб-разработки, и в следующей главе, а по сути в следующем разделе этой книги, предстоит изучение всех нововведений, добавленных в CSS спецификацией CSS3.
ГЛАВА 16 Введение в CSS3 Введение Итак, половина книги уже прочитана, усвоен большой объем новой информации. Теперь вы уже должны стать мастером работы с различными функциями HTML5, так давайте же сопоставим приобретенные вами знания со всеми новинками CSS3. Предполагается наличие у вас базовых знаний CSS2, поэтому в этом разделе книги предстоит поэтапное освоение особенностей CSS3. Ссылаясь на прежние функции CSS2, будут поочередно рассматриваться функции CSS3, и даже при поверхностных прежних знаниях можно будет усвоить новый учебный материал. Вас ждет весьма увлекательное обучение, поскольку в CSS3 очень много новых и динамичных функций, порой выходящих за рамки представлений о возможном без участия сценариев JavaScript. Структура В этой главе рассматриваются следующие темы:  Полный обзор всех новых функций, добавленных в CSS3.  Ответ на вопрос, как и почему CSS находится в стадии разработки.  Введение в курс всех новых, эффективных и доступных инструментов стилизации.  Изучение основ каждого из этих инструментов до их практического освоения. Цели Цель главы — дать полное представление о причинах и направлениях непрекращающегося развития CSS, и о текущем и будущем состоянии дел и вероятных отдаленных перспективах. Изучив предлагаемый материал, вы будете точно знать, какие типы новых вариантов оформления стилей доступны в CSS3, и подготовитесь к изучению всех их особенностей в остальной части этого раздела.
238 | Глава 16 Разработка CSS3 продолжается Впервые мысль о применении CSS появилась где-то в 1996 году, после чего понадобилось несколько лет, чтобы собрать первый релиз этих таблиц в 1999 году. К 2001 году поддержкой CSS обзавелись все новые браузеры, поскольку по сравнению с веб-страницами, состоящими только из HTML, это был вполне логичный шаг вперед, предлагающий возможности, о которых давно мечтали веб-разработчики. Но и этого было недостаточно, поскольку аппетиты интернет-пользователей были гораздо шире, и выражались в потребностях более эффективных и динамичных функций. Со временем контент разрастался, поэтому CSS2, над которыми уже работали в конце 1990-х, еще до того, как был выпущен сам CSS (да, вот как невероятно быстр рост этих технологий), стал стандартом примерно в 2007 году и снова был пересмотрен в 2009 году. Итак, существованием как CSS, так и CSS2 отметилась вторая половина первого десятилетия нового тысячелетия, но даже их уже было недостаточно. К счастью, уже к началу 2001 года началась работа над CSS3, продолжавшаяся около 10 лет, и даже сейчас время официального завершения спецификации CSS3 еще не настало, хотя она и превратилась в набор функций, поддерживаемый всеми современными браузерами. Бытуют утверждения, что CSS3 никогда не достигнет финальной стадии и что эта спецификация, в силу своей модульности позволяющая добавлять в нее все новые и новые независимые модули, будет находиться в стадии постоянной разработки. Но вполне вероятно, что в какой-то момент времени та или иная компания выступит за то, чтобы текущие возможности CSS3 были зафиксированы, высечены, так сказать, в камне, а другие разработчики последуют их примеру и согласятся с тем, что будущие расширения должны уже стать спецификацией CSS4. И все же, похоже, этот день еще не близок. Хотя конкретных планов относительно CSS4 пока нет, автор ожидает, что в конце концов это произойдет, как и когда-нибудь (что вполне вероятно) появится и HTML6. Никто не знает, что это будет, возможно, дело дойдет до просмотра информации в виртуальной реальности! Возможно, как только уляжется вся пыль, мы вернемся к простым ссылкам на CSS и HTML, и когда это произойдет, будут иметься в виду все функции, поддерживаемые в настоящее время этими двумя технологиями. А тем временем, разработка CSS3 все еще находится в развитии, поэтому за время присутствия на магазинных полках этой книги технология пойдет еще дальше. Но пока в этом разделе книги раскрывается состояние дел на начало 2020-х годов. Если есть желание проследить текущее развитие CSS, можно быть в курсе происходящего, обратившись по следующему URL-адресу на w3.org: tinyurl.com/w3orgcss
Введение в CSS3 | 239 Новое в CSS3 В этой главе состоится знакомство с новыми функциями CSS3, а также со множеством рисунков, иллюстрирующих их назначение и способы применения. На пробу и проработку есть также файлы примеров, позволяющие глубже разобраться в функциях и пользоваться кодом без его ручного ввода. Все они доступны в прилагаемом к книге бесплатном архиве. Знакомство с новинками позволит перейти к изучению следующих глав и, в конечном итоге, к полноценному освоению всей технологии CSS3. Итак, давайте взглянем на сложившуюся картину спецификации CSS3 в ее нынешнем виде и посмотрим, какие новые функции доступны для использования прямо сейчас, включая усовершенствованные селекторы атрибутов, фоновые решения, границы, тени блоков, перетекания, настройки цвета и прозрачности, макеты столбцов, текст и шрифты, размеры полей, перемещения, преобразования и многое другое. Не говоря уже о Flexbox-разметке и сетке CSS Grid. Селекторы атрибутов В CSS3 в селекторы атрибутов за счет использования новых операторов |, ~, ^, <, $ и * внесены три усовершенствования. Как известно, CSS предлагает поддержку идентификаторов и классов с помощью символов-операторов # (решетка) и . (точка). В показанном в примере 16.1 разделе <body> содержатся две строки кода HTML в строках 13 и 14 с тегом <h1> и тегом <p>, с двумя идентификаторами с именами intro и first, и классом по имени start. Пример 16.1 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Attribute Selectors</title> <style> #intro_1 { color : red; } #first_para { font-weight : bold; } .first_line { font-style : italic; } </style> </head> <body> <h1 id='intro_1'>This is a heading</h1> <p id='first_para' class='first_line'>Welcome to my website</p> </body> </html>
240 | Глава 16 CSS-код, используемый для стилизации этого HTML в строках с 7 по 9, имеет вполне стандартный вид. Но новые селекторы атрибутов позволяют делать такие вещи, как замену существующего CSS на следующий, после того как выяснится, что значение начинается со строкового значения (intro…), заканчивается строковым значением (…para) или просто содержит строковое значение (… t_l…), в следующем порядке: 7. 8. 9. h1[id ^= 'intro'] { color : red; } p[id $= 'para' ] { font-weight : bold; } p[class *= 't_l' ] { font-style : italic; } Результат в обоих случаях будет выглядеть так, как показано на рис. 16.1. Рис. 16.1. Простая стилизация двух элементов Как уже упоминалось, можно воспользоваться и другими операторами, но эти три дадут общее представление о том, как они работают. Дополнительные сведения о селекторах атрибутов приведены в главе 17 «Селекторы атрибутов CSS3». П РИМЕЧАНИЕ Для удобства чтения в код CSS добавляются дополнительные пробелы, чтобы столбцы и атрибуты располагались друг под другом. Такой прием можно взять на вооружение в качестве хорошей привычки при разработке собственных вебсайтов, но расположение пробелов полностью зависит от ваших предпочтений или же от требований вашего работодателя к стилю и комментариям. Фоновые решения В CSS3 добавили несколько новых способов создания фона, в том числе возможность изменять источник фона, указывать, как должны отображаться границы относительно фоновых изображений, области отсечения и использование нескольких фоновых изображений, как в примере 16.2.
Введение в CSS3 | 241 Пример 16.2 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Backgrounds</title> <style> .border { font-family : 'Times New Roman'; font-style : italic; text-align : center; padding : 60px; width : 250px; height : 300px; background : url('b1.gif') top left url('b2.gif') top right url('b3.gif') bottom left url('b4.gif') bottom right url('ba.gif') top url('bb.gif') left url('bc.gif') right url('bd.gif') bottom </style> </head> <body> <center> <div class='border'> <h1>Certificate of<br>Attendance</h1> <h2>Awarded To:</h2> <h3>__________________</h3> <h2>Date:</h2> <h3>___/___/_____</h3> </div> </center> </body> </html> no-repeat, no-repeat, no-repeat, no-repeat, repeat-x, repeat-y, repeat-y, repeat-x } На рис. 16.2 показан пример использования сразу нескольких таких функциональных возможностей, реализованных на основе кода этого примера. Как показано в строках с 14 по 21, граница состоит из восьми отдельных изображений, которые органично компонуются друг с другом. Как это работает, наряду с другими функциями создания фона, будет рассмотрено в главе 18 «Создание фона».
242 | Глава 16 Рис. 16.2. Граница, созданная с использованием сразу нескольких изображений Границы В предыдущем разделе было показано, как граница создается с использованием сразу нескольких фоновых изображений, но в CSS3 есть также несколько новых способов применения к границам цветовых решений и использования изображений в качестве границ, включая предоставление значений радиуса для создания закругленных границ. В примере 16.3 те же самые изображения, которые используются для создания фона в предыдущем примере, были собраны в единое изображение (показанное на рис.16.3). Затем части изображения извлекаются одна за другой и помещаются в настоящую границу (а не во внешнюю часть фона, как в предыдущем примере), в результате возникает изображение, показанное на рис. 16.4. Основное усовершенствование, показанное в примере 16.3, заключается в том, что используется только одно изображение, что упрощает задачу.
Введение в CSS3 Рис. 16.3. Файл border.png Рис. 16.4. Изображение border.png было расширено в границы элемента Пример 16.3 1. 2. 3. 4. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> | 243
244 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. | Глава 16 <title>Border Image</title> <style> .border { font-family : 'Times New Roman'; text-align : center; padding : 33px; width : 100px; height : 150px; border-width : 102px; border-style : dotted; border-image : url('border.png') 102; } </style> </head> <body> <center> <div class='border'> <h3>A</h3> <h2>One&nbsp;Image</h2> <h3>Border</h3> </div> </center> </body> </html> Этот пример очень похож на пример 16.2, отличаясь от него в основном в разделе <style>. Способ получения показанного результата подробно рассматривается в главе 19 «Построение границ». А теперь посмотрите на строку 15, где загружается единственный файл border.png и назначаются размеры для его применения к границе. Изображение имеет размеры 205 x 205 пикселей, поэтому значение 102 приводит к извлечению четырех углов по 102 x 102 пикселей каждый, а затем верх, низ и стороны составляются из небольших частей изображения, не используемых углами. Получается ничуть не сложнее, чем с какой-либо другой инструкцией стилизации <div>. И все же следует понимать, что строка 14 необходима для исправления «ошибки», из-за которой некоторые браузеры могут не отображать изображения границ, если для атрибута border-style установлено значение none (или же если ширина границы равна 0, что в данном случае не так). Как бы то ни было, если по какой-либо другой причине изображение не загрузится, то, по крайней мере, теперь для отображения есть своего рода резервная граница. Тени блоков В CSS3 теперь можно размещать тени позади элементов, используя различные значения цвета, смещения и размытия, т. е. можно дать тончайший намек на тень, будто элемент находится под прямыми солнечными лучами, и все это с применением
Введение в CSS3 | 245 всего лишь одной инструкции. В примере 16.4 создается элемент, в котором ничего нет, но есть его граница с тенью позади него, смещенной вниз и вправо. Пример 16.4 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Box Shadows</title> <style> .box { width : 500px; height : 140px; border : 10px solid #800; } .shadow1 { box-shadow : 15px 15px 10px #888; } </style> </head> <body> <center> <div class='box shadow1'></div> </center> </body> </html> В строке 12 задается применение тени к элементу <div>, а в предыдущих инструкциях устанавливаются размеры блока и применяется граница. Можно даже в соответствии с описаниями в главе 20 «Свойства блока и текста» создать тень внутри элемента. Результат выполнения кода примера показан на рис. 16.5. Рис. 16.5. Элемент с тенью позади него
246 | Глава 16 Столбцы и перетекания Кроме этого, в главе 20 «Свойства блока и текста» рассматривается применение нескольких столбцов, показанное в примере 16.5. Пример 16.5 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Multiple Columns</title> <style> .columns { text-align : justify; font-size : 16pt; column-count : 3; column-gap : 1em; column-rule : 1px solid black; } </style> </head> <body> <div class='columns'> Now is the winter of our discontent Made glorious summer by this sun of York; And all the clouds that lour'd upon our house In the deep bosom of the ocean buried. Now are our brows bound with victorious wreaths; Our bruised arms hung up for monuments; Our stern alarums changed to merry meetings, Our dreadful marches to delightful measures. Grim-visaged war hath smooth'd his wrinkled front; And now, instead of mounting barded steeds To fright the souls of fearful adversaries, He capers nimbly in a lady's chamber To the lascivious pleasing of a lute. </div> </body> </html> Результат загрузки кода этого примера в браузер показан на рис. 16.6. Существуют также различные способы управления перетеканием внутри и снаружи элемента, но соответствующий пример слишком объемный и его обсуждение будет приводиться в главе 20 «Свойства блока и текста».
Введение в CSS3 | 247 Рис. 16.6. Текст из шекспировского «Ричарда III», перетекающий по столбцам Цвета и прозрачность В CSS3 предлагается целый ряд новых способов обработки цветовых настроек и прозрачности, включая выбор между использованием цветов из пространства Red, Green, Blue (RGB) или цветового пространства Hue, Saturation, Luminance (HSL). И здесь важно понимать, что именно используется, поскольку, к примеру, зеленый цвет в HSL не совпадает с зеленым цветом в RGB. В примере 16.6 в CSS с применением контейнера <div> создается цветовой круг и конические градиенты. Пример 16.6 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Color Wheel</title> <style> .color-wheel { width : 600px; height : 300px; border-radius : 50%; background : conic-gradient(red, yellow, lime, aqua, blue, magenta, red); </style> </head> <body> <center> <div class="color-wheel"></div> </center> </body> </html>
248 | Глава 16 Подробнее цвета HSL и RGB будут рассматриваться в главе 21 «Цвета и прозрачность», и там же прозрачность будет использоваться с различными вариациями этого цветового круга, показанного на рис. 16.7. Рис. 16.7. Цветовой круг с коническими градиентами Текстовые эффекты и шрифты В главе 22 «Текстовые эффекты и шрифты» будут рассматриваться всевозможные текстовые эффекты, доступные в CSS3, включая применение теней, изменение размера, создание контуров и использование веб-шрифтов, к примеру, показанных на рис. 16.8 бесплатно предоставляемых компанией Google в количестве свыше 1200 семейств. В примере 16.7 загружается несколько образцов шрифтов Google, которые затем используются для отображения текста. Пример 16.7 1. 2. 3. 4. 5. 6. 7. 8. 9. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Web Fonts</title> <style> .cantarell { font-family : "Cantarell", .droidsans { font-family : "Droid Sans", .inconsolata { font-family : "Inconsolata", sans-serif; } sans-serif; } monospace; }
Введение в CSS3 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. | 249 .lobster { font-family : "Lobster", fantasy, serif; } .nobile { font-family : "Nobile", sans-serif; } .reenie { font-family : "Reenie Beanie", cursive, serif; } .tangerine { font-family : "Tangerine", cursive, serif; } .yanone { font-family : "Yanone Kaffeesatz", sans-serif; } html { font-size : 42pt; } </style> <link rel='stylesheet' type='text/css' href= 'http://fonts.googleapis.com/css?family=Cantarell'> <link rel='stylesheet' type='text/css' href= 'http://fonts.googleapis.com/css?family=Droid+Sans'> <link rel='stylesheet' type='text/css' href= 'http://fonts.googleapis.com/css?family=Inconsolata'> <link rel='stylesheet' type='text/css' href= 'http://fonts.googleapis.com/css?family=Lobster'> <link rel='stylesheet' type='text/css' href= 'http://fonts.googleapis.com/css?family=Nobile'> <link rel='stylesheet' type='text/css' href= 'http://fonts.googleapis.com/css?family=Reenie+Beanie'> <link rel='stylesheet' type='text/css' href= 'http://fonts.googleapis.com/css?family=Tangerine'> <link rel='stylesheet' type='text/css' href= 'http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz'> </head> <body> <div style='float:left; margin-right:10px;'> <div class='cantarell' >Cantarell</div> <div class='droidsans' >Droid Sans</div> <div class='inconsolata'>Inconsolata</div> <div class='lobster' >Lobster</div> </div> <div> <div class='nobile' >Nobile</div> <div class='reenie' >Reenie Beanie</div> <div class='tangerine' >Tangerine</div> <div class='yanone' >Yanone Kaffeesatz</div> </div> </body> </html> Результат загрузки этого примера в браузер будет выглядеть, как на рис. 16.9. Нетрудно заметить, что в разделе <style> устанавливаются атрибуты семейства шрифтов, и им даются имена классов, а затем приведенные ниже теги <link> приводят к фактической загрузке этих шрифтов с серверов Google. Остается только применить в разделе <html> выбранные классы там, где нужно воспользоваться тем или иным шрифтом.
250 | Глава 16 Рис. 16.8. Скромный образец из коллекции бесплатных веб-шрифтов Google Рис. 16.9. Группа используемых шрифтов Google Перемещения и преобразования Преобразования стали невероятно мощным дополнением технологии CSS. Ими в сочетании с CSS3-анимацией можно воспользоваться не только для создания прак-
Введение в CSS3 | 251 тически всего, на что только хватит фантазии, но также и для создания потрясающих ролловеров и получения других интерактивных и динамичных эффектов. В примере 16.8 создается элемент <div>, который окрашивается, обрамляется и заполняется текстом. Затем к нему применяется поворот на 45 градусов, вызываемый инструкцией в строке 13. Рис. 16.10. Применение к элементу 2D-вращения Пример 16.8 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Transformations</title> <style> .box { font-size : 14pt; width : 100px; height : 100px; background: yellow; border : 6px solid blue; transform : matrix(1, 1, -1, 1, 0, 0); } </style> </head> <body> <center> <br><br><br><br> <div class='box'> This box has been rotated clockwise by 45 degrees
252 21. 22. 23. 24. | Глава 16 </div> </center> </body> </html> Результат выполнения кода показан на рис. 16.10. Как это работает, будет подробно объяснено в главе 23 «Преобразования 2D». А затем, когда настанет время изучения 3D-преобразований, в главе 24 «3D и анимация» будет добавлено совершенно новое измерение. Flexbox-разметка Flexbox-разметка, будучи разработанной в 2009 году, и к 2022 году (на момент написания книги) так и остававшаяся кандидатом на включение в CSS3, получила весьма широкую реализацию во всех современных браузерах. В наши дни разработчики браузеров разбираются в полезных вещах, и стремятся предоставить своим пользователям и разработчикам новые мощные функции. Интересно, что идея Flexbox возникла по мотивам реализации в браузере Mozilla Firefox пользовательского интерфейса на основе базовых элементов макета, которые было легче спроектировать, чем пользоваться простым старым HTML. Этот интерфейс оказался настолько удачным и гибким, что стал также идеальным кандидатом в инструментарий создания веб-страниц. К 2012 году технология Flexbox достаточно устоялась, и ее функции стали включаться в большинство браузеров. Но, как уже говорилось в начале главы, CSS не стоит на месте, и пока Flexbox не приобретет окончательных очертаний и не перестанет быть просто кандидатом, некоторые из его частей все еще могут изменяться или улучшаться. И все же, по прошествии стольких лет использования этой технологии, вряд ли кому-то захочется сломать сеть и нарушить принцип обратной совместимости. Flexbox как отдельный модуль Flexbox — не какой-нибудь отдельный новый атрибут или функция, это, по сути, полноценный модуль, содержащий множество свойств и функций. Он предоставляет еще один способ реализации макетов, который порой основан на родительском элементе или элементе-контейнере, а порой — на дочернем элементе. С целью поверхностного ознакомления с тем, чего можно добиться с помощью Flexbox-разметки, в примере 16.9 показано, как Flexbox используется для создания адаптивного макета без использования атрибута float или position.
Введение в CSS3 | 253 Пример 16.9 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Flexbox</title> <style> .parent { border : solid 1px black; padding : 5px; background : red; display : flex; flex-wrap : wrap; } .child { border : solid 1px black; padding : 10px; margin : 2px; background : yellow; color : blue; font-size : 36pt; font-weight : bold; } </style> </head> <body> <div class="parent"> <div class='child'>Elem 1</div> <div class='child'>Elem 2</div> <div class='child'>Elem 3</div> </div> </body> </html> В строках с 26 по 30 этого примера содержится элемент-контейнер <div> с именем класса parent, а внутри него имеются три дополнительных элемента <div>, каждому из которых присвоено имя класса child. В наборе инструкций CSS контейнера класса parent все до строк 11 и 12 должно быть знакомо, а вот в них для свойства display указано значение flex, а для свойства flex-wrap — значение flex. Если бы этих строк не было, результат выполнения примера выглядел бы вполне ожидаемо, как показано на рис. 16.11. Но стоит только применить код из строк 11 и 12, для элементов класса child все резко переменится, и теперь, как показано на рис. 16.12, эти <div>-элементы всплывают рядом друг с другом, а кроме этого, их размеры уменьшены, чтобы соответствовать их содержимому.
254 | Глава 16 Рис. 16.11. Результат выполнения кода примера 16.9 без использования свойств Flexbox Рис. 16.12. С установкой свойств Flexbox элементы теперь всплывают рядом друг с другом Можно, конечно, спросить: а какой прок от применения технологии Flexbox, если в ней нет гибкости? Что ж, посмотрите, что произойдет, если изменить размер окна браузера, уменьшив его ширину, как показано на рис. 16.13, где дочерний элемент, уже не способный поместиться на прежнем месте, опустился на строку ниже. Это лишь одно из многих действий, которые могут назначаться макетам Flexbox, включая выравнивание по правому краю, запрещение переноса и многое другое. Нетрудно представить, что Flexbox-разметка предоставляет гораздо больше возможностей, которые будут рассматриваться в главе 25 «Flexbox-разметка». А для
Введение в CSS3 | 255 получения дополнительной информации при желании отслеживать продолжение развития Flexbox можно обратиться по следующему официальному URL-адресу: w3.org/TR/css-flexbox-1 Рис. 16.13. Уменьшение ширины окна браузера привело к перемещению последнего элемента на следующую строку CSS grid Как и Flexbox, CSS Grid представляет собой не просто отдельную функцию или атрибут, а еще один полноценный модуль CSS. Разница между ними в том, что Flexbox предназначен в основном для создания одномерных гибких макетов, а модуль CSS Grid, как это можно себе представить, предназначен для работы со столбцами и строками в макете в виде сетки. Опять же, как и в случае с Flexbox, CSS Grid исключает необходимость использования атрибута float или position. Модуль CSS Grid также находится в стадии разработки, и его первый черновой вариант был создан примерно в 2011 году разработчиками Microsoft, работавшими над Internet Explorer. Да, как ни странно, но из IE вышло нечто путное — когданибудь это ведь должно было случиться! Но оставим сарказм, поскольку по состоянию на 2017 год эту концепцию всецело поддержали разработчики всех основных браузеров, внедрив CSS Grid в свои продукты, исключение составил браузер Opera Mini, который в настоящее время не поддерживает (и, по всей видимости, не планирует поддержку) CSS Grid.
256 | Глава 16 Но чтобы прямо сейчас получить представление о возможностях данной технологии, посмотрим на код примера 16.10, где начиная со строки 28 внутри родительского (parent) <div>-элемента в строках с 29 по 37 создается макет сетки из девяти дочерних (child) <div>-элементов. Пример 16.10 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>CSS Grid</title> <style> .parent { border padding background display grid-gap grid-template-columns justify-content } .child { border padding margin background color font-size font-weight } </style> </head> <body> <div class="parent"> <div class='child'>Elem <div class='child'>Elem <div class='child'>Elem <div class='child'>Elem <div class='child'>Elem <div class='child'>Elem <div class='child'>Elem <div class='child'>Elem <div class='child'>Elem </div> </body> </html> : : : : : : : solid 1px black; 5px; red; grid; 5px; auto auto auto; space-evenly; : : : : : : : solid 1px black; 10px; 2px; yellow; blue; 36pt; bold; 1</div> 2</div> 3</div> 4</div> 5</div> 6</div> 7</div> 8</div> 9</div>
Введение в CSS3 | 257 Дочернему классу child указано такое же стилевое оформление, как и в предыдущем примере, а вот в стиль родительского класса parent в строках с 11 по 14 теперь включены инструкции, касающиеся сетки, чтобы у нее, как показано на рис. 16.14, были промежутки в 5 пикселей и автоматически назначался размер, соответствующий содержимому, и все это было равномерно распределено в отведенном пространстве. Рис. 16.14. Макет, созданный с помощью CSS Grid Рис. 16.15. Макет сетки уменьшился пропорционально ширине окна браузера
258 | Глава 16 Кроме того, как и в случае с Flexbox, макет CSS Grid, в зависимости от выбранных разнообразных и многочисленных атрибутов, может быть гибким. В данном примере, как показано на рис. 16.15, при изменении ширины окна браузера сетка будет плавно растягиваться или сжиматься. Эта настройка, конечно же, больше подходит не к изменениям ширины окна браузера, а к разным размерам ширины и высоты экрана. Но срабатывает все это в обоих случаях, максимально подстраиваясь под нужды пользователей, не теряя при этом наилучший визуальный эффект. Заключение Из всего сказанного в этой главе должно быть понятно, что особо не афишируемая масштабная разработка технологии CSS не прекращается. В следующих главах будет уделено внимание каждой из новых разработок и показаны пути их использования для выстраивания как можно более привлекательных макетов страниц.
ГЛАВА 17 Селекторы атрибутов CSS3 Введение Как известно, селекторы в CSS используются для сопоставления с элементами HTML, подлежащими той или иной стилизации. В CSS2 уже имеются селекторы идентификаторов и классов: # и . (точка), а также универсальный селектор *. Есть также и селекторы-потомки, размещаемые друг за другом, например span em, и дочерние селекторы, разделяемые символом «больше, чем», например span > em. Кроме этого, знак «плюс» (+) позволяет выбрать соседние дочерние элементы, например span + em, есть также и псевдоклассы, проверяющие происходящее, например a:hover, или выделяющие конкретную часть элемента, например p:first-letter. И наконец, есть селекторы атрибутов, позволяющие углубиться во внутреннее содержимое свойств атрибутов, например a[href = 'info.htm'], и это тот самый тип селекторов, который появился в CSS3 в качестве расширения. Структура В этой главе рассматриваются следующие темы:  Краткий обзор использования селекторов CSS2.  Причины разработки новых селекторов атрибутов CSS3.  Сведения о приемах поиска и сопоставления любых атрибутов, требующих сти- левого оформления.  Приемы сопоставления с учетом регистра символов или без его учета. Цели Цель главы — дать полное представление об использовании селекторов атрибутов CSS3 и показать их возможности и способы применения. Изучение предлагаемого материала позволит досконально разобраться в порядке применения селекторов атрибутов и вывести стилевое CSS-оформление на новый уровень.
260 | Глава 17 Селекторы атрибутов CSS А что можно придумать для повышения эффективности селекторов атрибутов? Ответов много, поскольку теперь доступны следующие операторы, где attr — атрибут, а value — проверяемое значение, а все, что между ними — оператор. Если чтото непонятно, не стоит беспокоиться, все прояснится по ходу чтения главы:  [attr]: выбор элементов с именем attr.  [attr = value]: выбор элементов с именем attr, чье значение в точности соответ- ствует value.  [attr ~= value]: выбор элементов по любому слову в строковом значении value, соответствующему списку слов в attr, разделенных пробелами.  [attr |= value]: выбор элементов по значениям attr, точно соответствующим зна- чению value или же точно соответствующим значению value, и сразу же после них содержащим дефис.  [attr ^= value]: выбор элементов по значениям attr, начинающимся со строково- го значения, содержащегося в value.  [attr $= value]: выбор элементов по значениям attr, заканчивающимся строко- вым значением, содержащимся в value.  [attr *= value]: выбор элементов по значениям attr, имеющим в своем составе строковое значение, содержащееся в value.  [attr operator value i]: когда i (или I) помещается перед закрывающей скобкой, значение сравнивается без учета регистра, при этом различия между верхним и нижним регистром символов игнорируются.  [attr operator value s]: когда s (или S) помещается перед закрывающей скобкой, значение сравнивается с учетом регистра, т. е. value должно точно соответствовать строке, и сравниваемые символы должны соответствовать как по нижнему, так и по верхнему регистру (пока что, похоже, это работает только в Firefox). Селектор по имени атрибута Разобраться в сути первой пары селекторов нетрудно, поскольку с этими селекторами уже, скорее всего, приходилось сталкиваться и, возможно, даже использовать их в своих проектах CSS2, как в примере 17.1, где просто выбирается именованный атрибут, и в данном случае это элемент <img> с атрибутом title. Пример 17.1 1. 2. 3. 4. 5. <!DOCTYPE html> <html> <head> <title>Name Attribute Selectors</title> <style>
Селекторы атрибутов CSS3 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. | 261 img[title] { border : 5px solid black; } </style> </head> <body> <center> <img src='cat.png' title='main'> <img src='cat.png'> </center> </body> </html> В строках 11 и 12 задается одно и то же отображение кошачьих глаз, но только в строке 11 применяется атрибут title. Поэтому, как показано на рис. 17.1, CSSстиль, указанный в строке 6 помещает в рамку только первое изображение, для которого указан этот атрибут. Рис. 17.1. Выбрано только первое изображение, имеющее атрибут title Селектор по значению атрибута Давайте продолжим работу с примером, проверив не только наличие атрибута, но и, как показано в примере 17.2, значение, примененное к атрибуту, где значение main у атрибута title есть только у одного элемента <img>, и именно оно и будет выбрано. Пример 17.2 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. <!DOCTYPE html> <html> <head> <title>Value Attribute Selectors</title> <style> img[title = 'main'] { border : 5px solid black; } </style> </head> <body> <center>
262 11. 12. 13. 14. 15. 16. | Глава 17 <img src='cat.png' title='main'> <img src='cat.png' title='second'> <img src='cat.png'> </center> </body> </html> Здесь, судя по коду в строках с 11 по 13, изображение выводится на экран три раза, но слово mail в значении атрибута title имеется только у экземпляра в строке 11. Вполне ожидаемый результат наличия рамки только у первого экземпляра показан на рис. 17.2, и хотя у второго экземпляра также имеется атрибут title, но его значение не совпадает с заданным, и в рамку этот элемент не помещается. Рис. 17.2. Здесь опять условию выбора соответствует только первое изображение Селектор по слову из списка Соответствие этому селектору будет соблюдаться, только если значение, следующее за селектором, будет найдено в качестве любого отдельно взятого слова в атрибуте элемента среди группы слов, разделенных пробелом. Такое обычно случается, когда к элементу, как показано в примере 17.3, одновременно применяется сразу несколько имен классов, а выбор идет только для того элемента, для которого используется имя класса main. Пример 17.3 1. 2. 3. 4. 5. 6. <!DOCTYPE html> <html> <head> <title>Word List Selector</title> <style> p[class ~= 'main'] { text-decoration : underline; }
Селекторы атрибутов CSS3 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. | 263 </style> </head> <body> <center> <p class='article main intro'>This is the first paragraph</p> <p class='article intro'>This is the second paragraph</p> <p class='article body'>This is the article body</p> </center> </body> </html> В строках с 12 по 13 задаются три элемента <p> с различными именами классов, среди которых встречаются article и intro, но только для первого элемента в строке 12 используется имя класса main. Это означает, что инструкция в строке 6 приведет к изменению только первого из этих трех абзацев, применив к нему, как показано на рис. 17.3, подчеркивание. Рис. 17.3. Соответствие найдено только в первом абзаце, текст которого и стал подчеркнутым Строку 6 можно изменить, чтобы указанное в ней условие соблюдал только элемент в строке 14, задав сопоставление со словом body, или же чтобы условие соблюдалось обоими элементами в строках 12 и 13, задав сопоставление со словом intro. Селектор по дефису Селектор по дефису аналогичен селектору по значению. Для него должно соблюдаться соответствие всей строке значения атрибута. Но может также соблюдаться соответствие и строке, за которой следует дефис. Дело в том, что некоторые значения свойств зависят от применения дефиса (значения используемого языка, например en-us и en-uk). С помощью этого селектора можно выбрать все значения, начинающиеся с en-, задав тем самым соответствие указанию на применение английского языка независимо от национальных вариаций. Именно это и задается в примере 17.4 для ограниченного набора языков.
264 | Глава 17 Пример 17.4 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. <!DOCTYPE html> <html> <head> <title>Hyphen Selector</title> <style> p[lang |= 'en'] { font-weight : bold; } </style> </head> <body> <center> <p lang='en-us'>Howdy. How's your day?</p> <p lang='gr' >Guten Tag und viel Gesundheit!</p> <p lang='en-uk'>Hello. Would you like some tea?</p> <p lang='fr' >Bonjour. Comment allez-vous?</p> </center> </body> </html> Здесь соответствие селектору, указанному в строке 6, соблюдается только в строках 11 и 13, поскольку только у них в значении имеется en-. Поэтому, как показано на рис. 17.4, полужирным шрифтом выделяются только первый и третий абзацы. Рис. 17.4. Соответствие найдено только в абзацах, для которых указан английский язык Селектор по начальным символам Если нужно найти соответствие только по нескольким символам, которые могут быть в начале значения свойства, можно воспользоваться селектором по начальным символам, показанным в примере 17.5, где в строках с 12 по 15 задаются четыре гиперссылки, а условию, заданному в строке 7, соответствуют только те из них, которые указывают на локальный сервер (и начинаются с символов /home).
Селекторы атрибутов CSS3 | 265 Пример 17.5 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. <!DOCTYPE html> <html> <head> <title>Start Selector</title> <style> body { font : 22pt Sans-Serif; } a[href ^= '/home'] { font-weight : bold; } </style> </head> <body> <center> <a href='https://google.com' >Google</a><br> <a href='/home/page1' >Page 1</a><br> <a href='https://facebook.com'>Facebook</a><br> <a href='/home/' >Home Page</a><br> </center> </body> </html> В строке 6 задается выделение текста более крупным шрифтом, чтобы он стал заметнее, и результат загрузки этого примера в браузер показан на рис. 17.5. Рис. 17.5. Выделение ссылок на локальные страницы Селектор по конечным символам Порой может потребоваться найти соответствие конечным символам строкового значения атрибута, что можно сделать, как в примере 17.6, применив селектор по конечным символам и добившись выделения только тех ссылок, которые указывают на домены .org.
266 | Глава 17 Пример 17.6 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. <!DOCTYPE html> <html> <head> <title>End Selector</title> <style> body { font : 22pt Sans-Serif; } a[href $= '.org' ], [href $= '.org/'] { font-weight : bold; } </style> </head> <body> <center> <a href='https://google.com' >Google</a><br> <a href='https://wikipedia.org' >Wikipedia</a><br> <a href='https://facebook.com' >Facebook</a><br> <a href='https://www.icann.org/'>Icann</a><br> </center> </body> </html> Как и в предыдущем примере, в четырех строках с 13 по 16 задаются гиперссылки на различные веб-ресурсы, а код в строке 6 предназначен просто для придания отображению повышенной четкости. А вот код в строках 7 и 8 интересен своей новизной. В строке 7 предназначение оператора $= (селекции по конечным символам) не вызывает сомнений и приводит к выбору любого строкового значения с окончанием .org. А вот далее стоит запятая, за которой задается еще одно выражение соответствия. Тем самым демонстрируется возможность задания сразу нескольких условий селекции путем простого разделения выражений запятой и указания через запятую любого нужно количества таких выражений. Рис. 17.6. Выделение только тех веб-доменов, которые оканчиваются на .org или .org/ В данном случае второе выражение было необходимо по той причине, что иногда копирование гиперссылки выполняется из адресной строки браузера, что часто
Селекторы атрибутов CSS3 | 267 приводит к наличию в конце URL-адреса символа /, например .org/. Это вполне приемлемо, но, чтобы выбирались и такие гиперссылки, указывается второе выражение, показанное в строке 8. Результат загрузки этого примера в браузер — на рис. 17.6. Если же в URL-адрес домена .org включены подкаталоги, то этому селектору они соответствовать не будут, поэтому в таком случае следует использовать описанный далее глобальный селектор. Глобальный селектор Если просто нужно проверить строку значения на наличие где-либо в ней произвольной последовательности символов, можно, как показано в примере 17.7, воспользоваться глобальным селектором. Здесь в строках с 14 по 17 задаются гиперссылки, в строке 16 задается ссылка на локальную папку с именем pdfs, а в строке 15 — просто ссылка на локальную папку. Пример 17.7 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. <!DOCTYPE html> <html> <head> <title>Global Selector</title> <style> body { font : 16pt Arial; } a[href *= 'pdf'] { background : url('pdf-icon.png') no-repeat; padding-left : 16px; } </style> </head> <body> <ul> <li><a href='https://google.com' >Google</a></li> <li><a href='/home/pdfs/' >Documents</a></li> <li><a href='https://facebook.com'>Facebook</a></li> <li><a href='/home/' >Home Page</a></li> </ul> </body> </html> В строке 6 просто задается увеличение размера текста, а вот в строках с 7 по 9 — кое-что, выглядящее намного эффектнее. Сначала, если где-либо в любом атрибуте href элемента <a> обнаруживается последовательность символов pdf, то в строках 8 и 9 для такого элемента задается неповторяющееся фоновое изображение в виде значка, загружаемое из файла pdf-icon.png, а затем той строке, где обнаружено такое значение атрибута, задается отступ вправо от значка в 16 пикселей. В конечном
268 | Глава 17 итоге все URL-адреса с символьной последовательностью pdf в произвольном месте получают, как показано на рис. 17.7, небольшой значок, помещаемый слева от них. Рис. 17.7. URL-адреса, имеющие отношение к файлам PDF, имеют прикрепленный к ним значок Флажок невосприимчивости к регистру символов Предыдущий пример, конечно, интересный, но не без потенциальных изъянов. В нем задается соответствие только для последовательности символов pdf, но не PDF или любой другой комбинации, не полностью составленной из символов нижнего регистра. Давайте представим, что вместо строки 7 из предыдущего примера используется другая строка, в результате чего получается код, показанный в примере 17.8, где искомое соответствие — строчная последовательность PDF с символами в верхнем регистре. Пример 17.8 (показана только измененная строка): 7. a[href *= 'PDF'] { Если загрузить код этого примера в браузер, соответствий найдено не будет, и получится результат, показанный на рис. 17.8. Но, если в ту же строку ввести маленькую поправку, чтобы получить код примера 17.9, обнаружатся соответствия любой последовательности символов PDF, независимо от того, в каком регистре будет каждый из этих символов: в нижнем или в верхнем. Пример 17.9 (показана только еще раз измененная строка): 7. a[href *= 'PDF' i] { Результат такого изменения — возврат к виду, показанному на рис. 17.8. И всего-то перед закрывающей квадратной скобкой был поставлен символ i (который также можно указывать в верхнем регистре — I), чего оказалось достаточно, чтобы выключить восприимчивость к регистру символов. Это означает, что будет найдено соответствие как прежнему строковому значению pdf, так и таким вариан-
Селекторы атрибутов CSS3 | 269 там, как pDf или PdF, и все они, в силу невосприимчивости к регистру символов, будут эквивалентны друг другу. Рис. 17.8. Когда выражение восприимчиво к регистру символов, соответствий найдено не будет Флажок восприимчивости к регистру символов И наконец, порой важно найти соответствие символам именно в верхнем и (или) нижнем регистре, для чего можно воспользоваться флажком восприимчивости к регистру символов, чтобы обеспечить соответствие по этому конкретному типу. С удовлетвоерением сообщаем, что для символов английского языка по умолчанию ищется соответствие в режиме восприимчивости к регистру символов, так что все именно так и будет происходить. Но бывает так, что возникает желание принудительно обеспечить поиск соответствия с учетом регистра символов, и в CSS уровня 4 есть спецификация, предусматривающая поддержку флажка s (или S), но проведенные автором книги исследования показали, что на момент написания книги этот флажок поддерживался только браузером Firefox. В примере 17.10 задаются три элемента <div>, в двух из которых в значениях атрибутов title используется слово DIV, составленное из символов в верхнем регистре, а в среднем элементе в значении этого атрибута имеется слово divides. Пример 17.10 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. <!DOCTYPE html> <html> <head> <title>Forced Case Sensitivity</title> <style> div[title *= "DIV" s] { background: lime; } </style> </head> <body> <div title='This is a DIV element'> First section
270 12. 13. 14. 15. 16. 17. 18. 19. 20. | Глава 17 </div> <div title='This element divides the page'> A divider </div> <div title='This is another DIV element'> Final section </div> </body> </html> При включенной невосприимчивости к регистру символов найденное соответствие DIV будет приводить к стилизации всех трех элементов, поскольку последовательности DIV и div будут считаться эквивалентными, но (по крайней мере, в браузере Firefox) только два экземпляра с символами в верхнем регистре соответствуют глобальному, чувствительному к регистру символов выражению, заданному в строке 6, о чем свидетельствует изображение на рис. 17.9, где соответствующие выбору элементы имеют фон цвета лайма. Рис. 17.9. Firefox последних версий, похоже, единственный браузер, поддерживающий принудительную установку восприимчивости к регистру символов Когда-нибудь этот пример, наверное, заработает во всех браузерах, но, если попытка его применения не сработает, значит, эту функцию ваш браузер еще не поддерживае. Исходя из всей истории разработки CSS, теперь понятно, что бывают функции, которые появятся в скором будущем, но их, наверное, лучше пока не использовать, пока не окрепнет уверенность в их работоспособности во всех браузерах — просто полагайтесь на проверку с исходной восприимчивостью к регистру символов для языка, выбранного для ваших веб-страниц. Совместимость браузера с CSS и другими функциями можно также проверить на следующем веб-сайте: https://caniuse.com Заключение Теперь в вашем арсенале инструментов задания стилей присутствует вся высокоэффективная техника применения селекторов атрибутов, а также известны все тонкости их использования и имеются сведения о том, что сегодня может, а что не может работать в конкретных браузерах. А в следующей главе нам предстоит перейти к рассмотрению приемов создания красивых фонов для веб-страниц.
ГЛАВА 18 Создание фона Введение Создание фона — важное новое дополнение в CSS3. Возможности новых функций позволяют не привязываться к одному фоновому цвету или изображению и использовать сразу несколько рисунков и накладывать на них элементы множеством способов. Атрибут border-box позволяет работать с внешним краем границы, атрибут paddingтолько до края области отступов, а атрибут content-box — только до края области содержимого страницы. Кроме этого, на основе их значений можно установить области отсечения или определить, где следует разместить источник контента. box — И наконец, с помощью CSS можно не только выбирать, где размещать содержимое, но и определять его отношение к фону и порядок взаимодействия с ним. Эта тема, поскольку в ряде примеров используются литералы шаблонов, очень хорошо подходит к демонстрации приемов размещения кода HTML в JavaScript-разделе документа; они позволяют вставлять переменные непосредственно в HTML-код. Благодаря этому можно будет понять, как вывести вашу веб-разработку на совершенно иной уровень. Структура В этой главе рассматриваются следующие темы:  Изучение различных типов доступных фонов.  Освоение способов использования для кода HTML литералов шаблонов.  Изменение способа отображения фона в элементе.  Изучение порядка использования градиентов вместо сплошного фона или изо- бражений. Цели В этой главе подробно рассматриваются все новые функции создания фона, доступные в CSS3, включая использование изображений и градиентов. Изучив предла-
272 | Глава 18 гаемый материал, вы сможете стилизовать фон любого желаемого элемента множеством интересных способов. Попутно можно будет открыть для себя возможности применения шаблонов с использованием JavaScript. Обрезка и начало фона В CSS уже имелась поддержка фонов, но только в пределах областей блочной модели. Теперь же, в CSS3, она входит с двумя новыми свойствами: background-clip и background-origin. Они позволяют указать начало фона внутри элемента, а также где обрезать фон, чтобы его не было в тех или иных частях блочной модели элемента. Оба свойства поддерживают следующие атрибуты:  border-box: относится к внешнему краю границы элемента  padding-box: относится к внешнему краю внутреннего отступа элемента  content-box: относится к внешнему краю области содержимого элемента Появилось также и новое свойство размера фона background-size, позволяющее поддерживать сразу несколько фоновых решений. Давайте начнем с рассмотрения новых свойств обрезки и начала фона. Но, поскольку один из самых эффективных инструментов создания шаблонов, литералы шаблонов, уже встроен во все современные браузеры, с ним и нужно познакомиться в первую очередь. Литералы шаблонов Конечно, в создании фона с применением литералов нет ничего необычного, но именно здесь в книге этот способ может найти себе применение, поэтому, прежде чем продолжить тему создания фона, давайте разберемся в том, что это такое. Знакомство с такими началами JavaScript, как переменные и массивы, уже состоялось. Нетрудно вспомнить, что им можно присваивать числовые или строковые значения (а также значения многих других типов). В примере 18.1, начиная со строки 11, двум переменным, name и title, присваиваются, соответственно, строковые значения Robin и Web Developer. Пример 18.1 1. 2. 3. 4. 5. 6. 7. 8. <!DOCTYPE html> <html> <head> <title>String Concatenation</title> </head> <body> <h1> <output id='output'></output>
Создание фона 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. </h1> <script> name title string string = = = += | 273 'Robin' 'Web Developer' 'My name is ' + name ' and I am a ' + title document.getElementById('output').innerHTML = string </script> </body> </html> Затем в строках 13 и 14 с помощью оператора + эти значения переменных объединяются в более длинную строку. В JavaScript этот оператор при использовании со строками приводит к их объединению. В строке 13 сочетанием присваивания и конкатенации создается первая половина длинной строки. А в строке 14 используется оператор += , представляющий собой сокращенный способ добавления в конец предыдущей строки. Например, вместо использования выражения string1 = string1 + string2 можно воспользоваться более короткой формой записи string1 += string2. Затем полученный результат вставляется в HTML-элемент <output>, имеющий идентификатор output. Это делается в строке 16 с помощью инструкции, которая уже встречалась в аналогичных местах книги. Результат загрузки этого документа в браузер показан на рис. 18.1. Рис. 18.1. Объединение и отображение строки средствами JavaScript Все это обычный код JavaScript, но его можно упростить еще больше, воспользовавшись литералами шаблонов, представляющими собой средства вставки значений переменных непосредственно в строки JavaScript без использования присваиваний или конкатенаций. Их работа осуществляется за счет применения вместо одинарных или двойных кавычек символа обратного апострофа `. На многих клавиатурах его можно найти слева от клавиши 1. Когда строка заключается в обратные апострофы, JavaScript получает команду вычислить любое содержимое внутри выражения ${…}, и заменить выражение вычисленным результатом. Пример 18.2 — переделка предыдущего примера.
274 | Глава 18 Пример 18.2 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. <!DOCTYPE html> <html> <head> <title>Template Literals</title> </head> <body> <h1> <output id='output'></output> </h1> <script> name = 'Robin' title = 'Web Developer' document.getElementById('output').innerHTML = `My name is ${name} and I am a ${title}` </script> </body> </html> Присмотревшись к строке 15, можно увидеть, что строка, вставляемая в HTML-код элемента <output>, заключена в пару одиночных обратных апострофов, а имена двух переменных, name и title, помещены в выражения ${…}, в результате чего отображаемый результат идентичен показанному на рис. 18.1. Мало того, что это простая строка, которая не требует пояснений (если уже известно, что такое литералы шаблонов), она делает ненужными строки 13 и 14 предыдущего примера. Короче говоря, получился готовый HTML-шаблон для работы с любыми значениями, которые могут содержаться в этих переменных. Надеюсь, этот простой трюк впечатлил вас своей эффективностью, позволяющей использовать JavaScript в качестве языка шаблонов, а также всем остальным, что может вам пригодиться. Кроме того, любой специалист, занимающийся поддержкой ваших проектов, поблагодарит вас за это. Использование свойства background-clip Завершив изучение краткого руководства по шаблонам, давайте расширим свои познания в создании фона, изучив применение атрибутов background-clip и background-origin. Первый из них указывает, следует ли игнорировать (не показывать) фон, если он появляется либо в области границы, либо в области внутреннего отступа элемента. Он поддерживает три ранее рассмотренных значения: border-box, padding-box и content-box.
Создание фона | 275 Например, следующее указание гласит, что фон должен отображаться во всех частях элемента вплоть до внешнего края его границы: background-clip:border-box; Или же, если нужно не показывать фон в любой части области границы элемента, можно воспользоваться следующим указанием: background-clip:padding-box; И наконец, если фон не нужно показывать нигде, кроме области содержимого элемента, можно воспользоваться следующим указанием: background-clip:context-box; Атрибут background-clip в равной степени применяется как к цветовой настройке фона, так и к фоновым изображениям. Использование свойства background-origin Указать смещение от верхнего левого угла элемента фонового изображения можно как в сочетании со свойством background-clip, так и без него. Это делается с помощью атрибута background-origin, в котором также поддерживаются три ранее описанных значения: border-box, padding-box и content-box. Например, следующее указание задает отображение фона с верхним левым углом точно в верхнем левом углу границы элемента: background-origin:border-box; Если нужно, чтобы верхний левый угол изображения отображался точно в верхнем левом углу области внутреннего отступа элемента, можно воспользоваться следующим указанием: background-origin:padding-box; Если же нужно, чтобы верхний левый угол изображения отображался точно в верхнем левом углу внутренней области содержимого элемента, можно воспользоваться следующим указанием: background-origin:content-box; Атрибут background-origin влияет только на фоновые изображения, не касаясь цветового оформления фона. Совместное использование обрезки и начала фона Разобравшись с тем, как работать с исходными изображениями и обрезать фоновые изображения, нужно посмотреть, как эти два свойства работают вместе во всех возможных комбинациях. Всего есть девять комбинаций, составляемых из трех значений, поддерживаемых при обрезке, и тех же трех значений, поддерживаемых при задании начала фона.
276 | Глава 18 Все они объединены в примере 18.3, но вместо использования девяти отдельных HTML-наборов для отображения различных комбинаций, что сделало бы документ слишком длинным и многословным, в нем для краткости используется массив (который, если вспомнить, представляет собой простую последовательность переменных с доступом по числовому значению индекса) и литералы шаблонов. Пример 18.3 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. <!DOCTYPE html> <html> <head> <title>Background Clip and Origin</title> <style> .out { border : 3px solid black; float : left; margin : 0 20px 20px 0; } .in { font : bold 12px monospace; border : 4px dotted red; line-height : 1.25; text-align : center; width : 132px; height : 132px; } .txt { margin-top : 75% } .box { background : url('box.jpg') lime top left no-repeat; color : green; border : 20px dashed blue; padding : 20px; width : 140px; height : 140px; } </style> </head> <body> <output id='output'></output> <script> attr = ['border-box', 'padding-box', 'content-box'] for (x = 0 ; x < 3 ; ++x) { for (y = 0 ; y < 3 ; ++y) { document.getElementById('output').innerHTML += ` <div class='out'> <div class='box' style='background-clip : ${attr[x]}; background-origin : ${attr[y]}'> <div class='in'> <div class='txt'> clip:${attr[x]}<br> origin:${attr[y]} </div>
Создание фона 41. 42. 43. 44. 45. 46. 47. 48. | 277 </div> </div> </div>` } } </script> </body> </html> Результат запуска кода этого примера должен выглядеть, как показано на рис. 18.2. Рис. 18.2. Все девять вариантов обрезки фона и выбора начала координат Чтобы объяснить происходящее, понадобится девять экземпляров элементов, у каждого из которых имеется внешняя граница, внутренний отступ и содержимое. Затем, чтобы увидеть, как изображения границ (и, конечно же, цветовые установки) применяются в каждой комбинации, к элементу применяется фоновый цвет, а в фон загружается файл изображения с именем box.jpg.
278 | Глава 18 В примере, начиная со строки 6, создается набор указаний для элементов класса out, предписывающих наличие сплошной черной 3-пиксельной границы для каждого из девяти элементов, размещаемых рядом друг с другом, а для их разделения применяется внешний отступ. Начиная со строки 9, для класса in устанавливается внутренний элемент с красной пунктирной рамкой толщиной 4 пикселя, задаются размеры и стили для текста, чтобы при выполнении кода примера в каждом из девяти элементов присутствовало четкое пояснение. Указания для класса txt в строке 15 обеспечивают отображение текста в нужном месте — на 75% ниже позиции области содержимого. И в завершение раздела <style> класс box, установки для которого начинаются в строке 16: это место, где фоновое изображение загружается в верхний левый угол того места, о котором чуть позже будет объявлено в атрибуте background-origin; для фона устанавливается цвет лайма, а для текста — зеленый цвет. Одновременно с этим создается внутренний отступ в 20 пикселей, чтобы можно было видеть, что происходит внутри него, и назначаются подходящие размеры. Раздел сценария JavaScript Здесь в строках 29 и 30 с использованием переменных циклов x и y, для каждой из которых задается последовательный перебор значений в диапазоне от 0 до 2, создаются два цикла, причем второй цикл вкладывается в первый. Значения переменных цикла x и y используются в качестве индексов массива attr[], объявленного в строке 27, для извлечения содержащихся в нем строковых значений. Затем в строках с 32 по 43 следует блок HTML-кода, заключенный в символы обратных апострофов. Первый обратный апостроф находится в конце строки 31, а составляющий ему пару второй — в конце строки 43. Внутри этих обратных апострофов находится стандартный HTML-код плюс четыре экземпляра литералов шаблона. Если посмотреть на выражение ${attr[x]} в строке 34 и выражение ${attr[y]} в строке 35, можно понять, что они просто извлекают значения атрибутов из массива attr[] для девяти возможных комбинаций при разных значениях х и у. Значения в переменной y служат для установки background-clip в border-box в первой строке отображаемого вывода, в padding-box во второй и в content-box в третьей. Это делается путем применения значения, полученного из attr[], непосредственно из кода HTML к принадлежащему элементу атрибуту style. В то же самое время значения в переменной x приводят к установке backgroundorigin каждого столбца в border-box для первого, padding-box для второго и contentbox для третьего элемента, и все это повторяется для следующих двух строк. При каждом проходе этой пары циклов в строке 31 результат просто добавляется к внутреннему HTML-коду элемента <output>, поэтому отображение результата и появляется на экране. Если присмотреться к изображению на рис. 18.2, можно понять, что именно происходит, и заметить, что для каждой из строк лаймовый фоновый цвет начинает за-
Создание фона | 279 полнение до края границы, затем до края внутреннего отступа, а затем заполняет всю область содержимого. Наряду с этим можно заметить эффект, производимый изменением начала фона (в сочетании с его обрезкой), например, если смотреть вдоль столбцов, изображение квадрата в первом столбце начинается с верхнего левого угла границы, во втором столбце — с верхнего левого угла внутреннего отступа, а в третьем столбце — с верхнего левого угла содержимого, и на него также влияют указания по обрезке. Код HTML в строках с 37 по 40 для получения визуальной картины примера не играет абсолютно никакой роли, но он выводит текст, поясняющий, какие значения атрибутов были применены к каждому элементу, поэтому, чтобы картина с первого взгляда еще больше прояснилась, был смысл немного усложнить код. Эти девять комбинаций конкретизируют все, чего можно добиться с помощью этих свойств, поэтому изображение на рис. 18.2 можно считать идеальным справочником, позволяющим вспомнить, что эти свойства делают и как их применять. Рис. 18.3. Просмотр созданного HTML-кода в консоли Помимо этого, было показано, как литералы шаблонов смогли найти достойное применение не только в одном-единственном случае, но и при применении в более сложных структурах вроде вложенных циклов. Неважно, будет в вашей разработке использоваться вложенная структура или нет, для литералов шаблонов, предлагае-
280 | Глава 18 мых JavaScript, наверняка найдется множество применений, ускоряющих любую веб-разработку, требующую динамичного и часто меняющегося контента. Кстати, если хотите увидеть, как выглядит тот самый только что созданный HTMLкод и сколько было сэкономлено на размере документа и отсутствии повторяющихся строк, можете вставить следующую инструкцию непосредственно перед закрывающим оператором </script> в строке 46, а затем просмотреть вывод, открыв консоль разработчика: console.log(document.getElementById('output').innerHTML) Результат должен выглядеть приблизительно так, как показано на рис. 18.3. Особо заинтересованные могут скопировать код из консоли и вставить его взамен элемента <output>, а затем удалить (теперь ненужный) раздел <script>, и убедиться, что результат будет таким же, как показано на рис. 18.2, но достигнут он будет за счет создания излишне длинного документа из 125 строк по сравнению с 48 строками, имеющимися в примере 18.3. Прилагаемый бесплатный архив файлов примеров, чтобы не приходилось заниматься набором текста на компьютере, также включает альтернативную версию примера. Размер фона При желании изменить размеры фонового изображения воспользоваться стандартными свойствами width и height не получится. Вместо них есть единый атрибут background-size, позволяющий изменять оба значения. Ему можно предоставить одно значение, на которое установятся оба размера или же предоставить два значения: одно — для ширины, а второе — для высоты: background-size : 100px background-size : 130px 90px Первая инструкция установит размеры фона 100 x 100 пикселей, а вторая —130 x 90 пикселей. В примере 18.4 создаются <div>-элементы, и в каждый из них загружается одно и то же фоновое изображение, но при этом используются разные значения атрибута background-size. Пример 18.4 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. <!DOCTYPE html> <html> <head> <title>Background Size</title> <style> .background { background : url('painting.png') green center no-repeat; color : white; width : 150px; height : 150px; font : bold 16pt sans-serif;
Создание фона 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. text-align border float margin background-size background-size background-size background-size background-size #box1 { #box2 { #box3 { #box4 { #box5 { </style> </head> <body> <div class='background' <div class='background' <div class='background' <div class='background' style='width:300px' <div class='background' style='width:880px' </body> </html> : : : : : : : : : center; solid black left; 20px; 100px; 140px 70px; 50%; 100%; 100% 100%; | 281 2px; } } } } } } id='box1'>Box 1</div> id='box2'>Box 2</div> id='box3'>Box 3</div> id='box4'>Box 4</div> id='box5'>Box 5</div> В этом примере начиная со строки 6 для класса background устанавливается фон зеленого цвета, в центр элемента без повторения загружается изображение, для элемента задается граница и внешний отступ, выбирается подходящий стиль и цвет шрифта, и элемент прижимается к левой стороне, чтобы быть выровненным по горизонтали. Для первых двух идентификаторов box1 и box2 в строках 16 и 17 задаются размеры соответственно 100 x 100 пикселей и 140 x 70 пикселей. Затем в строках 24 и 25 в разделе <body> задается отображение двух элементов, имеющих эти идентификаторы. Для остальных трех идентификаторов box3, box4 и box5 в строках с 18 по 20 используются процентные значения 50, 100, а затем 100 на 100 процентов, а отображение элементов с этими идентификаторами задается с 26 по 30, где для четвертого и пятого блоков непосредственно в HTML задается принудительное изменение ширины элемента, чтобы проиллюстрировать эти эффекты в элементах неквадратной формы. Тем самым, как показано на рис. 18.4, иллюстрируется, наверное, несколько неожиданно поведение процентных значений, где первые три блока отображаются так, как и можно было предположить. Но взгляните на четвертый блок, где к атрибуту размера фона применяется только одно значение 100%, устанавливающее ширину на ширину элемента, и поэтому высота изображения также была установлена на значение той же ширины (поскольку было предоставлено лишь одно значение), и получается, оба измерения должны иметь одинаковую протяженность. А вот в пятом блоке размер изображения был полностью изменен в обоих измерениях, поскольку значения 100% заданы как для ширины, так и для высоты, и они должны изменяться независимо друг от друга.
282 | Глава 18 Рис. 18.4. Фоновые изображения при использовании множества различных значений размеров фона Использование градиентов В CSS имеется широкий спектр доступных вариантов цветового оформления, в чем еще предстоит убедиться при изучении главы 21 «Цвета и прозрачность», а пока давайте посмотрим на ряд способов их применения к элементам фона. В примере 18.5 приведен отрывок из шекспировской пьесы «Как вам это понравится», для которого используется фоновый линейный градиент, плавно переходящий от синего цвета вверху к красному цвету внизу. Пример 18.5 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. <!DOCTYPE html> <html> <head> <title>Background Linear Gradient</title> <style> .bground { background-image : linear-gradient(blue, red); } #quote { color : white; padding : 10px; font : bold 28pt sans-serif; } </style> </head> <body> <div class='bground' id='quote'> All the world's a stage, And all the men and women merely players.
Создание фона 16. 17. 18. 19. 20. 21. | 283 They have their exits and their entrances, And one man in his time plays many parts, His acts being seven ages. </div> </body> </html> Результат выполнения кода этого примера показан на рис. 18.5. Рис. 18.5. Элемент с линейным градиентом фона В этом примере для элементов с идентификатором quote в строках с 7 по 9 задается стиль, пригодный для наложения на темный фон. В строке 6 задается стилевое оформление класса с именем bground, благодаря которому для текста, указанного в строках с 13 по 19, создается линейный фон. Путем простого изменения кода строки 6 этого примера (показан в примере 18.6) направление течения градиента изменяется, и он перетекает слева направо. Пример 18.6 (только настройки bground): .bground { background-image:linear-gradient(to right, blue, red); } Рис. 18.6. Градиент переключается на перетекание слева направо
284 | Глава 18 Результат выполнения кода этого примера показан на рис. 18.6. Используя этот прием, для to можно применить любую комбинацию с направлениями потока вверх, вниз, влево и вправо (top, bottom, left и right), заставляя градиенты течь во всех восьми основных направлениях стрелки компаса, включая диагональные градиенты. А если понадобится более высокая точность, направление потока градиента вместо инструкции to right или другой какой-либо инструкции можно указать в градусах, например 185deg. Точки остановки цвета Точки остановки цвета позволяют использовать в градиентах более двух цветов, как в примере 18.7 (где показаны только настройки bground), задающем радужную заливку по диагонали под углом 45 градусов). Пример 18.7 (только настройки bground): .bground { background-image:linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet); } Результат выполнения кода этого примера показан на рис. 18.7 Рис. 18.7. Диагональный линейный радужный градиент Удаленность точек остановки цвета и повторения При желании можно точно указать, насколько далеко вдоль градиента должна располагаться каждая точка остановки цвета, указав сразу за цветом значение в процентах. Градиент можно также задать повторяющимся, заменив функцию linear-gradient() на repeating-linear-gradient(). В примере 18.8 применены оба этих изменения.
Создание фона | 285 Пример 18.8 (только настройки bground): .bground { background-image:repeating-linear-gradient(45deg, red 5%, orange 10%, yellow 15%, green 20%, blue 25%, indigo 30%, violet 35%); } Результат выполнения кода этого примера показан на рис. 18.8. Рис. 18.8. Повторяющийся диагональный градиент Радиальные и конические градиенты Остаются еще два типа градиента, применяемых в качестве фонового изображения: радиальный и конический. Радиальный градиент начинается в центре окружности (или овала) и течет наружу, а конический градиент обтекает окружность (или овал), подобно линии на экране радара. В примере 18.9 в отношении разных <div>-элементов применяются оба этих типа градиентов. Пример 18.9 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. <!DOCTYPE html> <html> <head> <title>Radial and Conic Gradients</title> <style> .radial { background-image:radial-gradient( red, orange, yellow, green, blue, indigo, violet); } .conic { background-image:conic-gradient( red, orange, yellow, green, blue, indigo, violet, red); } .elem { float : left; margin : 10px; width : 400px; height : 200px; }
286 14. 15. 16. 17. 18. 19. 20. | Глава 18 </style> </head> <body> <div class='radial elem'></div> <div class='conic elem'></div> </body> </html> Результат выполнения кода этого примера показан на рис. 18.9. Рис. 18.9. Радиальный и конический градиенты, показанные рядом Здесь задается стилевое оформление двух классов: radial и conic, а затем стилевое оформление класса elem, используемого в двух элементах <div>, в одном из которых отображается радиальный градиент, в другом — конический. При желании можно также установить точные значения удаленности точек остановки цвета в процентах, а также применить префикс repeating- перед именами функций radius-gradient() и conic-gradient(), чтобы задать повторение градиентов. В главе 21 «Цвета и прозрачность» будет показано, как можно заменить английские цветовые названия значениями RGB или HSL и даже включить в эти значения прозрачность. Но все эти функции относятся не только к фону, но и к цвету в целом, поэтому здесь эта тема не получила дальнейшего развития. Заключение Существенное расширение функциональных возможностей по заданию фона в CSS3 не вызывает сомнений, и теперь какой угодно фон можно добавлять к любому элементу, стилизуя его практически любым способом, который только можно себе представить, включая использование широкого спектра градиентов. В следующей главе это исследование будет продолжено в рамках полного обзора способов задания границ в CSS3, где, в частности, в качестве способов задания границ будут рассматриваться фоновые изображения и градиенты.
ГЛАВА 19 Построение границ Введение Отчасти эта глава — продолжение предыдущей, поскольку у границ и фонов CSS3 много пересечений. И все же стоит поискать, где провести между ними разделительную черту. Начнем, пожалуй, с рассмотрения способов использования с прицелом на это фоновых изображений, затем разовьем тему с переходом к использованию одного изображения и только потом рассмотрим другие возможные типы границ. В качестве других типов будут рассматриваться границы разных цветов, причем, возможно, для каждой из сторон, а также границы с различными формами изогнутости и границы, составленные из градиентов. Структура В этой главе рассматриваются следующие темы:  Изучение всевозможных типов границ, доступных в CSS3.  Освоение приемов добавления к элементам разнообразных закругленных границ.  Изучение порядка использования в границах цветовых решений и градиентов.  Изучение приемов использования для границ одного или нескольких изображений. Цели Здесь будут рассматриваться все вопросы создания привлекательных границ. Изучение материалов главы позволит освоить все варианты оформления границ, включая добавление радиусов закруглений, изменение цветового оформления на разных краях, применение изображений и даже использование цветных градиентов.
288 | Глава 19 Радиус границы Одна из наиболее привлекательных новых функций — изменение радиуса границы, позволяющее создавать все типы ее закруглений, вплоть до полной окружности. Основное свойство называется радиусом границы — border-radius, но существует еще целый ряд сопутствующих свойств для точного задания формы углов. В примере 19.1 с использованием этих различных свойств создается множество различных типов границ. Пример 19.1 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. <!DOCTYPE html> <html> <head> <title>Border Radius</title> <style> .box { width : height : float : background : padding : margin-right : border : .border1 { border-radius : .border2 { border-radius : .border3 { border-top-left-radius : border-top-right-radius : border-bottom-left-radius : border-bottom-right-radius : .border4 { border-top-left-radius : border-top-right-radius : border-bottom-left-radius : border-bottom-right-radius : .border5 { border-radius : </style> </head> <body> <div class='box border1'></div> <div class='box border2'></div> <div class='box border3'></div> 100px; 100px; left; lime; 10px; 10px; 20px solid #006; } 50px; } 50px 50px 20px 20px; } 25px; 50px; 75px; 100px; } 20px 80px 80px 20px } 80px; 20px; 20px; 80px; 100%; }
Построение границ 36. 37. 38. 39. | 289 <div class='box border4'></div> <div class='box border5'></div> </body> </html> В этом примере основной класс в разделе <style> называется box, стилевые установки которого определяются, начиная со строки 7. Здесь устанавливаются размеры каждого отображаемого элемента, а также цвет фона, внешние и внутренние отступы и ширина границы, ее стиль и цвет. Элементы также по указанию значения для свойства float прижимаются к левой стороне, получая возможность выстроиться в ряд. Затем определяется стиль для пяти классов, где указываются разные стили границ, используемые элементами <div>, задаваемыми начиная со строки 33 в разделе документа <body>. Результат загрузки этого примера в браузер показан на рис. 19.1. Рис. 19.1. Примеры различных стилей границ Если к свойству border-radius применяется только одно значение (как в классе border1 в строке 14 для первого элемента в примере 19.1), всем углам задается одно и то же значение, поэтому получается симметричный прямоугольник или квадрат с границами, закругленными на указанную величину. Если для border-radius применяется два значения, то первое из них задает форму верхнего левого и нижнего правого угла, а второе — двух оставшихся углов. Если применяются три значения, то первое относится к верхнему левому углу, второе — к верхнему правому и нижнему левому углам, а третье — к нижнему правому углу. Когда предоставлены все четыре значения (как в классе border2 в строке 16 для второго элемента в примере 19.1), они применяются к углам по ходу часовой стрелки от верхнего левого угла к верхнему правому, затем к нижнему правому и, наконец, к нижнему левому углам. А теперь еще интереснее: все эти углы можно изменять по отдельности, воспользовавшись следующими свойствами:  border-top-left-radius  border-top-right-radius  border-bottom-left-radius  border-bottom-right-radius
290 | Глава 19 Эти свойства говорят сами за себя, и их применение можно увидеть в классе border3 в строке 18, в результате чего третий элемент отображается так, как показано на рис. 19.1. Но это еще не все. Для конкретных углов при желании можно указать два значения, и тогда первое применяется к первой стороне, указанной в имени свойства, а второе — ко второй именованной стороне. Например, когда значения задаются для свойства border-bottom-right-radius, то первое значение применяется к нижнему краю угла, а второе — к правому краю. Это можно увидеть в четвертом элементе на рис. 19.1, поскольку именно так заданы значения для упомянутого свойства класса border4 в строке 23. И наконец, можно создать целиком круглые или овальные границы, применив к свойству border-radius максимальное значение, обычно от 50% и выше, чтобы это точно получилось, как в установках для класса border5, применяемых для создания показанного на рисунке пятого элемента. Вообще-то значения для любых свойств границ могут по вашему усмотрению указываться как в пикселях, так и в процентах. Исчерпывающее объяснение всего разнообразия свойств радиуса границы можно найти по следующему URL-адресу: tinyurl.com/b-radius Цвета границ Независимо от типа создаваемой цветной границы, стандартной или с радиусами закругления, имеется также множество способов изменения ее цвета, включая применение различных градиентов. Но сначала давайте рассмотрим вариант применения сплошных цветовых решений. Как уже известно, следующая установка приведет к появлению сплошной синей границы шириной 10 пикселей: border : 10px solid blue; Но вот о том, что можно определить цвет отдельно для каждого из краев границы, как показано в примере 19.2, вы могли и не знать. В блоке стилей классов, начинающемся в строке 6, в строке 10 задается 20-пиксельная сплошная граница, после чего в строке 11 ей назначаются четыре цвета. Пример 19.2 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. <!DOCTYPE html> <html> <head> <title>Border Colors</title> <style> .box { width : 640px; height : 100px; background : cyan; border : 20px solid;
Построение границ 11. 12. 13. 14. 15. 16. 17. | 291 border-color : red yellow blue green; } </style> </head> <body> <div class='box'></div> </body> </html> Эти цвета, как показано на рис. 19.2, применяются по направлению движения часовой стрелки, начиная с верхней части границы. Рис. 19.2. Элемент с четырьмя границами разного цвета При желании, как и в случаях с border-top-style и с подобными этому свойствами, можно также установить эти цвета по отдельности, воспользовавшись следующими свойствами, каждое из которых принимает одно значение:  border-top-color  border-left-color  border-right-color  border-bottom-color Полную информацию о параметрах цвета границы, которые теперь доступны в CSS3, можно найти по следующему URL-адресу: tinyurl.com/b-color Градиентные границы При желании создавать многоцветные границы можно вместо изображения выбрать градиент. В примере 19.3 в строке 14 задается граница с переходом от оранжевого к синему цвету. Пример 19.3 1. 2. <!DOCTYPE html> <html>
292 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. | Глава 19 <head> <title>Gradient Border</title> <style> .border { font-family : 'Times New Roman'; text-align : center; padding : 10px; width : 300px; height : 200px; border-width : 10px; border-style : solid; border-image : linear-gradient(orange, blue) 27 / 35px; } </style> </head> <body> <center> <div class='border'> <h2>A</h2> <h1>Gradient</h1> <h2>Border</h2> </div> </center> </body> </html> Результат загрузки этого примера в браузер показан на рис. 19.3. Рис. 19.3. Использование градиента для построения границы Для более выразительного эффекта можно также воспользоваться заданием радиальных и повторяющихся градиентов, а также нарезать изображения границ раз-
Построение границ | 293 личными способами. Количество разнообразных эффектов не позволяет уделить слишком много места их описанию, но при желании проявить творческий подход к построению границ можно ознакомиться с официальной документацией, где демонстрируется множество других примеров, зайдя на веб-страницу по следующему URL-адресу: tinyurl.com/css3borders Использование нескольких фонов В главе 16 «Введение в CSS3» уже был вкратце рассмотрен вопрос об использовании фоновых изображений для создания границы в документе, как показано в примере 19.4. Пример 19.4 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. <!DOCTYPE html> <html> <head> <title>Multiple <style> .border { font-family font-style text-align padding width height background Border Images</title> : : : : : : : 'Times New Roman'; italic; center; 60px; 250px; 300px; url('b1.gif') top url('b2.gif') top url('b3.gif') bottom url('b4.gif') bottom url('ba.gif') top url('bb.gif') left url('bc.gif') right url('bd.gif') bottom left right left right </style> </head> <body> <center> <div class='border'> <h1>Certificate of<br>Attendance</h1> <h2>Awarded To:</h2> <h3>__________________</h3> <h2>Date:</h2> <h3>___/___/_____</h3> </div> no-repeat, no-repeat, no-repeat, no-repeat, repeat-x, repeat-y, repeat-y, repeat-x }
294 32. 33. 34. | Глава 19 </center> </body> </html> При загрузке кода примера в браузер должна получиться такая же картинка, как на рис. 19.4. Рис. 19.4. Граница, построенная из восьми изображений Теперь, после рассмотрения всех основ, необходимых для понимания того, как все это работает, давайте подробно разберем пример, в котором используются восемь отдельных изображений, представляющих четыре стороны и четыре угла границы. Угловые изображения указываются в строках с 13 по 16 для задания соответствующих фигур в левом верхнем, правом верхнем, левом нижнем и правом нижнем углу любого элемента, использующего этот класс. Для них также устанавливается режим без повторений. В строках с 17 по 20 указываются изображения для верхней, левой, правой и нижней сторон элемента, использующего данный класс, причем верхнее и нижнее изображения настроены на повторение по горизонтали, а левое и правое — по вертикали. Эти повторяющиеся изображения будут сужаться и расширяться, создавая
Построение границ | 295 сплошную сторону границы для любого элемента, но элементы с размерами границы, не превышающими размера изображения, будут иметь неприглядный вид. Угловые изображения b1.gif, b2.gif, b3.gif и b4.gif показаны на рис. 19.5. Рис. 19.5. Четыре угловые изображения А четыре изображения, используемые для сторон границы, показаны на рис. 19.6, где они увеличены, чтобы были видны отдельные пиксели. Если смотреть слева направо, то там показаны изображения верхней, левой, правой и нижней сторон границы. Рис. 19.6. Четыре изображения сторон границы В отношении изображений сторон границы следует заметить, что, хотя из-за того, что цветные пиксели простираются до соседних углов, в угловых изображениях отображаются дополнительные белые пиксели, для расширения изображений сторон белые пиксели не требуются. Поэтому эти изображения могут оставаться очень маленькими и быстро загружаться. В развернутом применении для этих белых пикселей, чтобы они не мешали применяемой цветовой схеме, с помощью графической программы, вероятнее всего, будет установлено значение прозрачности. Использование одного изображения Хотя в использовании нескольких изображений намного легче разобраться, они требуют восьми отдельных запросов к веб-серверу, увеличивая тем самым нагрузку на сеть и сервер. Разумнее, особенно для сайтов с высокой посещаемостью, собирать изображения границ в единое целое, получая, как показано на рис. 19.7, наименьшую из возможных границ в одном изображении. Затем, используя это изображение, можно воспользоваться инструкциями CSS3 для извлечения различных углов и сторон, и их размещения по границе элемента, как если бы они были отдельными изображениями. Тем самым обмен данными с сервером сокращается в восемь раз, позволяя браузеру выполнять его работу без заметного снижения производительности.
296 | Глава 19 Как ни странно, но работать с одним изображением намного проще, и можно стилизовать по-разному элемент с помощью CSS, как показано в примере 19.5 в строках с 6 по 13, поместив в строку 14 единую инструкцию с именем файла и значением, позволяющим разбить изображение на восемь компонентов, необходимых для создания неразрывной и расширяемой границы. Рис. 19.7. Одно изображение, созданное из восьми изображений, используемых для построения границы Пример 19.5 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. <!DOCTYPE html> <html> <head> <title>Single Border Image</title> <style> .border { font-family : 'Times New Roman'; text-align : center; padding : 33px; width : 100px; height : 150px; border-width : 102px; border-style : dotted; border-image : url('border.png') 102; } </style> </head> <body> <center> <div class='border'> <h2>An</h2> <h1>Image</h1>
Построение границ 22. 23. 24. 25. 26. | 297 <h2>Border</h2> </div> </center> </body> </html> Использование всего лишь одного свойства border-image позволяет загрузить изображение и извлечь его нужные части, а затем разместит их там, где они должны быть. Выполнение всех этих действий при использовании всего лишь одного значения 102 выглядит как какое-то волшебство. Это действительно похоже на магию, поскольку этого значения вполне хватает, чтобы сообщить браузеру о необходимости построить изображение, показанное на рис. 19.8. Рис. 19.8. Граница, построенная на основе одного изображения Веб-браузер уже определил, что изображение имеет размер 205 x 205 пикселей, поэтому, когда указывается значение 102 пикселя, он понимает, что каждый из углов должен иметь размер 102 x 102 пикселя, а все, что осталось между углами, должно использоваться для сторон, вот и все. А что будет, если вместо 102 указать другое значение? Ну, тогда в углах элементов будет использоваться меньшая часть каждого угла изображения, части сторон будут увеличиваться. Например, при значении 75 результат будет выглядеть как по-
298 | Глава 19 казано на рис. 19.9, который отличается от предыдущего рисунка границы, но все еще выглядит неплохо. Рис. 19.9. Другая нарезка изображения Заключение В последних нескольких главах был изложен материал, завершающий наше исследование фона, границ и изображений. В следующей главе будут предложены способы добавлений теней к элементам, указаний типов перетеканий, необходимых для случаев, когда содержимого больше, чем может поместиться в элементе. Также предстоит изучение способов работы со столбцами.
ГЛАВА 20 Свойства блока и текста Введение Здесь будет рассматриваться ряд эффектов CSS3, позволяющих добавлять к блочным элементам тени, управлять переполнением, когда содержимое элемента превышает его размеры, и перераспределение текста в колонках. И хотя рассмотрены будут всего лишь три функции, для удачной компоновки и приемлемой стилизации они играют фундаментальную роль, поэтому их подробное изучение стоит затраченного на него времени. Структура В этой главе рассматриваются следующие темы:  Изучение способов добавления к элементам различных теней.  Освоение приемов контроля за каждым аспектом переполнения элемента.  Изучение приемов распределения текста по нескольким колонкам.  Освоение способов улучшения восприятия текста колонки с помощью автоматической и ручной расстановки переносов. Цели Цель главы — дополнить арсенал ваших инструментов тремя высокоэффективными функциями стилевого оформления. Будут также рассмотрены все подробности их использования, а также другие функции CSS, которые можно комбинировать с ними для достижения наилучшего эффекта. Изучение материала главы позволит узнать все необходимое о тенях, о том, как справиться с переполнением текстом и об использовании нескольких колонок. Добавление теней Простой, но эффективный способ обратить внимание на содержимое и выделить его на фоне всего остального, имеющегося на странице — применить к элементу
300 | Глава 20 тот или иной тип тени. Теперь с помощью CSS3 это можно сделать различными способами, в любом выбранном цвете, в разных направлениях, а также внутри элементов. В примере 20.1 создаются разнообразные блочные тени как снаружи, так и внутри элементов. Пример 20.1 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. <!DOCTYPE html> <html> <head> <title>Box Shadows</title> <style> .boxa { width : 120px; height : 100px; .boxb { width : 280px; height : 100px; .all { background : cyan; float : left; margin : 10px; border : 10px solid red; .shadow1 { box-shadow : -6px -6px 10px #888; .shadow2 { box-shadow : 6px -6px 10px #888; .shadow3 { box-shadow : -6px 6px 10px #888; .shadow4 { box-shadow : 6px 6px 10px #888; .shadow5 { box-shadow : -6px -6px 10px #888 inset; .shadow6 { box-shadow : 6px -6px 10px #888 inset; .shadow7 { box-shadow : -6px 6px 10px #888 inset; .shadow8 { box-shadow : 6px 6px 10px #888 inset; .shadow9 { box-shadow : 0px 0px 20px #000; .shadowa { box-shadow : 0px 0px 20px #000 inset; </style> </head> <body> <div class='boxa all shadow1'></div> <div class='boxa all shadow2'></div> <div class='boxa all shadow3'></div> <div class='boxa all shadow4'></div> <div class='boxa all shadow5'></div> <div class='boxa all shadow6'></div> <div class='boxa all shadow7'></div> <div class='boxa all shadow8'></div> <div class='boxb all shadow9'></div> <div class='boxb all shadowa'></div> </body> </html> } } } } } } } } } } } } }
Свойства блока и текста | 301 На рис. 20.1 видно, что к свойству box-shadow применяются значения смещения по горизонтали и вертикали (со знаками «плюс» и «минус»), за которыми следуют степень размытия, цвет и указание на вложенность тени. Рис. 20.1. Разнообразие типов теней Для элементов класса boxa задается квадратная форма, что видно на первых восьми блоках на рис. 20.1, а для элементов класса boxb, что видно на последних двух блоках, задается прямоугольная форма. Класс all указывается для всех блоков, чтобы задать цвет, отступы, сторону, к которой прижимается блок, а также толщину и цвет границы. Затем задается стилизация десяти классов с целью создания различных типов теней. Для первых четырех классов задается по очереди создание тени в верхнем левом, верхнем правом, нижнем левом и нижнем правом углах элемента. Для следующих четырех классов создание теней задается схожим образом, но на этот раз с размещением внутри элементов. И наконец, для последних двух классов задается создание теней сначала снаружи, а потом внутри элемента. Затем для отображения установок для каждого из этих классов используется элементы, указанные в разделе <body>. Следует заметить, что при использовании внешних теней для них лучше использовать не слишком темные цвета, иначе можно исказить изображение затеняемого
302 | Глава 20 элемента. А вот для внутренних теней, возможно, потребуется использовать более темные цвета, так как большая часть их составляющей будет скрыта границей. Переполнение элементов До введения в практику применения CSS3 остро стояла проблема подстраивания текста, превышавшего по объему размер элемента. Раньше можно было только грубо установить для применяемого во всех случаях свойства overflow одно из следующих значений: hidden, visible, scroll или auto. Но теперь стало доступным более тонкое управление подобной ситуацией, поскольку появилась возможность воспользоваться свойствами overflow-x и overflow-y и применить те же самые значения по желанию только к горизонтальному или к вертикальному направлению. В примере 20.2 показано использование четырех комбинаций этих значений путем задания каждой из них для отдельно взятого класса. Пример 20.2 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. <!DOCTYPE html> <html> <head> <title>Element Overflow</title> <style> .box { float : left; background : yellow; margin-right : 60px; font-size : 20px; border : 1px solid #000; width : 100px; height : 100px; } .visible-x { overflow-x : visible; } .hidden-x { overflow-x : hidden; } .scroll-x { overflow-x : scroll; } .auto-x { overflow-x : auto; } .visible-y { overflow-y : visible; } .hidden-y { overflow-y : hidden; } .scroll-y { overflow-y : scroll; } .auto-y { overflow-y : auto; } </style> </head> <body> <div class='box visible-x visible-y'> ExtraWideWord The quick brown fox jumps over the lazy sleeping dog</div> <div class='box hidden-x visible-y'> ExtraWideWord The quick brown fox jumps over
Свойства блока и текста 29. 30. 31. 32. 33. 34. 35. 36. 37. | 303 the lazy sleeping dog</div> <div class='box visible-x hidden-y'> ExtraWideWord The quick brown fox jumps over the lazy sleeping dog</div> <div class='box auto-x auto-y'> ExtraWideWord The quick brown fox jumps over the lazy sleeping dog</div> </body> </html> У первого элемента в строке 24 нет прокрутки, и весь текст показан на странице вытекающим из него в полном беспорядке. А вот другие элементы, как показано на рис. 20.2, удерживают внутри себя свой контент различными способами. Рис. 20.2. Использование различных значений для свойств переполнения Поэкспериментируйте с кодом примера, переключая классы, применяемые к элементам <div>, чтобы увидеть, каких эффектов еще можно добиться. Иногда можно будет заметить, что несмотря на установку значения visible для свойств overflow-x или overflow-y, содержимое элемента может и не отображаться за его пределами. Дело в том, что согласно спецификации W3C, некоторые комбинации с аргументом visible невозможны, и если для одного свойства указано значение visible, а для другого либо scroll, либо auto, то по умолчанию значение visible будет изменено на auto. Макет, составленный из нескольких колонок До появления поддержки нескольких колонок веб-разработчикам, если нужно было отобразить текст в колонках, приходилось его разбивать вручную на отдельные фрагменты, помещая их в разные элементы. Вдобавок к тому, что все это было неуклюже и неэффективно, если браузер пользователя не был достаточно жестко ограничен в размерах окна, макет мог в конечном итоге выглядеть совсем не так, как задумывал его создатель.
304 | Глава 20 Теперь же текст может размещаться в любом количестве колонок, наподобие газетной статьи, причем весь процесс размещения полностью автоматизирован и поддерживается браузерами самых разных форматов. В примере 20.3 показан отрывок из шекспировского «Ричарда III», разбитый на пять колонок с промежутком в 1 em между колонками и их разделителем в один пиксель. Пример 20.3 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. <!DOCTYPE html> <html> <head> <title>Multiple Columns</title> <style> .columns { text-align : justify; font-size : 16pt; column-count : 5; column-gap : 1em; column-rule : 1px solid black; } </style> </head> <body> <div class='columns'> Now is the winter of our discontent Made glorious summer by this sun of York; And all the clouds that lour'd upon our house In the deep bosom of the ocean buried. Now are our brows bound with victorious wreaths; Our bruised arms hung up for monuments; Our stern alarums changed to merry meetings, Our dreadful marches to delightful measures. Grim-visaged war hath smooth'd his wrinkled front; And now, instead of mounting barded steeds To fright the souls of fearful adversaries, He capers nimbly in a lady's chamber To the lascivious pleasing of a lute. But I, that am not shaped for sportive tricks, Nor made to court an amorous looking-glass; I, that am rudely stamp'd, and want love's majesty To strut before a wanton ambling nymph; I, that am curtail'd of this fair proportion, Cheated of feature by dissembling nature, Deformed, unfinish'd, sent before my time Into this breathing world, scarce half made up, And that so lamely and unfashionable
Свойства блока и текста 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. | 305 That dogs bark at me as I halt by them; Why, I, in this weak piping time of peace, Have no delight to pass away the time, Unless to spy my shadow in the sun And descant on mine own deformity: And therefore, since I cannot prove a lover, To entertain these fair well-spoken days, I am determined to prove a villain And hate the idle pleasures of these days. Plots have I laid, inductions dangerous, By drunken prophecies, libels and dreams, To set my brother Clarence and the king In deadly hate the one against the other: And if King Edward be as true and just As I am subtle, false and treacherous, This day should Clarence closely be mew'd up, About a prophecy, which says that 'G' Of Edward's heirs the murderer shall be. Dive, thoughts, down to my soul: here Clarence comes. </div> </body> </html> Результат загрузки кода в браузер показан на рис. 20.3. Рис. 20.3. Растекание текста по нескольким колонкам Попробуйте загрузить этот пример в браузер настольной системы и посмотрите, как текст перетекает и переформатируется при изменении размеров окна браузера. Нетрудно будет убедиться, что этот способ создания колонок обладает высокой гибкостью и отзывчивостью.
306 | Глава 20 Но при этом можно заметить, что при наличии в строке пары слишком длинных слов для поддержки формата в этой строке может отображаться чрезмерно большое количество пробелов. Чтобы исправить ситуацию, можно применить пару дополнительных установок CSS для вставки в длинные слова знаков переноса, как в примере 20.4, где в строках 11 и 12 есть две новых установки для выполнения переносов: word-break и hyphens. Пример 20.4 (только начальный и head-раздел): 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. <!DOCTYPE html> <html lang='en'> <head> <title>Multiple Columns</title> <style> .columns { text-align : justify; font-size : 16pt; column-count : 5; column-gap : 1em; word-break : break-word; hyphens : auto; column-rule : 1px solid black; } </style> </head> Рис. 20.4. При использовании автоматической расстановки переносов количество пробелов уменьшается
Свойства блока и текста | 307 Чтобы установки сработали, важно, чтобы в элементе <html> был указан язык. Такое указание добавлено в строку 2 для выбора английского языка (любого из его вариантов). Результат внесения этих изменений — гораздо более аккуратное отображение текста, показанное на рис. 20.4. Установки на использование свойств word-break и hyphens могут применяться не только в колонках, но и в любом формате текста. Хотя наибольшая польза от них проявляется именно при создании колонок, поскольку благодаря им текст в колонках становится компактнее. Для свойства word-break поддерживаются значения normal, break-all, keep-all и breakword, которое используется в этом примере. Для свойства hyphens поддерживаются значения none, manual и auto, которое также используются в примере. Но даже при том, что колонки на рис. 20.4 выглядят намного лучше, чем на предыдущем рисунке, в них все еще встречаются нежелательные лишние пробелы. Ситуацию можно исправить вручную, воспользовавшись имеющимся в HTML мягким переносом &shy;, который можно расставлять в возможных потенциальных местах переносов длинных слов. Мягкие переносы будут заменяться знаками переноса только в том случае, если перенос для слова нужно будет применить в конце строки. В примере 20.5 в текст было добавлено множество таких мягких переносов. Пример 20.5 (только раздел с текстом): 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. <div class='columns'> Now is the winter of our dis&shy;con&shy;tent Made glor&shy;ious sum&shy;mer by this sun of York; And all the clouds that lour'd upon our house In the deep bosom of the ocean buried. Now are our brows bound with vic&shy;tor&shy;ious wreaths; Our bruised arms hung up for monu&shy;ments; Our stern alar&shy;ums changed to merry mee&shy;tings, Our drea&shy;dful marches to delight&shy;ful mea&shy;sures. Grim-visaged war hath smooth'd his wrink&shy;led front; And now, instead of mount&shy;ing barded steeds To fright the souls of fear&shy;ful adver&shy;saries, He capers nimbly in a lady's chamber To the las&shy;civ&shy;ious plea&shy;sing of a lute. But I, that am not shaped for sport&shy;ive tricks, Nor made to court an amor&shy;ous looking-glass; I, that am rudely stamp'd, and want love's maj&shy;esty To strut before a wanton ambling nymph; I, that am cur&shy;tail'd of this fair prop&shy;ortion, Cheated of fea&shy;ture by dis&shy;semb&shy;ling nature, Defor&shy;med, unfin&shy;ish'd, sent before my time Into this brea&shy;thing world, scarce half made up, And that so lamely and un&shy;fash&shy;ion&shy;able That dogs bark at me as I halt by them;
308 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. | Глава 20 Why, I, in this weak pip&shy;ing time of peace, Have no de&shy;light to pass away the time, Unless to spy my shadow in the sun And des&shy;cant on mine own deform&shy;ity: And there&shy;fore, since I cannot prove a lover, To enter&shy;tain these fair well-spoken days, I am deter&shy;mined to prove a villain And hate the idle plea&shy;sures of these days. Plots have I laid, induc&shy;tions danger&shy;ous, By drunken proph&shy;ecies, libels and dreams, To set my brother Clar&shy;ence and the king In deadly hate the one against the other: And if King Edward be as true and just As I am subtle, false and treach&shy;erous, This day should Clar&shy;ence closely be mew'd up, About a proph&shy;ecy, which says that 'G' Of Edward's heirs the murd&shy;erer shall be. Dive, thoughts, down to my soul: here Clar&shy;ence comes. </div> Результат этих изменений показан на рис. 20.5. Рис. 20.5. Результат добавления вручную вариантов переносов длинных слов Конечно, это только прибавляет лишних хлопот, но в тех случаях, когда настоятельно требуется представить выводимый текст в наилучшем виде независимо от его объема, используемого браузером, эти дополнительные усилия могут иметь
Свойства блока и текста | 309 решающее значение. Добавлять мягкие переносы можно сколько угодно, доводя отображение текста до полного совершенства и вставляя их в отдельные слова по нескольку раз, поскольку использоваться будут только те из них, которые придутся на конец строки. Хорошо также то, что мягкие переносы &shy; работают во всех форматах текста, а не только в колонках, поэтому, если какую-либо из ваших веб-копий необходимо будет использовать в другом месте, возможно, в более широких колонках или даже вообще не в колонках, ей можно будет смело воспользоваться, поскольку добавленные мягкие переносы не будут срабатывать там, где они не нужны. Возможно, добиться идеальной расстановки пробелов для всех размеров окна браузера не удастся никогда, но все же можно будет обеспечить наилучшее отображение текста в большинстве случаев. Заключение Эта глава обогатила ваш инструментарий несколькими новыми функциями оформления стилей с соответствующим применением свойств блока и текста, что позволит выполнять ручную и автоматическую расстановку переносов в тексте, переформатировать текст в макет с несколькими колонками, добавлять привлекательные тени и проводить логическую обработку текста при переполнении им размеров элемента. В следующей главе процесс изучения продолжится рассмотрением всего, что может дать нам в стилевом оформлении задание цвета и прозрачности.
ГЛАВА 21 Цвета и прозрачность Введение Вы можете даже этого не осознавать (или не испытывать в этом ни малейших потребностей), но способ задания цветовых решений в CSS3 благодаря добавлению функций rgb(), rgba(), hsl() и hsla() был существенно улучшен. Они предоставляют полный контроль над любым цветом, включая его красный, зеленый и синий компоненты, его точный оттенок, его насыщенность, применяемую яркость, а также степень альфа-прозрачности. Больше нет ограничений, накладываемых использованием предопределенных имен цветов или работой с шестнадцатеричными форматами задания цвета. Теперь уже можно делать все то же самое, что и в графических программах, выбирая цвета из цветовых кругов или независимо выбирая яркость и прозрачность. Структура В этой главе рассматриваются следующие темы:  Порядок использования цветового пространства RGB.  Способы добавления цвета из цветового пространства HSL.  Приемы использования альфа-прозрачности.  Способы создания комбинаций из различных цветовых типов для достижения большего эффекта. Цели Здесь состоится полноценное знакомство со всем разнообразием приемов применения цветовых решений в веб-документах, предоставляемых CSS3. Изучение материалов главы позволит стать специалистом по подбору цвета путем использования широкого спектра доступных инструментов и методов.
312 | Глава 21 RGB-цвета Цветовая система RGB знакома, наверное, всем, кто когда-либо имел дело с CSS. Цвета в ней задаются в формате #RGB или #RRGGBB. Например, #000 — абсолютно черный цвет, а #FFF — абсолютно белый, #F00 — красный, #0F0 — зеленый, а #00F — синий цвет, всего 16 × 16 × 16 (или 4096) возможных цветов при использовании формата задания цвета с одной цифрой на каждый компонент, например #FEB для персикового цвета. Можно также воспользоваться двузначным форматом задания цвета, позволяющим поддерживать 256 × 256 × 256 (или более 16 миллионов) возможных цветов, например #FFE5B4 для более конкретного и гораздо более точно заданного оттенка персикового цвета. И, как уже известно, заглавные буквы в шестнадцатеричных обозначениях использовать необязательно, потому что комбинация #feb также задает персиковый цвет, как и комбинацией #ffe5b4. Разумеется, когда не нужен точный подбор цветов, можно просто воспользоваться одним из 147 поддерживаемых названий. Их преимущество заключается в мгновенной узнаваемости при первом же просмотре таблиц стилей; например, когда применяются такие интересные названия, как antiquewhite (античный белый) или lightseagreen (светло-зеленый) и т. д. Но теперь в CSS3 для установки необходимых значений RGB можно воспользоваться функцией rgb(), и при этом не ограничиваться использованием шестнадцатеричных значений, поскольку можно также использовать десятичные числа от 0 до 255 или процентные значения от 0 до 100. Например, rgb(255, 229, 180) и rgb(100%, 90%, 70%) достаточно точно (и почти что точно для процентных значений) позволяют задать такой же персиковый цвет, как и при применении комбинации #FFe5B4. В примере 21.1, чтобы укоротить слишком длинный документ, для заполнения элемента <output>, указанного в строке 10, тысячами инструкций <div> с целью демонстрации диапазона различных значений RGB, примененных к ним с использованием функции rgb(), используется функция шаблонов, впервые упомянутая в главе 18 «Создание фона». Пример 21.1 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. <!DOCTYPE html> <html> <head> <title>RGB Colors</title> <style> div { height : 1px; } </style> </head> <body> <output id=’output’></output>
Цвета и прозрачность 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. | 313 <script> for (j = 0 ; j < 101 ; j += 10) { for (k = 0 ; k < 101 ; k += 10) { for (l = 0 ; l < 101 ; l += 10) { document.getElementById(‘output’).innerHTML += `<div style=’background:rgb(${j}%, ${k}%, ${l}%)’></div>\n` } } } </script> </body> </html> Результат загрузки примера в браузер показан на рис. 21.1. При просмотре картинки можно изменять масштаб изображения в браузере, чтобы увеличивать и уменьшать мелкие детали в цветовых полосах. В примере начиная со строки 12 в разделе <script> задаются три вложенных цикла JavaScript. Значения переменных этих циклов j, k и l увеличиваются в диапазоне от 0 до 100 с шагом 10 за каждый проход цикла. В результате в переменной l во внутреннем цикле постоянно перебираются значения 0, 10, 20 и так далее до 100, а затем все начинается снова, при этом значение переменной k в среднем цикле увеличивается на 10, а внутренний цикл запускается снова и снова и так далее, пока внешний цикл, наконец, не увеличится на 10 после задания 100 элементов <div> (и далее после задания каждых 100 элементов). В итоге во внутреннем цикле пройдет тысяча итераций, в среднем — сотня, а во внешнем — десять. Получается, что к функции rgb() в строке 16 применяется диапазон значений красного, зеленого и синего цвета в процентах от 0 до 100 с шагом 10. Код может проходить все циклы с увеличением значений их переменных на единицу, но тогда получился бы 100 × 100 × 100 (или миллион) элементов <div>, что заняло бы много времени и, скорее всего, привело бы к сбою работы браузера. При уменьшении общего числа элементов <div> до тысячи код работает достаточно быстро, и при этом получается весьма неплохая диаграмма цветовых полос, в которой (если увеличить масштаб изображения в браузере, а затем прокрутить картинку) можно посмотреть, как уровни синего постоянно меняются в самых маленьких диапазонах, при этом зеленый проходит через следующий уровень диапазонов, а красный проходит через десять крайних диапазонов. Вставка нужных значений происходит в строке 16, где осуществляется доступ к трем значениям шаблона: ${j}, ${k} и ${l}. Текущее значение в переменных при каждом доступе к этим значениям шаблона заменяется на строку, а затем к каждой строке добавляется знак %, и функция rgb() получает значения в процентах. Теперь уже известно, что все эти чудеса происходят по той причине, что вместо одинарных или двойных кавычек для строки используются обратные кавычки, уведомляя тем самым JavaScript о необходимости подстановки значений в шаблон.
314 | Глава 21 Рис. 21.1. Диаграмма RGB-комбинаций, составленных из цветовых полос Ниже приведены только первые несколько из 1000 созданных элементов <div>, в которых можно заметить динамику процесса увеличения значений, задаваемую внешним и средним циклами, для третьих и вторых значений, в то время как первые значения останутся неизменными до создания 100 элементов <div>. <div <div <div <div <div <div <div <div <div <div <div <div <div <div <div <div <div <!-- style="background:rgb(0%, style="background:rgb(0%, style="background:rgb(0%, style="background:rgb(0%, style="background:rgb(0%, style="background:rgb(0%, style="background:rgb(0%, style="background:rgb(0%, style="background:rgb(0%, style="background:rgb(0%, style="background:rgb(0%, style="background:rgb(0%, style="background:rgb(0%, style="background:rgb(0%, style="background:rgb(0%, style="background:rgb(0%, style="background:rgb(0%, etc… --> 0%, 0%)"></div> 0%, 10%)"></div> 0%, 20%)"></div> 0%, 30%)"></div> 0%, 40%)"></div> 0%, 50%)"></div> 0%, 60%)"></div> 0%, 70%)"></div> 0%, 80%)"></div> 0%, 90%)"></div> 0%, 100%)"></div> 10%, 0%)"></div> 10%, 10%)"></div> 10%, 20%)"></div> 10%, 30%)"></div> 10%, 40%)"></div> 10%, 50%)"></div>
Цвета и прозрачность | 315 При желании увидеть весь вывод, создаваемый этим кодом, можете перед закрывающим тегом </script> вставить следующую строку, записывающую копию кода HTML в консоль разработчика: console.log(document.getElementById('output').innerHTML) Использование цветового круга Цветовые полосы могут показаться вполне подходящим средством выбора цвета, если, конечно, согласиться с прокруткой сотен (или даже тысяч) строк, но если нужен беглый обзор максимально возможного количества цветов с плавным переходом между ними, то можно воспользоваться цветовым кругом. В примере 21.2 для создания такого цветового круга с цветами радуги в качестве точек остановки цвета используется конический градиент, причем для получения плавного цветового градиента по всему периметру, как показано на рис. 21.2, первый и последний цвета совершенно одинаковы. Рис. 21.2. Цветовой круг, созданный с помощью конического градиента Пример 21.2 1. 2. 3. <!DOCTYPE html> <head> <title>RGB Color Wheel</title>
316 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. | Глава 21 <style> #wheel { width height border-radius background : : : : 400px; 400px; 50%; conic-gradient( red, yellow, lime, aqua, blue, magenta, red); } </style> </head> <body> <center> <div id=’wheel’></div> </center> </body> </html> В этом примере стилевые установки применяются к элементу <div> с идентификатором wheel, чтобы задать ему ширину и высоту 400 пикселей, радиус границы 50%, чтобы сделать его круглым, а затем применить последовательность цветов радуги в виде конического градиента по ходу часовой стрелки, начиная с позиции 12 часов и продолжая далее по кругу. Этот цветовой круг будет в сфере наших интересов на протяжении всей главы, особенно когда начнется рассмотрение порядка использования вместо RGB формата HSL (в котором задаются оттенок, насыщенность и яркость), поскольку заметно, что если начать отсчет сверху, то красный цвет занимает положение на отметке 0 градусов, зеленый находится под углом 120 градусов, а синий — под углом 240 градусов от вершины, а все остальные цвета находятся между этими основными. Кроме того, цветовое пространство на основе голубого, пурпурного и желтого цветов (CMY), используемое при печати на бумаге (наряду с черным и поэтому называемое CMYK), также просматривается в этом цветовом круге соответственно при 180, 300 и 60 градусах, и все их позиции находятся на равном удалении от позиций цветов RGB. Вскоре станет понятно, что, обладая этими знаниями, можно абсолютно однозначно выбрать цвет, просто указав одно значение — количество градусов по ходу цветового колеса, на котором он расположен, и это значение может быть выражено числом с плавающей точкой или целым числом. RGBA-цвета Использование функций для отображения цветов дает еще одно преимущество: если требуется воспользоваться еще и прозрачностью, вместо rgb() можно применить функцию rgba(), где буква «a» означает альфа-прозрачность.
Цвета и прозрачность | 317 Чтобы показать это в работе, код примера 21.3 рисует желтый фон, а затем на него накладывается градиент синего цвета, прозрачность которого изменяется слева направо от полностью непрозрачного до полностью прозрачного. Пример 21.3 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. <!DOCTYPE html> <head> <title>Using RGBA</title> <style> #outer { position : relative; } .box { position : absolute; width : 100%; height : 200px; } #box1 { background : yellow; } #box2 { top : 100px; background : linear-gradient(to right, rgba(0, 0, 255, 1), rgba(0, 0, 255, 0) ); } </style> </head> <body> <div id='outer'> <div class='box' id='box1'></div> <div class='box' id='box2'></div> </div> </body> </html> Как это выглядит при загрузке в браузер, показано на рис. 21.3. Здесь в качестве контейнера для двух дочерних элементов с идентификаторами box1 и box2 создается элемент с идентификатором outer. А для класса box, который будет использоваться для элементов с идентификаторами box1 и box2, задается абсолютное позиционирование, позволяющее им накладываться друг на друга. Для элемента box1 указывается сплошной желтый фон, а для box2 с помощью функции rgba() со значениями 0 для красного, 0 для зеленого и 255 для синего компонента задается сплошной синий цвет. Он применяется к элементу в виде линейного градиента с альфа-прозрачностью, постепенно меняющейся от полной непрозрачности (со значением 1) до полной прозрачности (со значением 0). Иными словами, с переходом от первого ко второму набору значений: rgba(0, 0, 255, 1) rgba(0, 0, 255, 0) Для элемента с идентификатором box2 задано также свойство top со значением 100 пикселей, поэтому он перемещается на половину высоты элемента с идентификатором box1 вниз, чтобы можно было увидеть эффекты, заданные как для box1, так и для box2, а также результат наложения этой пары элементов друг на друга.
318 | Глава 21 Рис. 21.3. Наложение сплошного и прозрачного градиентного цвета На рисунке видны три отдельных части. Вверху сплошной желтый цвет, а внизу сплошной синий, медленно переходящий в полностью прозрачный, обнажая имеющийся под ним белый фон. А вот в середине синий цвет медленно переходит от синего к желтому, демонстрируя эффект увеличения прозрачности или же уменьшения непрозрачности (что одно и то же), сначала смешиваясь с желтым цветом и, наконец, проявляя его в полной мере. Функцию rgba() можно использовать в любом месте установки цвета в CSS, а не только в градиентах, но здесь использовался градиент, чтобы показать, насколько точно можно устанавливать альфа-прозрачность цвета, демонстрируя широкий диапазон значений в одном изображении. HSL-цвета А теперь давайте рассмотрим уже упоминавшуюся здесь функцию hsl(), предназначенную для задания цвета на основе оттенка, насыщенности и яркости. Как ни странно, чтобы показать цветовой круг со всеми оттенками, насыщенностью и яркостью, в примере 21.4 для создания цветового круга HSL, показанного на рис. 21.4, используются обычные названия цветов и функция rgba(): Пример 21.4 1. 2. 3. 4. <!DOCTYPE html> <head> <title>An HSL Color Wheel</title> <style>
Цвета и прозрачность 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. #outer { position : relative; width : 400px; margin : auto; .wheel { position : absolute; width : 400px; height : 400px; border-radius : 50%; #wheel1 { background : conic-gradient( red, yellow, lime, aqua, blue, magenta, red); #wheel2 { background : radial-gradient( rgba(255, 255, 255, 1), rgba(255, 255, 255, 0)); </style> </head> <body> <div id='outer'> <div class='wheel' id='wheel1'></div> <div class='wheel' id='wheel2'></div> </div> </body> </html> | 319 } } } } У получаемого здесь изображения много общего с создаваемым кодом примера 21.2, с той лишь разницей, что на цветовой круг наложен второй градиент. Этот градиент, заданный в строке 15, радиальный с переходом от центра к краям с прорисовкой чисто белого цвета, но в нем задается переход по окружности от полной непрозрачности к полной прозрачности. В цветовом пространстве HSL определяется не только используемый цвет (оттенок), но также насыщенность (количество этого цвета) и яркость (степень его яркости). Поэтому, чтобы максимально приблизиться к цветовому кругу HSL, в центре изображения на рис. 21.4 — уменьшенная насыщенность и цвет, при переходе к краям происходит их увеличение. Этот пример не показывает идеальный цветовой круг HSL, но в результате выполнения его кода мы получаем достаточно близкое представление о нем. Это позволяет использовать рисунок, чтобы разобраться в работе функции hsl(). Первое значение, передаваемое функции (оттенок), — это расстояние от вершины по ходу цветового круга, на котором может располагаться цвет. Это значение должно быть указано в градусах, а не в процентах. Второе значение (насыщенность) — это расстояние от центра цветового круга до края, указанное в процентах. В центре цвета практически нет, а край представляет 100%-ную насыщенность этого цвета. И последнее (не показанное на цветовом круге HSL) значение (яркость) показывает, насколько ярким должен быть цвет. Это значение выражается в процентах, и значение в 50% считают нейтральным и используют по умолчанию.
320 | Глава 21 Рис. 21.4. Цветовой круг HSL Теперь, разобравшись в особенностях работы функции hsl(), рассмотрим пример 21.5, код которого выводит на экран широкий спектр поддерживаемых значений в виде диаграммы цветовых полос, показанной на рис. 21.5. Пример 21.5 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. <!DOCTYPE html> <html> <head> <title>HSL Colors</title> <style> div { height : 1px; } </style> </head> <body> <output id='output'></output> <script> for (j = 0 ; j < 360 ; j += 36) { for (k = 0 ; k < 101 ; k += 10) { document.getElementById('output').innerHTML += `<div style='background:hsl(${j}, ${k}%, 50%)'></div>\n` } }
Цвета и прозрачность 18. 19. 20. | 321 </script> </body> </html> Рис. 21.5. Широкий спектр значений оттенка и насыщенности В отличие от кода примера 21.1, здесь используются только два цикла, поскольку значение яркости привязано к 50%: это стандартная величина яркости, и любые значения ниже него будут намного темнее, вплоть до черного со значением 0%, или намного светлее, вплоть до белого со значением 100%. При желании увидеть HTML-код, сгенерированный сценарием, можно непосредственно перед закрывающей инструкцией </script> вставить показанную ниже строку, после чего можно будет просмотреть код в консоли разработчика: console.log(document.getElementById('output').innerHTML) Применение прозрачности И наконец, если нужно просто задать элементу степень прозрачности, не задавая никаких цветов, можно воспользоваться свойством opacity, как в примере 21.6, где
322 | Глава 21 отображаются десять элементов <div>, и у каждого из них прозрачность меньше, чем у предыдущего. Пример 21.6 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. <!DOCTYPE html> <html> <head> <title>Opacity</title> <style> div { background : blue; font : bold 12pt Monospace; padding : 1px 3px; } </style> </head> <body> <div style='opacity:0.0'>Opacity:0.0</div> <div style='opacity:0.1'>Opacity:0.1</div> <div style='opacity:0.2'>Opacity:0.2</div> <div style='opacity:0.3'>Opacity:0.3</div> <div style='opacity:0.4'>Opacity:0.4</div> <div style='opacity:0.5'>Opacity:0.5</div> <div style='opacity:0.6'>Opacity:0.6</div> <div style='opacity:0.7'>Opacity:0.7</div> <div style='opacity:0.8'>Opacity:0.8</div> <div style='opacity:0.9'>Opacity:0.9</div> <div style='opacity:1.0'>Opacity:1.0</div> </body> </html> Рис. 21.6. Различные уровни непрозрачности элемента
Цвета и прозрачность | 323 На рис. 21.6 можно увидеть результат простого ввода значений от 0 для отсутствия непрозрачности (полной прозрачности) и до 1 для полной непрозрачности (отсутствия прозрачности), и на этом все. Заключение И на этом изучение использования цветов CSS3 завершается. Теперь можно будет четко указывать нужные цвета теми способами, которые наиболее полно соответствуют вашим представлениям о выборе цвета. В следующей главе наступит черед обратить внимание на текстовые эффекты и веб-шрифты.
ГЛАВА 22 Текстовые эффекты и шрифты Введение Когда создавался CSS3, стилизация текста уже была достаточно развитой, но, чтобы Интернет мог серьезно конкурировать с возможностями печатных СМИ, предстояло еще очень многое сделать. В плане развития было представлено множество новых функций и способов стилизации текста и шрифтов, в частности, касательно применения теней, наложения текста, разнотипных переносов слов, а также была устранена зависимость от использования только тех шрифтов, которые предлагались браузерами или операционными системами за счет поддержки веб-шрифтов, ко многим из которых такие компании, как Google, теперь открыли бесплатный доступ. Также пересмотрели блочную модель с целью добавления поддержки изменения размеров блока, позволяющей решать, к чему применяются размеры, задаваемые объекту: к элементу, включая любые отступы и (или) границы, или только к содержимому элемента, чтобы отступы и границы считались дополнениями к этим размерам. И чтобы помочь пользователям управлять областями ввода, размер которых им не по нраву, появилась возможность разрешать им изменять размер элементов, а чтобы усилить визуализацию текущей позиции фокуса в документе, было улучшено выделение фокуса с разрешением его стилевого оформления. Структура В этой главе рассматриваются следующие темы:  Изучение всех тонкостей изменения размеров блока и соотнесения этих разме- ров с его содержимым.  Изучение способов управления текстом в случаях его выхода и невыхода за гра- ницы элемента.  Приобретение возможности работы с очень длинными словами и поддержки изменения размеров пользовательских элементов.  Получение полного представления о применении теней и использовании веб- шрифтов.
326 | Глава 22 Цели Цель главы заключается в изучении различных функций, связанных с текстом, помогающих в создании наиболее привлекательных макетов CSS. В их числе — тонкое управление шириной и высотой элементов в соответствии с их содержимым, отступами и границами, управление слишком длинными словами, разбиением и переполнением слов, прикрепление к тексту привлекательных теней, а также загрузка и использование любого из многих тысяч веб-шрифтов, наиболее соответствующего тематике реализуемого проекта. Задание размеров блока Вопросы стилизации текста относятся не только к тексту как таковому, поскольку принципиальное значение для процесса проектирования имеет также расположение текста и содержащих его элементов на странице (или экране). Поэтому, прежде чем перейти к возможностям работы со шрифтами и с самим текстом, давайте посмотрим на контейнеры для шрифтов, иными словами, на их элементы и на то, как задается их стилевое оформление. Вам приходилось когда-нибудь при разработке CSS ошибаться, забывая рассчитать отступы и границы? Теперь все это осталось в прошлом, поскольку уже в самом начале можно указать способы применения заданных вами размеров. По умолчанию для свойства box-sizing используется значение content-box, при этом CSS-размеры ширины и высоты относятся к области содержимого элемента, и любые отступы и границы игнорируются. Это эквивалентно следующей установке: box-sizing: content-box; Но при использовании значения border-box, заставляющего все отступы и границы помещаться в заданном пространстве, элементу можно указать конкретную ширину и высоту, для чего используют такую установку: box-sizing: border-box; При этом любая толщина границы или отступа должна быть сжата внутри указанной области, уменьшая, в силу необходимости, часть содержимого. В примере 22.1 создается пара одинаковых элементов с той лишь разницей, что для свойства boxsizing одного из них выбрано значение content-box, а другого — border-box. Пример 22.1 1. 2. 3. 4. 5. 6. 7. <!DOCTYPE html> <html> <head> <title>Box sizing</title> <style> .box { font : bold 14pt serif; border : 10px solid red;
Текстовые эффекты и шрифты 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. | 327 width : 200px; height : 100px; padding : 20px; margin-right : 20px; float : left; display : flex; justify-content : center; align-items : center; text-align : center; color : blue; background : lime; background-clip : content-box; } #box1 { box-sizing : content-box; } #box2 { box-sizing : border-box; } </style> </head> <body> <div class='box' id='box1'>Living in a box</div> <div class='box' id='box2'>Living in a box</div> </body> </html> Для обоих элементов, отнесенных к классу box, заданы цвет и стиль шрифта, 10-пиксельная красная граница, а также 20-пиксельный внутренний отступ. Другие установки CSS элементам с этим классом задают размер 200 × 100 пикселей и гарантию, что элементы будут размещены на одной линии, а содержимое — располагаться по центру. Кроме того, свойство background-clip для этого класса устанавливается только на область содержимого content-box, поэтому лаймовый фон в каждом случае точно указывает на границы области. На рис. 22.1 можно увидеть, что у первого элемента действительно есть 10-пиксельная красная граница, внутри которой 20 пикселей отступа, а затем область содержимого размером 200 × 100 пикселей с текстом. Рис. 22.1. Задание размеров блока по умолчанию и по границе
328 | Глава 22 А вот второй элемент, включая отступы и границы, точно соответствует размеру области содержимого первого. Это связано с тем, что для свойства box-sizing второго элемента установлено значение border-box, стало быть, все границы и отступы должны помещаться по ширине и высоте в заданные 200 × 100 пикселей. В результате область содержимого уменьшается до оставшегося пространства, которое в данном случае составляет 140 × 40 пикселей после вычитания 20 пикселей отступа и 10 пикселей границы с каждой стороны, что в сумме дает уменьшение на 60 пикселей в каждом направлении. Наиболее полезным это свойство может оказаться в условиях, когда отступы и (или) границы элементов в макете изменяются независимо. Если заставить эти части элемента находиться в пределах ширины и высоты, предоставляемых вашим макетом, установив для свойства box-sizing таких элементов значение border-box, то эти события могут изменить или, что еще хуже, сломать дизайн макета. Текстовое переполнение Иногда могут возникать потребности в сокращении текста, например в случаях, подобных применению поисковой системы Google, в которой часто цитируется текст с веб-сайтов, обрезаемый многоточием, означающим «и так далее», например … Результат показан на рис. 22.2. Рис. 22.2. Текстовое переполнение, усеченное двумя разными способами Это лаконичный способ создания отрывков определенного размера, разъясняющий читателям ситуацию. Без этой функции окончания отрывков могут показаться грубыми и неприглядными. В примере 22.2 создается пара элементов с одинаковым содержимым, но, как показано на рис. 22.2, с разной обработкой переполнения, где во втором элементе текст аккуратно обрезается в подходящем месте слова многоточием. Пример 22.2 1. 2. 3. <!DOCTYPE html> <html> <head>
Текстовые эффекты и шрифты 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. | 329 <title>Text Overflow</title> <style> .box { font : bold 16pt serif; border : 2px solid blue; width : 640px; padding : 5px; margin : 5px 0; float : left; color : yellow; background : olive; white-space : nowrap; overflow : hidden; } #box1 { text-overflow : clip; } #box2 { text-overflow : ellipsis; } </style> </head> <body> <div class=’box’ id=’box1’>Straw, no too stupid a fad, I put soot on warts – now read that backwards.</div> <div class=’box’ id=’box2’>Straw, no too stupid a fad, I put soot on warts – now read that backwards.</div> </body> </html> Чтобы свойство text-overflow возымело какой-либо эффект, сначала для свойства white-space нужно установить значение nowrap, а для свойства overflow — hidden. Без установки для свойства white-space значения nowrap текст будет просто перетекать со строки на строку, а без установки для свойства overflow значения hidden текст, если ему понадобится, будет выходить за пределы элемента, создавая хаос на странице. Перенос длинных слов В главе 20 «Свойства блока и текста» был показан способ автоматического разрыва слов и их переноса на следующую строку при выходе за границы элемента. Но есть особый, неучтенный случай, когда имеется слово, которое само по себе шире элемента, в котором оно находится. В подобных случаях можно воспользоваться свойством word-wrap со значением break-word, принуждающим длинные слова к переносу: word-wrap : break-word; В примере 22.3 создаются два элемента, в каждом из которых в качестве образа отображается одно и то же длинное слово Antidisestablishmentarianism. Это слово явно длиннее своих элементов, поэтому получившееся переполнение, как показано на рис. 22.3, обрабатывается по-разному.
330 | Глава 22 Рис. 22.3. Слишком длинное слово обрабатывается двумя разными способами Пример 22.3 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. <!DOCTYPE html> <html> <head> <title>Wrapping Very Long Words</title> <style> .wrap { border : 2px solid olive; font : bold 24pt monospace; width : 300px; height : 150px; background : lime; color : purple; } #wrap1 { word-wrap : normal; } #wrap2 { word-wrap : break-word; } </style> </head> <body> <div class=’wrap’ id=’wrap1’> Antidisestablishmentarianism is one of the longest words </div> <br> <div class=’wrap’ id=’wrap2’> Antidisestablishmentarianism
Текстовые эффекты и шрифты 24. 25. 26. 27. | 331 is one of the longest words </div> </body> </html> В этом примере переполнение элемента не скрыто, чтобы можно было четко проследить происходящее. В первом элементе длинное слово выходит за его границы, поскольку для свойства word-wrap установлено значение normal, и, если бы переполнение было скрыто, мы бы просто не увидели вторую половину слова, поскольку она стала бы невидимой. А во втором элементе свойство word-wrap имеет значение break-word и поэтому длинное слово разрывается, чтобы соответствовать размеру элемента, путем помещения остальной его части на следующую строку. Изменение размеров элементов пользователем Иногда появляется возможность помочь своим пользователям, позволяя им вырваться из ограничений созданного для них макета и перетаскивать угол элемента с целью изменения его размеров. Больше всего это может касаться поля ввода, где предоставлено достаточно места для большинства намеченных целей, но все же хочется, чтобы пользователь мог вводить более длинные данные, если он того пожелает, не просто за счет прокручивания (что не всегда бывает удачным вариантом для небольших элементов), а путем изменения размера элемента по своему усмотрению. В примере 22.4 создается четыре разных элемента: два элемента <div>, элемент и элемент <table>. В первом из них возможность изменения размеров пользователем не поддерживается, поскольку его свойству resize присвоено значение none, а вот в других элементах поддерживается, потому что у них этому свойству присвоено другое значение. <output> Пример 22.4 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. <!DOCTYPE html> <html> <head> <title>Element Resizing</title> <style> .box { border : 2px solid purple; font : bold 12pt Arial; margin-right : 10px; width : 100px; height : 100px; background : darkorange; color : yellow; overflow : auto;
332 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. | Глава 22 float : left; } #box1 { resize : none; } #box2 { resize : horizontal; } #box3 { resize : vertical; } #box4 { resize : both; } </style> </head> <body> <div class=’box’ id=’box1’> Twas brillig, and the slithy toves did gyre and gimble in the wabe; all mimsy were the borogoves, and the mome raths outgrabe. </div> <div class=’box’ id=’box2’> Twas brillig, and the slithy toves did gyre and gimble in the wabe; all mimsy were the borogoves, and the mome raths outgrabe. </div> <output class=’box’ id=’box3’> Twas brillig, and the slithy toves did gyre and gimble in the wabe; all mimsy were the borogoves, and the mome raths outgrabe. </output> <table> <tr> <td class=’box’ id=’box4’> Twas brillig, and the slithy toves did gyre and gimble in the wabe; all mimsy were the borogoves, and the mome raths outgrabe. </td> </tr> </table> </body> </html> В этом примере первому элементу не предоставили возможность изменения размеров пользователем, поэтому в нем доступны только полосы прокрутки. Для второго элемента было разрешено изменять размер только в горизонтальном направлении, для третьего — только в вертикальном, а последнему элементу предоставили полное право изменять размер в обоих направлениях. Именно такие эффекты изменения размера в трех элементах можно увидеть на рис. 22.4. Такой результат достигнут за счет предоставления свойству resize значений none, и both для стилевого оформления элементов с идентификаторами, соответственно, box1, box2, box3 и box4. Если приглядеться к нижним правым углам элементов со второго по четвертый, то можно заметить там небольшой значок horizontal, vertical
Текстовые эффекты и шрифты | 333 с двумя диагональными линиями, указывающий пользователю, что размер элемента можно изменять, перетаскивая границы элемента за этот угол. Рис. 22.4. Четыре возможных параметра изменения размера в действии Выделение фокуса Раз уж разговор только что шел об изменении пользователем размера поля ввода, то лучшего места для рассмотрения свойства layout-offset, чем это, пожалуй, не найти. Использование этого свойства дает возможность увеличить контур, размещаемый вокруг элемента при получении этим элементом фокуса. В примере 22.5 создаются три разных элемента, каждый из которых может получить фокус, и чтобы увидеть результат, можно по ним перемещаться или же менять фокус по-другому. Пример 22.5 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. <!DOCTYPE html> <html> <head> <title>Outline</title> <style> html { font : bold 14pt Arial; } html *:focus { outline : dashed thick; outline-offset : 10px; } </style> </head> <body> <ul> <p><a href=’nowhere’>A link</a></p> <p><input type=’text’></p>
334 15. 16. 17. 18. | Глава 22 <p><a href=’alsonowhere’>Another link</a></p> </ul> </body> </html> Свойство layout-offset поддерживает все значения размера CSS, например 10px, 0.2em и т. д. Результат выполнения кода примера показан на рис. 22.5. Рис. 22.5. Элемент ввода получил фокус, после чего его граница сместилась на 10 пикселей Текстовые тени В главе 20 «Свойства блока и текста» рассматривались способы создания теней для элементов. А теперь посмотрим, как с помощью свойства text-shadow можно создать тени только для текста. В примере 22.6 это свойство используется четыре раза в разных классах, и тени, в соответствии с присваиваемыми свойству значениями top-left, top-right, bottom-left и bottom-right, будут помещаться в левый верхний, правый верхний, левый нижний и правый нижний угол элемента. Пример 22.6 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. <!DOCTYPE html> <html> <head> <title>Text Shadows</title> <style> .shadow { color : font : #shadow1 { text-shadow : #shadow2 { text-shadow : #shadow3 { text-shadow : #shadow4 { text-shadow : </style> </head> blue; bold 64pt -5px -5px 5px -5px -5px 5px 5px 5px Arial ; 8px #555; 8px #555; 8px #555; 8px #555; } } } } }
Текстовые эффекты и шрифты 14. 15. 16. 17. 18. 19. 20. 21. 22. <body> <center> <span class='shadow' <span class='shadow' <span class='shadow' <span class='shadow' </center> </body> </html> | 335 id='shadow1'>Me</span> &nbsp; id='shadow2'>and</span> &nbsp; id='shadow3'>my</span> &nbsp; id='shadow4'>shadow</span> Значения, предоставляемые свойству text-shadow, задают смещение по вертикали и горизонтали, которое может быть отрицательным, нулевым или положительным, за которым следует количество пикселей, на которые следует распространить эффект размытия, и, наконец, используемый цвет. Результат загрузки этого примера в браузер показан на рис. 22.6. Рис. 22.6. Набор теней с разным смещением Чем больше смещение, тем сильнее текст выделяется на странице, и тут нетрудно переборщить. Применяемое размытие при низких значениях будет слишком резким и ярко окрашенным, а при слишком высоких значениях тени будут сильно размываться и станут нечеткими и излишне светлыми. В качестве цвета обычно используется оттенок серого или черного, если не будет желания подобрать оттенок под цвет фона страницы. Если цвет не указывать, будет использоваться цвет текста. Если не указывать размытие, то под текстом будет размещена его точная копия с указанным смещением и без размытия. А вот для смещения нужно предоставлять оба значения. Веб-шрифты И наконец, настал черед еще одной не менее важной темы этой главы. Речь пойдет о множестве веб-шрифтов, имеющихся в вашем распоряжении. Как бывает с любыми шрифтами, эти шрифты можно покупать поштучно, пакетами или по подписке для применения на вашем собственном или на другом веб-сервере. Или же можно воспользоваться совершенно бесплатной огромной библиотекой шрифтов дос-
336 | Глава 22 тупной на таких сайтах, как Google Fonts, откуда мы и будем брать шрифты для текущего раздела. Например, чтобы импортировать Google-шрифт под названием Dancing Script, нужно в разделе <head> документа разместить следующую инструкцию: <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Dancing+Script"> Тем самым браузер узнает, что ему нужно импортировать таблицу стилей CSS с указанного адреса. После этого к шрифту можно будет обращаться из кода CSS, возможно, задав для его применения стилевое оформление класса по имени dancing: .dancing { font-family : "Dancing Script", cursive, serif; } Теперь этот класс можно просто указать в любом элементе, задав отображение его содержимого с использованием этого шрифта: <span class='dancing'>This is Dancing Script</span> В примере 22.7 показанные выше инструкции были объединены в один документ с отрывком из стихотворения Льюиса Кэрролла. Пример 22.7 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. <!DOCTYPE html> <html> <head> <title>Web Fonts</title> <style> #poem { font-size : 24pt; } .dancing { font-family : "Dancing Script", cursive, serif; } </style> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Dancing+Script"> </head> <body> <div class='dancing' id='poem'> Twas brillig, and the slithy toves did gyre and gimble in the wabe; all mimsy were the borogoves, and the mome raths outgrabe. "Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Beware the Jubjub bird, and shun the frumious Bandersnatch!. </div> </body> </html> Отображаемый текст здесь находится в элементе <div> с идентификатором poem стихотворения и относится к классу dancing. Для свойства font-size, принадлежащего элементу с идентификатором poem, устанавливается значение 24pt, а для свойства font-family элементов класса dancing указывается семейство шрифтов Dancing Script,
Текстовые эффекты и шрифты | 337 и на всякий случай, если шрифт по какой-то причине будет недоступен, указывается и разумная альтернатива в виде семейства наклонных шрифтов с засечками. Загрузка самого шрифта задается в строках 9 и 10 посредством таблицы стилей, которая находится по указанному URL-адресу. Результат выполнения кода этого примера показан на рис. 22.7. Рис. 22.7. Стихотворение, отображаемое шрифтом Google Dancing Script Если доступ к шрифту уже имеется и его нужно загрузить, можно воспользоваться стилевой установкой @font-face, указав имя и URL-адрес местонахождения, откуда браузер должен загрузить шрифт. Принимаются как шрифты TrueType (.ttf), так и OpenType (.otf), а также файлы форматов веб-шрифтов .woff и .woff2. Например, если уже имеется шрифт, сохраненный как Sacramento-Regular.ttf, можно воспользоваться следующим кодом: 1. 2. 3. @font-face { font-family : "Sacramento Regular"; src : url('Sacramento-Regular.ttf'); } Затем, при желании, можно объявить стилевое оформление класса, упростив доступ к шрифту: .sacramento { font-family : "Sacramento Regular"; } После чего для использования шрифта останется только в коде HTML отнести нужный элемент к нужному классу: <span class='sacramento'>This is Sacramento Regular</span> Пример 22.8 — переделанная под именно такую локальную загрузку шрифта версия предыдущего примера. Пример 22.8 1. 2. 3. 4. <!DOCTYPE html> <html> <head> <title>Local Fonts</title>
338 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. | Глава 22 <style> #poem { font-size : 24pt; } @font-face { font-family : "Sacramento Regular"; src : url('Sacramento-Regular.ttf'); } .sacramento { font-family : "Sacramento Regular"; } </style> </head> <body> <div class='sacramento' id='poem'> Twas brillig, and the slithy toves did gyre and gimble in the wabe; all mimsy were the borogoves, and the mome raths outgrabe. "Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Beware the Jubjub bird, and shun the frumious Bandersnatch!. </div> </body> </html> Результат выполнения кода примера показан на рис. 22.8. Рис. 22.8. Применение локальной загрузки шрифта Полное описание способов импортирования шрифтов с использованием правила @font-face (локально, как показано здесь, либо из других источников в Интернете), можно найти по следующему URL-адресу, где также можно обнаружить целый ряд связанных свойств для тонкой настройки отображения шрифтов : https://tinyurl.com/cssfont-face Для просмотра имеющихся (на данный момент) 1300+ бесплатных шрифтов, предоставляемых Google, и получения доступа к ним, перейдите по следующему URLадресу, где их можно загрузить для локального использования. Если же щелкнуть кнопкой мыши на названии понравившегося шрифта, чтобы выбрать его стиль, а
Текстовые эффекты и шрифты | 339 затем щелкнуть на значке в виде трех квадратов и знака + в правом верхнем углу веб-страницы (чтобы открыть диалоговое окно выбранного семейства — Selected family), появятся правила CSS, которые можно скопировать и вставить в свой код для использования этих правил: fonts.google.com Но если хотите, можете не копировать и вставлять этот код, а просто последовать инструкциям, изложенным в разделе и скопировать только URL-адрес местоположения таблицы стилей для шрифта, находящейся на сервере Google, после чего воспользоваться этой таблицей точно также, как и в приведенных здесь примерах, и тогда все получится в наилучшем виде. Заключение На этом изучение множества новых текстовых эффектов, блочной модели, теней и шрифтов, доступных в CSS3, завершается. На данный момент из вас уже должен был получиться специалист по использованию шрифтов, способный создавать вебпроекты, соответствующие всему лучшему, что может предложить мир печати. В следующей главе предстоит углубленное изучение целого ряда более сложных и интересных функций CSS3, таких как применение преобразований для создания просто поразительных эффектов.
ГЛАВА 23 Двумерные преобразования Автору посчастливилось писать на тему в ходе разработки CSS3. Тогда реализация новых функций в разных браузерах шла несколько бессистемно. Иногда один браузер не поддерживал функцию, а его конкурент поддерживал, но не использовал рекомендуемые имена и значения свойств. Бывало, браузер вообще шел вразрез со стандартом, и функцию в нем реализовывали совершенно иначе, его создатели даже не придерживались единого отображения результатов ее работы. Веб-разработчикам, стремящимся использовать эти функции, все походило на хождение по минному полю, требующему большого объема условного кода, срабатывавшего в зависимости от сборки браузера и обнаруженной на хосте операционной системы. Но войны браузеров завершились, и их подавляющее большинство остановилось на варианте, предложенном открытым исходным кодом Chromium, используемым в браузерах Google Chrome, Microsoft Edge и Opera. А есть еще и Safari от Apple, но он, за исключением некоторых мелочей, вполне сопоставим с другими браузерами. Введение Все, о чем говорится в этой главе, стало уже куда приятнее и понятнее, чем несколько лет назад, как для автора, так и (надеюсь) для читателей, потому что теперь имеется стандартный набор свойств и значений преобразований, который может применяться во всех браузерах и на всех платформах. Здесь можно будет убедиться в том, насколько простой и логичной стала работа с двумерными преобразованиями. Благодаря им предоставляется возможность получать по мере надобности специальные эффекты: легко и быстро масштабировать и поворачивать объекты и даже наклонять их. А если понадобится, можно будет научиться использовать матрицы и создавать на их основе собственные преобразования и переходы. Структура В этой главе рассматриваются следующие темы:  Изучение всех двумерных преобразований, доступных в CSS3.  Освоение способов комбинирования переходов с преобразованиями.
342 | Глава 23  Применение приемов произвольного масштабирования, вращения и наклонения объектов.  Изучение способов использования матриц для получения комбинированных эф- фектов. Цели Здесь вы научитесь изменять формы и расположение объектов. Освоив материал главы, вы станете специалистом по вращениям, перемещениям, наклонам, масштабированиям, а также плавным переходам между всеми преобразованиями с помощью применения эффектов анимации. Вы также научитесь использовать их со всеми другими полезными свойствами. Преобразования В CSS3 предоставляется более 20 различных типов преобразований, применимых к элементам HTML, и работа со всеми ними ведется через свойство transform. Есть переходы, представляющие собой изменение положения на плоскости, масштабирования, уменьшение или увеличение объектов в одном или нескольких измерениях, вращения, наклоны и, если этого еще недостаточно, произвольные преобразования с использованием матриц. Кроме того, можно располагать не только преобразованиями, но и свойством перехода transition, с помощью которого можно эти преобразования анимировать. Сочетание этих двух свойств позволяет создавать весьма интерактивные и динамичные веб-страницы. В примере 23.1 создается оранжевый прямоугольник с красной рамкой, после чего он размещается в абсолютной позиции. Над ним размещаются три кнопки, с помощью которых можно заставить блок двигаться в различных направлениях благодаря применению к ним CSS-правил реагирования при наведении курсора мыши. Пример 23.1 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. <!DOCTYPE html> <html> <head> <title>Translation and Transition</title> <style> #box { position : absolute; top : 50px; left : 50px; width : 100px; height : 100px; background : orange;
Двумерные преобразования 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. border transition #x:hover ~ #box { transform #y:hover ~ #box { transform #b:hover ~ #box { transform </style> </head> <body> <button id=’x’>Right</button> <button id=’y’>Down </button> <button id=’b’>Both </button> <div id=’box’></div> </body> </html> : : : : : 5px solid red; all 1s ease-in-out; translateX(100px ); translateY(100px ); translate( 100px, 100px); | 343 } } } } Стилевое оформление элементов с идентификатором box начинается в строке 6, где свойству position присваивают значение absolute, свойствам top и left — значения смещений от границ содержащего их элемента, а также присваиваются значения свойствам width, height, background и border. Все эти свойства применяются к элементу, задаваемому в строке 23. В этом примере в строке 13 есть также и новая установка, использующая свойство перехода transition. Предоставленные ему значения указывают, что все свойства, которые могут измениться, с этого момента должны изменяться в течение 1 секунды и изменения должны начинаться медленно, ускоряться, а затем замедляться, т. е. соответствовать принципу, известному как ease-in-out. Сразу этот эффект не проявляется, но настраивает элемент на то, что при любом будущем изменении какоголибо свойства предписанным образом выполняется переход (или анимация). А теперь разберемся с магической частью. В строках с 14 по 16 есть три правила, выполняемые при наведении курсора мыши применительно к элементам с идентификаторами x, y и b, в качестве которых выступают три кнопки, задаваемые в строках с 20 по 22. С помощью оператора ~ эти правила применяются к родственному элементу с идентификатором box. В результате наведение курсора мыши на любую из кнопок приводит к срабатыванию одного из трех правил преобразования, каждое из которых передает слегка различающиеся значения перемещения по горизонтали и вертикали в функцию translate(), что приводит к перемещению объекта (движению в его двумерной плоскости), которое будет анимировано согласно ранее установленному правилу перехода. При загрузке примера в браузер получается результат, показанный на рис. 23.1. Когда указатель мыши наводят на любую из трех кнопок, блок плавно перемещается в заданном направлении. При отведении указателя от кнопки и в сторону от других кнопок блок автоматически возвращается в исходное положение. И все это без малейшего намека на использование JavaScript. Применение подобной техники с использованием вместо CSS сценария JavaScript потребовало бы функции для доступа, затем для перемещения объекта, а также для возвращения его
344 | Глава 23 в исходную позицию, и все это требовало бы привязки к событиям прохода указателя мыши над кнопками. Для программиста на JavaScript это не составило бы особого труда, но, если правильно пользоваться установками CSS3, в этом нет никакой необходимости! Рис. 23.1. Объект можно перемещать, проводя курсором мыши по кнопкам Переходы Прежде чем продолжить изучение преобразований, давайте сначала выясним возможности, открываемые переходами, для которых можно указать тип желаемой анимации при преобразовании одного или нескольких свойств элемента, после чего браузер автоматически за вас позаботится обо всех промежуточных кадрах. Чтобы настроить переход, нужно установить значения для трех свойств: transition-property transition-duration transition-delay transition-timing-function : : : : свойство; время; время; тип; Для значения свойства перехода transition-property следует назначить хотя бы одно анимируемое свойство (или свойство, подвергаемое переходу), если его значение изменится. В качестве универсального значения для любых свойств, которые могут изменяться, можно воспользоваться значением all. В качестве значения можно указать width, или height, или color, или любое другое свойство, подвергаемое изменению, или же указать через запятые список значений для выборочного перехода в более чем одном свойстве. Для свойства transition-duration следует указать время, обычно всего несколько секунд или даже меньше для анимации, воспринимаемой пользователем (допускаются значения с плавающей точкой), например 3s, 1.5s или .75s и т. д. Точно так можно указать период задержки, в течение которого будет ожидаться запуск перехода. И значения для него могут также выглядеть как 3s, 1.5s или .75s и т. д.
Двумерные преобразования | 345 И наконец, наверное, самая интересная возможность, позволяющая решить, как должна выглядеть анимация, выбор значения, применяемого к свойству transitiontiming-function из следующего перечня:  ease: Медленное начало, ускорение и медленное завершение.  linear: Переходы с постоянной скоростью.  ease-in: Медленное начало с быстрым продолжением до завершения.  ease-out: Быстрое начало, продолжение с той же скоростью и медленное завершение.  ease-in-out: Медленное начало, быстрое продолжение и медленное завершение. Использование любого из значений со словом ease, в отличие от линейного (linear), более механичного по восприятию перехода, обеспечивает более плавное и естественное восприятие. Если нужно еще больше разнообразить переходы, можно создать свою собственную динамику переходов, воспользовавшись функцией cubebezier(), создающей уникальную кривую, которой transition-timing-function может воспользоваться для изменения скорости фаз перехода. К примеру, ниже приведены значения функций, которыми можно воспользоваться для альтернативного способа создания предыдущих пяти типов перехода (ease, linear, ease-in, ease-out и ease-in-out), где они следуют в том же порядке: transition-timing-function transition-timing-function transition-timing-function transition-timing-function transition-timing-function : : : : : cubic-bezier(0.25, cubic-bezier(0, cubic-bezier(0.42, cubic-bezier(0, cubic-bezier(0.42, 0.1, 0, 0, 0, 0, 0.25, 1, 1, 0.58, 0.58, 1); 1); 1); 1); 1); Как и следовало ожидать, в CSS предлагается краткая форма указания всех этих значений свойств с использованием разных имен свойств, и это простое свойство transition. Его использование позволяет передать значения имени свойства для перехода, а затем продолжительность перехода, тип сглаживания перехода и, наконец, любую требуемую задержку: transition : all .3s linear .2s; Просто в качестве еще одного примера, давайте изменим другое значение — фон объекта. Код примера 23.2 предлагаемого для этого изменения, похож на код предыдущего, но настроен только на изменение цвета. Пример 23.2 1. 2. 3. 4. 5. 6. 7. <!DOCTYPE html> <html> <head> <title>Translation and Transition</title> <style> #box { position : absolute; border : 5px solid red;
346 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. | Глава 23 transition top left width height background #b:hover ~ #box { background #g:hover ~ #box { background #c:hover ~ #box { background </style> </head> <body> <button id=’b’>Blue</button> <button id=’g’>Grey</button> <button id=’c’>Cyan</button> <div id=’box’></div> </body> </html> : : : : : : : : : background 1s ease-in-out; 50px; 50px; 100px; 100px; orange; } blue; } grey; } cyan; } В этом примере перемещение указателя мыши по кнопкам, показанным на рис. 23.2, согласно указаниям в строках с 14 по 16, приводит к изменению цвета фона блока. Рис. 23.2. Изменение цвета блока при прохождении указателя мыши над кнопками Можно также заметить, что в строке 8 вместо универсального значения all упоминается только лишь свойство background. В качестве упражнения вам предлагается скомбинировать примеры 23.1 и 23.2, чтобы увидеть, как будет выглядеть сочетание перехода и перемещения. Полное описание функций задания характеристик фаз перехода и смягчения его восприятия можно найти по следующим URL-адресам:  tinyurl.com/trans-timing  tinyurl.com/beziereasing
Двумерные преобразования | 347 Перемещения Сочетание перемещения с переходом демонстрировалось в предыдущей части главы для создания анимации. А теперь давайте посмотрим на конкретные примеры использования функции перемещения translate(). Функция принимает два аргумента: протяженность перемещения объекта по горизонтали и по вертикали. В их качестве могут использоваться отрицательные, нулевые или положительные значения любого типа измерения, включая проценты, но чаще всего используются пиксели. Например, следующие две установки используются для перемещения объекта вправо на 50 пикселей и вниз на 50 пикселей соответственно: transform : translate(50px, 0px); transform : translate( 0px, 50px); Если нужно переместить объект в одном измерении, для достижения тех же результатов можно воспользоваться альтернативными функциями: transform : translateX(50px); transform : translateY(50px); Ожидаемое вскоре свойство translate Кроме того, есть потенциально доступное, но поддерживаемое (на момент написания книги) только браузерами Firefox и Safari обычное свойство перемещения translate, которым можно будет воспользоваться следующим образом: translate : 50px 0px; translate : 0px 50px; Или можно указать только одно значение для перемещения по обоим измерениям на одну и ту же величину: translate : 50px; И можно также указать три значения для перемещения по трем измерениям: translate : 50px 0px 150px; Но свойство translate, в отличие от использования свойства transform с функцией translate(), не заставляет другие элементы страницы обтекать объект, к которому оно применено, и оно (на момент написания книги) не работает в браузерах на основе Chromium. Данный раздел просто оповещает об ожидаемой вскоре, но пока не рекомендуемой для широкого применения функции. Не забывайте, что узнать о доступности той или иной функции в браузерах всегда можно на веб-сайте caniuse.com. Масштабирование С помощью масштабирования можно изменять горизонтальные и (или) вертикальные размеры элемента, используя для этого функцию scale() с двумя аргументами,
348 | Глава 23 или же можно просто изменить один или другой размер с помощью функций ScaleX() или scaleY() с одним аргументом. В примере 23.3 используются все три типа масштабирования. Пример 23.3 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. <!DOCTYPE html> <html> <head> <title>Scaling</title> <style> #box { position : absolute; border : 5px solid red; transition : all 1s ease-in-out; top : 50px; left : 50px; width : 100px; height : 100px; background : orange; } #b:hover ~ #box { transform : scaleX(1.5 ); } #g:hover ~ #box { transform : scaleY(1.5 ); } #c:hover ~ #box { transform : scale( 1.5, 1.5); } </style> </head> <body> <button id=’b’>Stretch X</button> <button id=’g’>Stretch Y</button> <button id=’c’>Stretch Both</button> <div id=’box’></div> </body> </html> Рис. 23.3. Указатель мыши находится над третьей кнопкой, поэтому блок растянут в обоих направлениях
Двумерные преобразования | 349 В строках с 14 по 16 используются функции масштабирования, а в строке 8 снова задается переход в отношении всех свойств. Работу кода можно увидеть, наводя указатель мыши на различные кнопки. В каком бы состоянии ни был блок, при прохождении указателя мыши над другой кнопкой технология CSS осуществляет плавный переход от текущего состояния к новым установкам свойства. Результат загрузки примера в браузер показан на рис. 23.3. Вращение Объекты можно не только растягивать и сжимать, но и вращать на нужное количество градусов по часовой или против часовой стрелки, даже если хотите, несколько раз по кругу. В примере 23.4 выполняются три различных типа поворота блока, используемого в этой главе. Пример 23.4 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. <!DOCTYPE html> <html> <head> <title>Rotation</title> <style> #box { position : absolute; border : 5px solid red; transition : all 1s ease-in-out; text-align : center; color : blue; font : bold 16pt Arial; top : 50px; left : 50px; width : 100px; height : 100px; background : orange; } #b:hover ~ #box { transform : rotate( 90deg); } #g:hover ~ #box { transform : rotate(-180deg); } #c:hover ~ #box { transform : rotate(1080deg); } </style> </head> <body> <button id=’b’>Clockwise 90</button> <button id=’g’>Reverse 180 </button> <button id=’c’>Three loops </button> <div id=’box’>I’m Spinning Around</div> </body> </html>
350 | Глава 23 В примере в блок помещен цветной полужирный текст, позволяющий четко рассмотреть повороты в действии. В строках с 17 по 19 задается поворот на 90 градусов по часовой стрелке, 180 градусов против часовой стрелки и полный трехкратный поворот, соответственно, при каждом проходе указателя мыши над кнопками (рис. 23.4). Рис. 23.4. Блок в процессе вращения Можно, если хотите, указывать значения в радианах. Если вспомнить, то 2 × PI (равное 3,14159…) или 6,28 радиана — это 360 градусов, поэтому фактически работа будет вестись со значениями, относящимися к числу PI. Например, PI соответствует половине окружности в радианах, что эквивалентно 180 градусам, поэтому значение 3.14rad вызывает поворот на 180 градусов, а 1.57rad — поворот на четверть оборота и т. д. Наклон Последнее из преобразований, различаемых по именам, — функция наклона skew(), с помощью которой можно задавать наклон объекта в горизонтальной или в вертикальной плоскости, по часовой или против часовой стрелки. Функция принимает два аргумента: вертикальный и горизонтальный наклон, и именно в таком порядке. В качестве альтернативы для наклона в одном из измерений можно воспользоваться любой из функций skewX() или skewY(). В примере 23.5 вызываются все три типа наклона, и каждый привязан к кнопке, над которой проходит указатель мыши. Пример 23.5 1. 2. 3. 4. <!DOCTYPE html> <html> <head> <title>Skew</title>
Двумерные преобразования 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. | 351 <style> #box { position : absolute; border : 5px solid red; transition : all 1s ease-in-out; top : 50px; left : 50px; width : 100px; height : 100px; background : orange; #x:hover ~ #box { transform : skewX( 30deg ); #y:hover ~ #box { transform : skewY(-30deg ); #b:hover ~ #box { transform : skew( 30deg, -30deg); </style> </head> <body> <button id=’x’>SkewX 30 </button> <button id=’y’>SkewY -30</button> <button id=’b’>Skew Both</button> <div id=’box’></div> </body> </html> } } } } При наклоне прямоугольного элемента одна из сторон перемещается в желаемом направлении, в результате чего соседние стороны растягиваются в длину, образуя параллелограмм. Если наклон задается по часовой стрелке в одном направлении и против часовой стрелки в другом (оба на одинаковую величину), относительные размеры останутся прежними, но элемент станет больше из-за растянутых сторон. Поэтому такой вид наклона не подходит для создания вращений, если только сопутствующее ему увеличение не соответствует вашим намерениям. Результат выполнения примера показан на рис. 23.5. Рис. 23.5. Блок был наклонен против часовой стрелки
352 | Глава 23 Использование матриц Все упомянутые здесь функции преобразований создают весьма привлекательные эффекты, но есть и другие способы преобразования объектов, для применения которых предоставляется функция matrix(), позволяющая создавать свои собственные преобразования. Но у новичков, возможно, возникнет желание придерживаться, по возможности, уже готовых функций, поскольку в этой функции используется перемножение матриц и ей для работы требуется шесть значений. Исходя из этого, при желании создать свои собственные преобразования функции matrix() нужно передать четыре значения, описывающие преобразование, и два для указания перемещения. Назовем их a, b, c, d, x и y. Здесь цель не в том, чтобы научить вас перемножению матриц, для которого в конце раздела приводится ссылка на URL-адрес с дополнительной информацией, а в том, чтобы просто показать результаты изменения некоторых из этих значений и продемонстрировать, что при этом получается. В примере 23.6 для проведения экспериментов с функцией задается создание шести кнопок. Пример 23.6 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. <!DOCTYPE html> <html> <head> <title>Matrix Transformations</title> <style> #box { position : absolute; border : 5px solid red; transition : all 1s ease-in-out; top : 50px; left : 50px; width : 100px; height : 100px; background : orange; #a:hover ~ #box { transform : matrix(2, 0, 0, 1, 0, #b:hover ~ #box { transform : matrix(1, 1, 0, 1, 0, #c:hover ~ #box { transform : matrix(1, 0, 1, 1, 0, #d:hover ~ #box { transform : matrix(1, 0, 0, 2, 0, #x:hover ~ #box { transform : matrix(1, 0, 0, 1, 50, #y:hover ~ #box { transform : matrix(1, 0, 0, 1, 0, </style> </head> <body> <button id=’a’>A</button> <button id=’b’>B</button> <button id=’c’>C</button> <button id=’d’>D</button> 0); 0); 0); 0); 0); 50); } } } } } } }
Двумерные преобразования 27. 28. 29. 30. 31. | 353 <button id=’x’>X</button> <button id=’y’>Y</button> <div id=’box’></div> </body> </html> В строках с 14 по 19 для аргументов 1 и 4 функции matrix() заданы исходные значения 1, поскольку первый аргумент задает коэффициент масштабирования по горизонтали, а четвертый — коэффициент масштабирования по вертикали. Результат выполнения кода примера — на рис. 23.6. Рис. 23.6. Наведение указателя мыши на кнопку D приводит к вертикальному масштабированию путем изменения значения четвертого аргумента То есть значение 1 для каждого из этих аргументов задает пропорциональный масштаб элемента, за исключением тех случаев, когда указатель мыши проходит над связанными с ними кнопками, в результате чего значение каждого из них устанавливается равным 2, чтобы удвоить масштаб в конкретном измерении. По сути, шесть заданных здесь значений представляют собой следующие комбинированные действия: matrix(scaleX, skewY, skewX, scaleY, translateX, translateY); Если провести указателем мыши над кнопками A или D, то можно будет увидеть, что блок становится вдвое больше по горизонтали или по вертикали. Кнопки B и C связаны со значениями 2 и 3 и, в свою очередь, выполняют наклон по вертикали и горизонтали. Последние две кнопки перемещают блок по горизонтали и вертикали. Проведите указателем мыши по всем этим кнопкам и понаблюдайте за тем, что получается. Здесь нужно понять, что, составляя из этих значений различные комбинации, можно добиться любой требуемой комбинации масштабирования, наклона, поворота и перемещения. Если вас это заинтересовало и нужна более подробная информация, перейдите по следующему URL-адресу: https://tinyurl.com/css-matrix
354 | Глава 23 Заключение На этом исследование использования технологии CSS3 для преобразований, перемещений и переходов объектов всевозможными способами завершается. Не забывайте, что плавные переходы могут применяться и к другим свойствам: width, height, color, font-size, и не только к ним, что позволяет создавать весьма интересные эффекты, повышая интерактивность и привлекательность пользовательского интерфейса. В следующей главе все, что было усвоено в этой, будет перенесено, выражаясь буквально, в следующее измерение! Мы действительно перейдем на более высокий уровень — в мир трехмерных преобразований и переходов, чтобы ваши элементы казались выскакивающими из веб-страницы.
ГЛАВА 24 Трехмерная графика и анимация Введение Эта глава особенно понравится сторонникам трехмерной графики, поскольку поставляемые с CSS3 3D-инструменты работают эффективно, быстро и очень просты в использовании. С их помощью можно установить глубину своего 3D-мира и посмотреть, насколько далеко он находится от зрителя. Можно выбрать смещение, при котором происходят преобразования, а затем выполнить множество преобразований, масштабирований, вращений и многого другого. В главе использован один основной пример, на который будут постоянные ссылки, и несколько других примеров, заполняющих фрагменты всего остального. Более того, основной пример весьма интересен, и до появления CSS3 для реализации таких же эффектов пришлось бы убить уйму времени на программирование с использованием 3D-тригонометрии. Структура В этой главе рассматриваются следующие темы:  Изучение всех особенностей 3D-преобразований.  Освоение способов выталкивания элемента из 2D-плоскости.  Изучение способов игры с перспективой для получения зрелищных эффектов.  Освоение способов манипуляции 3D-объектами, как будто они у вас в руках. Цели Цель главы — раскрыть трехмерные возможности CSS3 в легком и увлекательном повествовании. Успешно освоившие предлагаемый материал могут стать классными 3D-специалистами, готовыми создавать что угодно: от простых 3D-эффектов до страниц с эффектами виртуальной реальности.
356 | Глава 24 3D-преобразования Возможности, предоставляемые CSS для 3D-преобразований, поистине поразительны. Они позволяют без единой строки кода JavaScript полностью анимировать 3D-объекты, а также управлять их перемещением и вращением любым способом, не ограничивая своих фантазий. Чтобы красиво проиллюстрировать эти возможности, понадобится пример, превышающий по объему все предыдущие. В примере 24.1 для анимации трехмерного куба различными способами плавно и незаметно, с результатами, которые поразили бы воображение первых веб-разработчиков, используются HTML-элементы в комбинации с чистым кодом CSS3. Прежде чем продолжить изучение главы, нужно запустить пример и хорошенько поиграть с кнопками над 3D-кубом, наводя на них указатель мыши. Пример 24.1 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. <!DOCTYPE html> <html> <head> <title>3D Transformations</title> <style> #outer { perspective : 500px; width : 200px; margin : 10px auto; #cube { transform-style : preserve-3d; width : 100%; height : 200px; color : white; text-align : center; font : bold 18pt Arial; transition : all 1s linear; .face { position : absolute; width : 100%; height : 100%; #left { background : green; transform : rotateY( -90deg) translateZ(100px); #right { background : orange; transform : rotateY( 90deg) translateZ(100px); #up { background : red; transform : rotateX( 90deg) translateZ(100px); #down { background : magenta; transform : rotateX( -90deg) } } } } } }
Трехмерная графика и анимация 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. #back { background transform #front { background transform @keyframes spin { to { transform | 357 translateZ(100px); } : indigo; : rotateX( -180deg) translateZ(100px); } : blue; : rotateX( 0deg) translateZ(100px); } : rotateX( rotateY( 1turn) 1turn); } } #l:hover ~ #cube { transform : rotateY( 90deg); } #r:hover ~ #cube { transform : rotateY( -90deg); } #u:hover ~ #cube { transform : rotateX( -90deg); } #d:hover ~ #cube { transform : rotateX( 90deg); } #b:hover ~ #cube { transform : rotateX( 180deg); } #s:hover ~ #cube { animation : spin 6s linear 10; } </style> </head> <body> <div id='outer'>&nbsp; <button id='l'> L </button> <button id='r'> R </button> <button id='u'> U </button> <button id='d'> D </button> <button id='b'> B </button> <button id='s'>Spin</button> <br><br><br><br> <div id='cube'> <div class='face' id='left'> <br><br><br>LEFT </div> <div class='face' id='right'><br><br><br>RIGHT</div> <div class='face' id='up'> <br><br><br>UP </div> <div class='face' id='down'> <br><br><br>DOWN </div> <div class='face' id='back'> <br><br><br>BACK </div> <div class='face' id='front'><br><br><br>FRONT</div> </div> </div> </body> </html> Кнопки L, R, U, D, B и Spin, созданные в строках 52–57 примера, означают «Влево», «Вправо», «Вверх», «Вниз», «Назад» и «Вращение». Наведение указателя мыши на любую из первых пяти кнопок приводит к тому, что в поле зрения поворачивается выбранная грань. А это же действие в отношении последней кнопки заставляет куб вращаться, выполняя 10 полных наборов оборотов. Убирание указателя мыши с
358 | Глава 24 кнопок приводит к восстановлению показа лицевой грани. Результат загрузки этого примера показан на рис. 24.1. Рис. 24.1. Трехмерный куб, вращающийся в трех измерениях А теперь посмотрим, как собран пример, исследуя способы работы 3D-преобразований в CSS. Задание перспективы Когда нужно поднять элемент из 2D-пространства CSS, переводя его в третье измерение, используется свойство perspective. Оно позволяет использовать для элемента 3D-преобразования и переходы. Предоставляемые этому свойству значения задают расстояние, разделяющее наблюдателя и центр объекта. Следовательно, низкое значение показывает, что зритель находится близко к объекту, и будет очень сильный 3D-эффект, который сперва создаст слишком деформированное изображение, снижая тем самым эффект 3D. Для начала, эмпирическое правило гласит, что нужно взять наибольший размер объекта в 3D и установить значение перспективы примерно в два-три раза больше него. Как только эффект проявится, можно будет настроить значение в соответствии со своим вкусом и замыслом той картинки, которую должен увидеть зритель. В примере 24.1 длина ребер куба составляет 200 пикселей, что, согласно уравнению Пифагора, означает, что диагонали будут составлять около 283 пикселей, поэтому в примере для перспективы установлено значение 500 пикселей, чуть меньше двой-
Трехмерная графика и анимация | 359 ной протяженности диагонали, но это значение было выбрано после подстройки: сначала протестировали исходное значение в 850 пикселей, а затем оно постепенно уменьшалось до оптимального в 500 пикселей. Можете поупражняться в подстройке значения в строке 6, пробуя применять значения меньше и больше 500px, и посмотреть, что из этого выйдет. Это поможет быстро получить представление о том, как это свойство работает. Чтобы проиллюстрировать подобный эксперимент, в примере 24.2 используется значение 50px, создающее принудительное трехмерное изображение изнутри объекта. Поскольку кнопки больше не видны, в примере 24.2 с целью автоматического поворота объекта в самый конец документа добавляется еще один блок кода. Теперь объект будет вращаться 10 раз сам по себе. Пример 24.2 (только измененные строки): 6. 70. 71. 72. 73. #outer { perspective : 50px; <script> document.getElementById('cube').style.animation = 'spin 6s linear 10' </script> Рис. 24.2. Вид куба изнутри Неважно, что строки с 70 по 73 были добавлены после закрывающего тега </html>, так как браузеры снисходительны, и это просто мелкая добавка, заставляющая
360 | Глава 24 объект вращаться без изменения нумерации строк в примерах. Кроме того, как показано на рис. 24.2, она иллюстрирует способ выполнения команды JavaScriptанимации (или другого преобразования) для объекта. Этот пример показывает, как можно вращать или перемещать элементы CSS за зрителями, а также перед ними, что открывает совершенно новые возможности создания сценариев типа виртуальной реальности (VR) для любителей проводить смелые эксперименты в области веб-разработки. Но решившиеся на это, вероятно, будут работать с элементами гораздо большего размера, чтобы они могли казаться дальше от зрителя и меньше искажались в 3D. Чтобы вращать объект в трех измерениях, можно воспользоваться функцией rotate3d() или функциями rotateX(), rotateY() и rotateZ(). Трехмерные версии есть также и у других функций, например у skew() и translate(). Два способа изменения перспективы Можно также применительно к свойству transform воспользоваться функцией perspective(), создающей 3D-пространство для текущего элемента: transform : perspective(500); Когда нужно, чтобы у группы дочерних элементов было собственное трехмерное пространство, следует поднять родительский элемент именно таким способом, а не использовать для родительского элемента и всех его дочерних объектов общее 3D-пространство, задаваемое свойством perspective. В примере 24.3 создается два набора дочерних элементов: первый с родительским элементом, использующим свойство perspective, и второй без него. Пример 24.3 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. <!DOCTYPE html> <html> <head> <title>Perspective Types</title> <style> .outer { width height background border .perspective { perspective .box { width height margin float background border : : : : : : : : : : : 640px; 120px; cyan; 1px solid black; 200px; 100px; 100px; 0 55px; left; red; 1px solid black; } }
Трехмерная графика и анимация 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. transform | 361 : perspective(200px) rotateX(45deg); } </style> </head> <body> <div class='outer perspective'> <div class='box'></div> <div class='box'></div> <div class='box'></div> </div><br> <div class='outer'> <div class='box'></div> <div class='box'></div> <div class='box'></div> </div> </body> </html> Для каждого из этих наборов из трех блоков используется один и тот же родительский стиль, задаваемый для класса outer. Но для верхнего набора также используется стиль, задаваемый для класса perspective. Для класса outer просто задается ширина, высота и граница, а для класса perspective — свойство perspective со значением 200px. Результат загрузки кода примера в браузер — на рис. 24.3. Рис. 24.3. Верхние блоки разделяют родительскую установку Стилевое оформление класса box задает создание красных блоков 100 × 100 пикселей, широкий внешний отступ и значение свойства float, позволяющее элементам этого класса выстраиваться в одну линию рядом друг с другом. Затем в строках 18
362 | Глава 24 и 19 используется свойство transform, для которого вызывается функция perspective() с аргументом 200px, а затем функция rotateX() с аргументом 45deg. В результате каждый блок поворачивается вдоль горизонтальной оси таким образом, что его верхняя часть движется к браузеру, а нижняя часть — к зрителю, что соответствует повороту на 45 градусов. Посмотрите, что получается с тремя верхними блоками, использующими одно и то же трехмерное пространство, поскольку к их родительскому элементу применяется свойство perspective, а вот нижние три блока поворачиваются каждый сам по себе в своем собственном трехмерном пространстве. Этот эффект проявляется даже при том, что установки для класса box ящика идентичны для всех блоков, даже включая вызов функции perspective() с аргументом 200px. Задание стиля преобразования В примере 24.3 есть одна проблема, которая могла ускользнуть от вашего внимания: 3D-эффект в нем не совсем правильный. Дело в том, что браузеру нужно сообщить, что используемое свойство transform-style не должно быть плоским по умолчанию, так как работа ведется в 3D. Для него должно быть объявлено значение preserve-3d, поэтому в класс outer нужно добавить следующую установку: transform-style : preserve-3d; Показывать это здесь нет никакого смысла, но в прилагаемый бесплатный архив примеров измененный таким образом файл включен под именем example_03a.html. Результат должен выглядеть так, как показано на рис. 24.4. Рис. 24.4. Теперь поворот соблюдает особенности трехмерного пространства
Трехмерная графика и анимация | 363 Изменение исходной точки преобразования По умолчанию начало преобразования будет находиться прямо в центре родительского элемента или текущего элемента, если для родительского элемента не задано свойство perspective. Это включает в себя горизонтальную и вертикальную составляющую в направлениях X и Y и половину пути к зрителю в направлении Z. Но при желании любое из этих значений можно изменить, воспользовавшись свойством transform-origin, как показано в примере 24.4, где во втором наборе блоков это свойство установлено для пары направлений X и Y равным, соответственно, 0% и 10%: Пример 24.4 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. <!DOCTYPE html> <html> <head> <title>Changing Origin</title> <style> .outer { perspective : width : height : background : transform-style : border : .box { width : height : margin : float : background : border : transform : 200px; 640px; 120px; cyan; preserve-3d; 1px solid black; } 100px; 100px; 0 55px; left; red; 1px solid black; perspective(200px) rotateX(45deg); } .origin { transform-origin : 50% 10%; } </style> </head> <body> <div class='outer'> <div class='box'></div> <div class='box'></div> <div class='box'></div> </div><br> <div class='outer'> <div class='box origin'></div> <div class='box origin'></div> <div class='box origin'></div>
364 33. 34. 35. | Глава 24 </div> </body> </html> Код этого примера работает аналогично коду примера 24.3. В данном случае установки для класса box одинаково распространяются на все блоки, но здесь оба набора блоков используют одни и те же родительские свойства perspective и preserve-3d, а разница в том, что для второго набора используется другое значение свойства transform-origin, не такое, как для первого. Результат выполнения этого примера показан на рис. 24.5. Рис. 24.5. Для нижнего ряда применено другое начало координат Работа в 3D-пространстве Пришло время вернуться к примеру 24.1 и нашему вращающемуся кубу. Теперь, разобравшись получше с CSS в 3D, давайте посмотрим, как был построен куб. В примере 24.1 можно заметить, что в строке 51 есть элемент с идентификатором outer, охватывающий все остальное. Это контейнер для хранения кнопок и куба. Внутри контейнера outer находится набор из шести кнопок, под которыми (после нескольких разделительных тегов <br>) находится еще один контейнер под названием cube. И наконец, внутри куба находятся шесть его граней, каждая из которых — в своем собственном элементе <div>. По коду HTML не сразу понятно, как устроен куб, поэтому давайте посмотрим на установки для класса граней face в строке 16. Здесь свойство position каждого ис-
Трехмерная графика и анимация | 365 пользующего этот класс элемента (что делают все грани), устанавливается в значение absolute, а к его свойствам ширины и высоты применяются все 100%: 16. 17. 18. .face { position width height : absolute; : 100%; : 100%; } Эти значения зависят от родительского элемента, называемого cube, ширина которого равна 200px и задана для элементов с идентификатором outer в строке 7, а его высота сделана равной 200px в установке для элементов с идентификатором cube в строке 11. Таким образом, каждой грани куба задаются значения для свойств position, width и height. Теперь давайте поочередно посмотрим на каждую грань куба, начиная с той, что в строке 19 называется left. Эту грань, когда смотрим на куб, нужно поместить на его левую сторону, и обеспечить ее правильный поворот и окраску. Сначала используется зеленый цвет, затем в строке 20 грань поворачивается против часовой стрелки по оси Y, чтобы ее левый край был направлен к браузеру, а правый — к зрителю. Теперь элемент невидим, поскольку находится сбоку от нас, и, не имея глубины, ему нечего отображать. Затем в строке 21 она перемещается в нужную позицию на 100px по измерению Z: 19. 20. 21. #left { background transform : green; : rotateY( -90deg) translateZ(100px); } Поскольку грань left теперь обращена влево, когда она поднимается на 100 пикселей по оси Z, это относительно текущего положения элемента и поворота происходит в восходящем направлении. Следовательно, грань перемещается на 100 пикселей влево и теперь находится в нужном месте. Аналогичным образом грань right начиная со строки 22 получает окраску, затем соответствующий поворот также по оси Y, но на этот раз по часовой стрелке (с ее исходной позиции), а затем перемещается на 100 пикселей по ее измерению Z и так размещается на правой стороне куба. Теперь для верхней грани под названием up начиная со строки 22 задается красный цвет, и она поворачивается по оси X. Затем путем перемещения по оси Z на 100 пикселей и с учетом ее текущего поворота эта грань помещается на вершину куба. Нижняя грань (названная down), начиная со строки 28 окрашивается в пурпурный цвет и поворачивается против часовой стрелки, после чего перемещается вниз по оси Z, чтобы получилась нижняя сторона куба. Начиная со строки 31, для задней грани куба (называемой back) устанавливается цвет индиго и задается поворот по оси X на 180 градусов. Она перевернулась, а затем задается ее перемещение по оси Z к задней стороне. И наконец, для передней стороны (называемой front) устанавливается синий цвет и задается поворот на 0 градусов по оси X (что можно было бы и не указывать, так как здесь не совершается никаких действий, но в примере этот код появляется просто для соответствия другим установкам граней), а затем задается ее перемещение по оси Z на 100 пикселей по направлению к зрителю — и у нас получается готовый куб!
366 | Глава 24 Управление кубом Построив куб в трехмерном пространстве, заданном в элементе outer в строке 6, можем приступить к управлению фигурой. В примере было решено начиная со строки 42 воспользоваться применительно к ряду кнопок селектором hover. С помощью оператора ~ действие этой установки применяется к родственному элементу cube, который и есть наш 3D-куб. Для выполнения действий свойство transform вызывает функцию rotateX() или rotateY(), используя значения, противоположные тем, которые были назначены при размещении различных граней. Например, в строке 20 для грани, названной left, задается поворот против часовой стрелки на 90 градусов по оси Y. Следовательно, в строке 42 при наведении указателя мыши на кнопку L ко всему кубу применяется поворот по часовой стрелке на 90 градусов. Благодаря этому получается поворот левой грани куба по направлению к зрителю: 42. #l:hover ~ #cube { transform : rotateY( 90deg); } Точно так же преобразования, примененные в строках с 43 по 46, противоположны (или обратны) тем, которые применялись к любой другой грани. В данном случае они применяются ко всему кубу, чтобы повернуть его целиком, в результате чего выбранная грань перемещается под взгляд зрителя. Для показа передней грани преобразования не задаются, поскольку увод указателя мыши от кнопок все равно заставит ее повернуться под взгляд зрителя, и в результате стандартных установок селектора CSS hover куб возвращается в исходное положение. Но куб не поворачивается в новые позиции мгновенно, поскольку к нему в строке 15 задается применение свойства transition, чем обусловлена плавная анимация в линейном (linear) темпе в течение одной секунды. Особый интерес вызывает код в строке 47, где задается действие при проходе указателя мыши над кнопкой Spin. Здесь к кубу применяется свойство animation, указывающее ему использовать правила анимации, определенные в spin в строке 37, в течение 6 секунд, причем анимация должна быть линейной и повторяться 10 раз. Это свойство нами еще не исследовано, поэтому следует пояснить, что правилу @keyframes в строках с 37 по 41, присваивается имя spin, которым можно воспользоваться, и эти правила гласят, что анимация должна вращать выбранный объект полностью по измерениям X и Y на один полный оборот (от 0 градусов до 360 градусов каждый). Значение 1turn применено здесь, чтобы показать, как им можно воспользоваться в качестве единицы измерения, эквивалентной 360 градусам. Таким образом, половина оборота (или 0.5turn) эквивалентна 180deg и т. д. Вместо значения linear можно воспользоваться любым типом плавности или другими типами перехода, подробно рассмотренными в главе 23 «Двумерные преобразования», а вместо значения 10 можно установить любое нужное вам количество повторений, или же указать значение infinite, чтобы вращение никогда не останавливалось. Теперь свойству animation можно присвоить это правило анимации, кото-
Трехмерная графика и анимация | 367 рое при наведении указателя мыши на кнопку активации будет применяться согласно следующей инструкции: 47. #s:hover ~ #cube { animation : spin 6s linear 10; } 3D-перемещение Теперь уже, наверное, сложилось полное понимание того, как работает код примера 24.1. Поэкспериментируйте с этим кодом, заставляя его делать разные вещи. Это будет не только интересно, но и в немалой степени поучительно. Как только закончите с экспериментами, переходите к подробному рассмотрению 3D-функции, начиная с translate3d(). При построении куба в примере 24.1 рассматривалось перемещение в Z-измерении, заданное функцией translateZ(). Но перемещения можно также задавать в измерениях X и Y, применяя для этого функции translateX() и translateY(), и сразу в трех измерениях, используя функцию translate3d(), которая принимает три значения и может использоваться следующим образом: transform : perspective(200) translate3d(-30px, 0px, 0px); Здесь к свойству transform применяются функции perspective() и translate3d(), при этом перемещение в X-измерении — пример задания отрицательного значения, что также разрешено. 3D-масштабирование Масштабирование также полностью поддерживается в трех измерениях и реализуется благодаря функциям scaleX(), scaleY(), scaleZ() и scale3d(). Первые три функции принимают одно значение, а третья требует предоставления трех. Значение 1 указывает на отсутствие масштабирования, 2 — на увеличение размера в два раза, 0.5 — уменьшение вдвое и т. д. Значения могут быть как положительными, так и отрицательными. В качестве примера использования функции scale3d() можно растянуть блок по X-измерению, сжать его по Y и оставить прежним по Z. Значения должны быть выражены целыми числами или числами с плавающей точкой без указания единиц измерения вроде px или em: transform : perspective(200) scale3d(1.2, .5, 1); 3D-вращение В CSS3 доступно также вращение в трех измерениях, для чего используются функции rotateX(), rotateY(), rotateZ() и rotate3d(). Для первых трех функций в качестве значения указывается угол поворота в выражениях вида 45deg, .5turn или -10grad,
368 | Глава 24 или же с указанием значения в радианах, например 6.28rad и т. д. Для вращения сразу в трех измерениях необходимо указать три числа и значение угла. Числа представляют собой по очереди измерения X, Y и Z и должны иметь значения от 0 до 1 для каждого измерения. Один из способов выполнить вращение сразу в нескольких измерениях — создать следующее правило, предписывающее в данном случае поворот на 60 градусов по часовой стрелке только в измерении Y: transform : perspective(200) rotate3d(0, 1, 0, 60deg); Чтобы проиллюстрировать работу этого кода, изменим только стилевое оформление класса face в коде примера 24.1, чтобы создать код примера 24.5, где свойство прозрачности всех граней было установлено всего на 60%, позволяя просвечиваться всему, что находится за кубом. Результат будет выглядеть примерно так, как показано на рис. 24.6. Рис. 24.6. Из-за другой настройки прозрачности стали видны задние грани куба Пример 24.5 (только класс face): .face { position opacity width height : : : : absolute; .6; 100%; 100%; }
Трехмерная графика и анимация | 369 Видимость обратных сторон граней Остается собрать последний фрагмент головоломки 3D-преобразований CSS: что нам делать с обратными гранями элементов при их повороте. Например, из предыдущего раздела известно, что текст, написанный на 2D-элементе, при повороте Xизмерения на 180 градусов будет по-прежнему отображаться, но теперь уже в перевернутом виде, просвечиваясь с другой стороны. Аналогично этому, если повернуть его на 180 градусов по оси Y, то он будет просвечиваться зеркально перевернутым. Но предположим, что при нынешней прозрачности нам не хочется видеть скрытые лицевые стороны граней с обратной стороны. При желании эти обратные стороны можно скрыть, изменив настройку свойства backface-visibility на hidden, добавив в стилевую установку для класса face еще одну строку, чтобы создать код примера 24.6. Пример 24.6 (только класс face): .face { position opacity backface-visibility width height : : : : : absolute; .6; hidden; 100%; 100%; } Рис. 24.7. Куб похож на изображенный на рис. 24.1, но имеет более светлый оттенок из-за меньшей прозрачности
370 | Глава 24 В результате, как показано на рис. 24.7, все обратные стороны граней стали невидимыми. Куб может казаться привлекательнее, если видны его задние грани, но теперь есть решение, позволяющее при желании сделать их невидимыми. Между прочим, уменьшение прозрачности дает возможность увидеть, как выглядел бы куб, если бы грани вращались без перемещения по оси Z. Результат показан на рис. 24.8. Рис. 24.8. Вот что произойдет, если «забыть» переместить грани куба Код, позволяющий увидеть это в браузере, слишком длинный, и приводить его здесь ради пустой забавы, пожалуй, не стоит, но его можно найти в прилагаемом бесплатном архиве примеров в файле под именем Example_07.html. По сути, это модификация кода примера 24.1 в сочетании с кодом примера 24.5. Заключение Пожалуй, уже понятно, что с помощью технологии CSS3 можно создавать просто потрясающие 3D-эффекты. Их сочетание с переходами и анимацией действительно позволяет поднять ваши веб-разработки на совершенно новый уровень. Теперь у вас есть все, что нужно знать об обработке как двумерной, так и трехмерной графики. В следующей главе нам предстоит разобраться с просто фантастическим новым способом создания динамически самонастраиваемых макетов с помощью технологии Flexbox.
ГЛАВА 25 Макет Flexbox Введение Разработка Flexbox была связана с необходимостью создания гибких и динамичных веб-макетов с четким выравниванием, а также с логичным и аккуратным распределением элементов и пространства, даже если размер этих элементов неизвестен. В качестве примера можно привести веб-сайт для портфолио фотографий, на котором коллекции изображений должны плотно занять все пространство, как кирпичи разного размера в ручной кладке. Этого сложно добиться с помощью стандартного CSS и, как правило, требуется применение сценария JavaScript. Как раз Flexbox и есть идеальное решение для такого проекта. А что нужно сделать, чтобы макет, который вполне удачно смотрится на широком мониторе, также хорошо распределял различные элементы на устройстве, высота которого больше ширины, например, на мобильном телефоне? И здесь Flexbox, несомненно, станет идеальным решением. Структура В этой главе рассматриваются следующие темы:  Изучение концепции модели макета Flexbox.  Уяснение порядка совместной работы главной и поперечной оси.  Работа с примером интерактивной среды Flexbox, чтобы опробовать многочис- ленные функции.  Приобретение навыков переноса, выравнивания и центрирования с помощью Flexbox. Цели Эта глава — полное и самодостаточное введение в модель макета Flexbox. Изучение материалов главы позволит освоить предлагаемый в ней набор высокоэффек-
372 | Глава 25 тивных функций и откроет возможность создания впечатляющих динамичных и гибких макетов. Сведения о Flexbox Цель разработки Flexbox, длившейся несколько лет, состояла в том, чтобы создать контейнерный элемент и придать ему возможность изменения размеров своих дочерних элементов и даже порядка и направления их распределения с целью добиться наиболее выгодного их размещения в доступном пространстве. Основным стимулом стал растущий ассортимент мобильных устройств различных размеров и форм: телефонов, планшетов и ноутбуков. То есть, Flexbox, скорее всего, был решением, лучше всего подходящим для небольших макетов. Более крупные и сложные макеты, вероятно, выиграют от использования Grid-макета, рассматриваемого в следующей главе. Но начнем мы с Flexbox, так как он позволяет ознакомиться с концепциями, необходимыми для понимания и задать расположение элементов независимо от направления, в отличие от обычных макетов, где превалирует либо горизонтальное, либо вертикальное расположение. Flexbox не отдельное свойство или функция, а целый модуль функций. Часть из них применяется к элементу-контейнеру, а часть — к его дочерним элементам. Для контейнера используется термин flex-контейнер, а для дочерних элементов — flexэлементы. Принцип работы Flexbox заключается в гибком управлении потоком элементов (отсюда и название Flexbox). Создание интерактивной среды Flexbox Чтобы объяснить, как все складывается воедино, для работы нужен более объемный пример. Но поскольку за время прочтения предыдущих глав уже накоплен большой объем навыков, сложность примеров может возрастать и дальше с расчетом на то, что вы полностью сможете в них разобраться. В примере 25.1 собрано сразу несколько функций, заменяющих множество небольших примеров с прицелом на то, что они позволят изменять любое и каждое свойство Flexbox в любом сочетании и мгновенно отслеживать производимые эффекты. Пример 25.1 1. 2. 3. 4. 5. 6. 7. <!DOCTYPE html> <html> <head> <title>Flexbox Playground</title> <style> body { background : #def; } .label { width : 110px;
Макет Flexbox 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. .link { #outer { .box { text-align : right; float : left; } color : blue; text-decoration : underline; cursor : pointer; } display : flex; border : 1px solid black; border-radius : 5px; background : linear-gradient(cyan,deepskyblue); padding : 5px; box-sizing : border-box; width : 100%; height : 400px; resize : both; overflow : hidden; } display : flex; background : linear-gradient(yellow,red); align-items : center; justify-content : center; border : 1px solid black; border-radius : 5px; font : bold 20pt Arial; resize : both; overflow : auto; color : white; } width : 100px; height : 100px; } width : 30px; height : 80px; } width : 150px; height : 130px; } width : 50px; height : 50px; } width : 70px; height : 150px; } width : 100px; height : 90px; } width : 160px; height : 180px; } width : 40px; height : 50px; } width : 120px; height : 150px; } #Box_A { #Box_B { #Box_C { #Box_D { #Box_E { #Box_F { #Box_G { #Box_H { #Box_I { </style> </head> <body> <output id='output'></output><br> <div id='outer'> <div class='box' id='Box_A'>A</div> <div class='box' id='Box_B'>B</div> <div class='box' id='Box_C'>C</div> <div class='box' id='Box_D'>D</div> <div class='box' id='Box_E'>E</div> <div class='box' id='Box_F'>F</div> <div class='box' id='Box_G'>G</div> <div class='box' id='Box_H'>H</div> | 373
374 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. | Глава 25 <div class='box' id='Box_I'>I</div> </div> <script> settings = ['flex-direction', 'flex-wrap', 'justify-content', 'align-items', 'align-content', 'gap'] values = [['row', 'row-reverse', 'column', 'column-reverse'], ['nowrap', 'wrap', 'wrap-reverse'], ['normal', 'flex-start', 'flex-end', 'start', 'end', 'center', 'stretch', 'left', 'right', 'space-between', 'space-around', 'space-evenly'], ['normal', 'flex-start', 'flex-end', 'start', 'end', 'center', 'stretch', 'baseline', 'self-start', 'self-end'], ['normal', 'flex-start', 'flex-end', 'start', 'end', 'center', 'stretch', 'baseline', 'space-between', 'space-around', 'space-evenly'], ['0px', '10px', '20px', '30px', '40px', '50px', '60px', '70px', '80px', '90px']] for (j = 0 ; j < settings.length ; ++j) { id('output').innerHTML += `<div class='label'>${settings[j]} :&nbsp;</div>` for (k = 0 ; k < values[j].length ; ++k) { id('output').innerHTML += `<span class='link' id='${settings[j]}${values[j][k]}' onclick='set(${j},${k})'>${values[j][k]}</span> ` } id('output').innerHTML += '<br>\n' } function set(j, k) { for (x = 0 ; x < values[j].length ; ++x) { style(settings[j] + values[j][x], 'font-weight', 'normal') style(settings[j] + values[j][x], 'color', 'blue') } style(settings[j] + values[j][k], 'font-weight', 'bold') style(settings[j] + values[j][k], 'color', 'red') style('outer', settings[j], values[j][k]) } function id(val) { return document.getElementById(val) } function style(obj, prop, val) { id(obj).style[prop] = val } </script> </body> </html>
Макет Flexbox | 375 После загрузки в браузер пример должен выглядеть так, как показано на рис. 25.1. Рис. 25.1. Этот пример позволяет протестировать 158 400 комбинаций свойств Flexbox Прежде чем перейти к использованию примера для объяснения разных функций Flexbox, давайте кратко рассмотрим порядок его работы, что также поможет немного разобраться в его сути. Как работает пример В нем три основных раздела. В разделе <style> находятся все используемые CSSустановки. Затем имеется код HTML, создающий пустой элемент <output>, в который будет добавлено несколько интерактивных элементов управления. И, наконец, код JavaScript, используемый для заполнения элемента <output>, а также для обработки щелчков кнопкой мыши. Для использования Flexbox не нужен код JavaScript. Здесь этот код применяется только как средство замены большого объема кода HTML несколькими строками кода на JavaScript, генерирующего нужный код HTML буквально на лету, или же как средство закулисного изменения различных значений свойств CSS.
376 | Глава 25 В строках с 6 по 12 в разделе <style> задается фон градиентной заливки, интерактивные ссылки и все различные части, отображаемые над основным дисплеем Flexbox. Довольно емкий <div>-элемент под этим разделом — это flex-контейнер, а дочерние <div>-элементы внутри него — это flex-элементы, упоминавшиеся в разделе «сведения о Flexbox». Родительский контейнер с идентификатором outer стилизован в строке 13 со свойством display, имеющим значение flex, с целью настройки модуля для его дочерних элементов. Здесь также можно было использовать значение inline-flex, чтобы выстроить родительский контейнер в одну линию с любыми родственными элементами, не затрагивая при этом его дочерние элементы. Начиная со строки 23, происходит стилизация каждого из девяти элементов flexbox также с использованием для свойства display значения flex по одной простой причине — центрирование текстовых идентификаторов A–I как по горизонтали, так и по вертикали. Дополнительно при этом используется четкое и эффективное применение Flexbox. Блоки flex-элементов создаются в строках с 47 по 55 в разделе <body>, где им присваиваются идентификаторы, позволяющие коду CSS в строках с 33 по 41 задать каждому разную ширину и высоту для имитации нашей работы с различными flexэлементами разных размеров. На рис. 25.1 можно увидеть эти элементы, помеченные буквами от A до I. Они в исходном состоянии расположены вдоль верхней части flex-контейнера, поскольку flex-свойства, кроме тех, что находятся в строке 13, указывают, что для <div>элемента с идентификатором outer, являющегося Flexbox-макетом, задается указание display : flex;. В строках 58 и 59 раздела <script> создается массив с именем settings[], содержащий шесть различных имен свойств, с которыми будет работать. В строках с 60 по 74 создается соответствующий первому массиву двумерный массив с именем values[][], содержащий значения, доступные для применения к каждому из свойств. Скобки [] или [][] после имен массивов указывают на его размерность. В строках с 76 по 85 содержится пара вложенных циклов для перебора элементов этих двух массивов и создания из них HTML-кода, с помощью которого отображается верхняя часть примера. Внешний цикл, начинающийся со строки 76, выполняет последовательный перебор шести имен свойств, используя индексную переменную с именем j, а внутренний цикл, начинающийся со строки 79, использует для итерации индексную переменную с именем k, но многие значения свойств связаны со тем, которое индексируется с помощью j. (Имена переменных j, k и i очень популярны среди программистов при использовании в качестве временных индексов для перебора элементов массивов). HTML-код, генерируемый этой парой циклов, создает несколько <div>-элементов для перечисления имен свойств, за каждым из которых следует несколько <div>элементов для их возможных значений. Затем получившийся код HTML сохраняется в свойстве innerHTML элемента <div> с идентификатором output, представляясь
Макет Flexbox | 377 браузеру как бы уже присутствующим на странице кодом HTML. Для создания этого кода HTML используются литералы шаблонов внутри строк в обратных кавычках. И наконец, к созданному таким образом HTML-коду ссылок прикрепляются события onclick, запускающие функцию set() в строке 86. Эта функция принимает переданные ей значения, одно из которых — индекс имени свойства, а другое — значение применяемого свойства, а затем соответственным образом изменяет стиль <div>-элемента с идентификатором outer (<div>-элемент Flexbox). Одновременно с этим значение выделяется полужирным шрифтом и красным цветом, а предыдущее значение этого свойства получает обычный шрифт синего цвета. Это позволяет сразу увидеть, какие свойства и связанные с ними значения используются в области Flexbox в настоящее время. Две функции в строках 95 и 96, id() и style(), возвращают, в свою очередь, объект на основе его идентификатора в сценарий JavaScript и применяют значение к свойству объекта. Если захочется увидеть HTML, созданный всем сценарием, после } в строке 85 можно добавить следующую строку кода: ; console.log(id('output').innerHTML) Символ ; служит окончанием предыдущей инструкции, а остальная часть строки выводит HTML на консоль разработчика, где код приобретает вид, показанный на рис. 25.2. Рис. 25.2. Просмотр в консоли разработчика HTML-кода, созданного в этом примере
378 | Глава 25 Работа с примером Не нужно досконально разбираться в работе примера. Достаточно знать, что по щелчку кнопкой мыши на любом значении свойства над flex-контейнером инициированное им изменение тут же отобразится ниже, в области этого контейнера. Кроме того, все flex-элементы во Flexbox сделаны такими, что их размеры могут изменять пользователи, поэтому не нужно довольствоваться изначально установленными в примере шириной и высотой, их размеры можно изменять по своему желанию. Можно также изменить размер самого Flexbox, посмотрев, какой за этим последует результат. Для этого нужно захватить мышью правый нижний угол элемента и перетащить его на новую позицию. Чтобы в любой момент сбросить все значения до исходных, просто перезагрузите документ в браузере, и все настройки будут инициализированы заново. В прилагаемом бесплатном архиве файлов примеров также есть документ, сохраненный как example_01a.html, который идентичен примеру, за исключением того, что в нем все flex-элементы инициализированы одинаковыми горизонтальными прямоугольными размерами (200 × 50 пикселей). Это пригодится при желании проверить, как flexэлементы одинакового размера взаимодействуют друг с другом. Если загрузить этот документ в браузер, он будет иметь вид, показанный на рис. 25.3. Рис. 25.3. Все flex-элементы одинаковы, для них задан перенос и центровка
Макет Flexbox | 379 Flex-направление А теперь давайте рассмотрим эти свойства Flexbox по отдельности, начиная со свойства главной оси, flex-direction. Этому свойству присваивается одно из четырех возможных значений:  row: Flex-элементы позиционируются слева направо  row-reverse: Flex-элементы позиционируются справа налево  column: Flex-элементы позиционируются сверху вниз  column-reverse: Flex-элементы позиционируются снизу вверх На рисунках 25.1 и 25.3 показано, что свойство flow-direction не задано, поэтому и там, и там применяется значение по умолчанию row. На рис. 25.4 на трех копиях экрана показаны все остальные возможные значения в действии. Как видите, на первой копии экрана flex-элементы позиционируются справа налево, затем сверху вниз и, наконец, снизу вверх. Попробуйте сами использовать эти настройки в сочетании с изменением размеров flex-элементов и, возможно, промежутков между ними. Рис. 25.4. Flex-направления row-reverse, column и column-reverse (начало)
380 | Глава 25 Рис. 25.4. Flex-направления row-reverse, column и column-reverse (окончание)
Макет Flexbox Рис. 25.5. Использование значений wrap и wrap-reverse | 381
382 | Глава 25 Наряду с этими значениями свойств есть понятие поперечной оси. Изменить ее пользователь не может, она — следствие значения свойства flow-direction. Если главная ось — одно из значений строки, то поперечная ось проходит вверх и вниз по столбцам. Если главная ось — одно из значений столбца, то поперечная ось проходит слева или справа по строкам. Представьте, что вы читаете книгу. В английском языке главная ось проходит по строкам слева направо, а поперечная ось — по столбцам сверху вниз. Для языков с написанием справа налево поперечная ось такая же, но для языков, читающих сверху вниз, их поперечная ось проходит слева направо и т. д. Перенос flex-элементов Существует только три способа работы с flex-элементами с позиции их переноса с помощью свойства flex-wrap, а если значение для flex-wrap не установить, переносы Flexbox выполнять не будет:  nowrap: Это значение по умолчанию, при котором все элементы остаются на одной линии.  wrap: С этой настройкой элементы будут переноситься сверху вниз.  wrap-reverse: Работает подобно wrap, но переносы выполняются снизу вверх. На рис. 25.1 и 25.3 показано, как работает значение nowrap, используемое по умолчанию, а на рис. 25.5 показана работа значений wrap и wrap-reverse, когда объект I переносится в другое место, позволяя всем flex-элементам принимать свои первоначальные нерастянутые или сжатые значения. Выравнивание всего содержимого по главной оси Свойство justify-content поддерживает следующие значения, многие из которых очень похожи на другие значения с похожими именами, но имеют слегка иные эффекты. Одним из стимулов написания этого примера было предоставить вам возможности попробовать все значения на практике и понаблюдать за возникающими изменениями.  normal: Это значение, используемое по умолчанию, как будто не установлено никакого выравнивания и исходная позиция — начальный край.  flex-start: Элементы размещаются вплотную друг к другу и выравниваются по начальному краю контейнера.  flex-end: Элементы размещаются вплотную друг к другу и выравниваются по конечному краю контейнера.  start: Элементы размещаются вплотную друг к другу и выравниваются по на- чальному краю главной оси контейнера.
Макет Flexbox | 383  end: Элементы размещаются вплотную друг к другу и выравниваются по конеч- ному краю главной оси контейнера.  center: Элементы размещаются вплотную друг к другу и выравниваются по цен- тру главной оси.  left: Элементы размещаются вплотную друг к другу и выравниваются по на- чальному краю контейнера.  right: Элементы размещаются вплотную друг к другу и выравниваются по ко- нечному краю контейнера.  space-between: Элементы равномерно распределяются по главной оси вплотную к краям.  space-around: Элементы равномерно распределяются по главной оси с неболь- шими отступами от краев.  space-evenly: Элементы равномерно распределяются по главной оси с полными отступами от краев. На рис. 25.6 показан выбор значений start, end и center. Вы можете сами попробовать другие значения и увидеть различия, но иногда они будут проявляться только при изменении значений других свойств, так что можете смело экспериментировать. Рис. 25.6. Выбор значений выравнивания start, end и center (начало)
384 | Глава 25 Рис. 25.6. Выбор значений выравнивания start, end и center (окончание)
Макет Flexbox Рис. 25.7. Использование space-значений between, around и evenly (начало) | 385
386 | Глава 25 Рис. 25.7. Использование space-значений between, around и evenly (окончание) Значения, определяющие распределение пустого пространства для каждого flexэлемента при разных способах отображения, трудно различимы, но, если внимательно присмотреться к копиям экрана на рис. 25.7, то можно увидеть результаты практического применения всех трех значений. Основное различие между ними заключается в способе влияния распределения пустого пространства на внешние стороны элементов с каждого края. Выравнивание элементов по поперечной оси Свойство align-items поддерживает значения, перечисленные чуть ниже. Аналогично ситуации со свойством justify-content, отличить характер эффектов, производимых при использовании одних значений, от тех, что производятся другими, порой весьма непросто. Зачастую отследить производимые эффекты удается только при изменении значений других свойств. Итак, это свойство поддерживает следующие значения:  normal: Используется по умолчанию и ведет себя как при установке для flex- элементов значения stretch.  flex-start: Края отступов flex-элементов размещаются на одном уровне с началь- ным краем поперечной оси.
Макет Flexbox | 387  flex-end: Края отступов flex-элементов размещаются на одном уровне с конеч       ным краем поперечной оси. start: Элементы размещаются вплотную друг к другу на одном уровне с начальным краем контейнера по соответствующей оси. end: Элементы размещаются вплотную друг к другу на одном уровне с конечным краем контейнера по соответствующей оси. center: Элементы размещаются по центру поперечной оси. stretch: Элементы растягиваются так, что поперечный размер их блоков отступов выстраивается в одну линию. baseline: Элементы выравниваются вдоль основной линии их flex-контейнера. self-start: Элементы размещаются вплотную к начальному краю контейнера на соответствующей оси. self-end: Элементы размещаются вплотную к начальному краю контейнера на соответствующей оси. На рис. 25.8 к flex-элементам применен набор значений end, center и baseline. Чтобы увидеть различные варианты значений в действии, попробуйте изменить flexdirection на column-reverse, flex-wrap на wrap-reverse и align-content на end, и сразу станет заметен целый ряд интересных различий в применении разных значений align-items. Рис. 25.8. Для выравнивания применены значения end, center и baseline (начало)
388 | Глава 25 Рис. 25.8. Для выравнивания применены значения end, center и baseline (окончание)
Макет Flexbox | 389 Выравнивание всего содержимого по поперечной оси Мы разобрались с работой свойства align-items, но есть еще свойство align-content, устанавливающее распределение пространства между flex-элементами и вокруг них вдоль поперечной оси Flexbox. Считайте это версией align-items, используемой на противоположной оси. Это свойство поддерживает следующие значения:  normal: Совокупность элементов находится на исходных позициях, как будто это свойство к ней и не применялось.  flex-start: Совокупность элементов с поперечным начальным краем строки сдвигается в начало контейнера.  flex-end: Совокупность элементов с поперечным начальным краем строки сдви- гается в конец контейнера.  start: Совокупность элементов с поперечной осью сдвигается в начало контей- нера. Рис. 25.9. Выбор для выравнивания содержимого по поперечной оси значений start, center и end (начало)
390 | Глава 25 Рис. 25.9. Выбор для выравнивания содержимого по поперечной оси значений start, center и end (окончание)
Макет Flexbox Рис. 25.10. Настройка свойства выравнивания элементов на значения left, center и right (начало) | 391
392 | Глава 25 Рис. 25.10. Настройка свойства выравнивания элементов на значения left, center и right (окончание)  end: Совокупность элементов с поперечной осью сдвигается в конец контейнера.  center: Элементы размещаются вплотную друг к другу в центре контейнера вдоль поперечной оси.  stretch: По необходимости размер любых элементов с автоматически задавае- мым размером увеличивается в равной степени.  baseline: Совокупность элементов выравнивается вдоль основной линии ее flex- контейнера.  space-between: Элементы равномерно распределяются по поперечной оси вплотную к краям.  space-around: Элементы равномерно распределяются по поперечной оси с не- большими отступами от краев.  space-evenly: Элементы равномерно распределяются по поперечной оси с пол- ными отступами от краев. На рис. 25.9 показаны результаты выбора значений start, center и end. При проведении экспериментов со свойством align-content можно изменить настройки промежутков, выбрать разные значения свойства align-items и посмотреть, какие результаты можно получить.
Макет Flexbox | 393 К примеру, на рис. 25.10 показано значение align-content, установленное на end, со значениями start, center и end свойства align-items. Заметьте, что эти выравнивания происходят на одном и том же месте, без изменения выравнивания совокупности элементов. Другие свойства В перечне свойств можно также заметить свойство gap, изменяющее промежуток между элементами. Это сродни внешнему отступу, принимающему любое значение единиц измерения. Если, к примеру, задать условие gap : 20px, вокруг целевого элемента будет зазор в 20 пикселей. В примере можно самостоятельно проверить влияние различных значений от 0px до 90px, но этот диапазон обозначен только для целей изучения, а вам доступны любые произвольные значения. Есть также и другие свойства, не задействованные в примере. Во-первых, есть свойство order. С его помощью можно задать желаемый приоритет для каждого flex-элемента. По умолчанию значение их свойства order равно 0, чем задается наивысший приоритет, но, если некоторые элементы должны появиться на втором уровне, их свойству order можно присвоить значение 1, а если у других элементов должен быть еще меньший приоритет, их свойству order можно присвоить 2 и т. д., создавая нужную сложность упорядочения. Есть также свойства flex-shrink и flex-grow. Когда этим свойствам присваиваются значения, браузеру дается разрешение изменять их размеры на указанные величины, чтобы они больше соответствовали макету. Указываемые значения — пропорции. По умолчанию свойство flex-grow имеет значение 0, которое можно увеличивать, используя целые числа или числа с плавающей точкой, чтобы указать, какая часть оставшегося пространства в flexконтейнере должна быть назначена элементу. По умолчанию свойство flex-shrink имеет значение 1, которое можно изменять, используя целые числа или числа с плавающей точкой, чтобы указать, насколько может быть сжат элемент, чтобы в доступном пространстве могли разместиться другие элементы. Оба эти свойства работают в сочетании со свойством flex-basis, которое определяет размер элемента с позиции пространства, оставляемого им в качестве доступного. Его значение по умолчанию — auto, его можно изменить на любое значение измерения ширины, например flex-basis: 120px и т. д. Или же в качестве значений flex-basis можно использовать строки fill, max-content, min-content, fit-content или просто content (для автоматического задания размера на основе содержимого элемента). Полноценное объяснение порядка работы Flexbox от его проектировщиков можно найти по следующему URL-адресу: tinyurl.com/flexbasics
394 | Глава 25 А это ссылка на веб-сайт, где показано, как с помощью Flexbox создать то, что называется Святым Граалем макетов: tinyurl.com/hgflex Заключение На данный момент вы уже узнали обо всех удивительных возможностях, получаемых с помощью Flexbox. Средство позволяет, если вы того пожелаете, создавать целые макеты, хотя некоторые более крупные макеты могут стать сложными для управления из-за их одномерности. Поэтому в следующей главе рассматривается альтернативная технология двумерной компоновки под названием CSS Grid.
ГЛАВА 26 CSS Grid Введение Каким бы эффективным ни был Flexbox, он не отличался абсолютной универсальностью и завершенностью, на что, возможно, изначально надеялись его разработчики. Да, все в нем легко, гибко и прекрасно работает, но иногда ничто не может заменить сетку grid-макета, и плоскости просто больше не подходят для работы. Именно поэтому и была разработана технология CSS Grid, позволяющая считать себя расширением Flexbox в другом измерении, поскольку она, кроме всего прочего, поддерживает и многие атрибуты Flexbox, по крайней мере, там, где их применение имеет логический смысл. Итак, настало время узнать, какие дополнительные возможности CSS Grid предлагает помимо функций, доступных во Flexbox. Структура В этой главе рассматриваются следующие темы:  Изучение концепции CSS Grid и причин создания этой технологии наряду с Flexbox.  Работа с интерактивной средой CSS Grid, представленной в этой главе.  Изучение всех основных свойств и функций CSS Grid.  Приобретение навыков размещения элементов сетки именно там, где они нужны. Цели Здесь изложены сведения о всех функциях CSS Grid, включая все, что делается с их помощью, раскрываются причины их создания и порядок их использования. Изучение материалов главы позволит освоить приемы компоновки grid-макетов и привести вас в готовность их применения в своих проектах с максимальным эффектом.
396 | Глава 26 Сведения о CSS Grid В этой главе, как и в ее предшественнице, посвященной Flexbox, есть только один весьма объемный пример, но с ним стоит поработать, так как он позволяет протестировать практически неограниченное количество grid-макетов CSS, не заставляя самим создавать образцы документов. Все основные свойства доступны по одному щелку кнопкой мыши, а свойства, определяющие место элемента в сетке и количество ячеек, которые он должен занимать, можно задать в простых строках ввода. Разумеется, это не полноценный продукт, а только пример, поэтому работа ограничивается девятью дочерними элементами и максимальной сеткой 9 на 9 ячеек. И все же этого вполне достаточно для изучения всего необходимого касательно использования модуля CSS Grid. Чтобы длина документа не превышала 100 строк, в примере 26.1 было опущено несколько строк, которые иначе оставались бы пустыми. Но если захочется поэкспериментировать с кодом, прочитав объяснения порядка его работы, можно будет взглянуть на файл example_01a.html в бесплатном прилагаемом к книге архиве файлов примеров, который идентичен приводимому здесь, но содержит больше пробелов, а также выводит создаваемый код HTML в консоль разработчика на тот случай, если его захочется изучить. Пример 26.1 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. <!DOCTYPE html> <html> <head> <title>CSS Grid Playground</title> <style> body { background : #def; } input { width : 33px; margin : 0 0 5px; font : 6pt monospace; } .label { width : 110px; text-align : right; float : left; } .link { color : blue; text-decoration : underline; cursor : pointer; } #outer { display : grid; border : 1px solid black; border-radius : 5px; background : linear-gradient(cyan,deepskyblue); padding : 5px; box-sizing : border-box;
CSS Grid 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. .box width height resize overflow { display background align-items justify-content width height border border-radius font resize overflow color : : : : : : : : : : : : : : : : 100%; 350px; both; hidden; } flex; linear-gradient(yellow,red); center; center; 100%; 100%; 1px solid black; 5px; bold 20pt Arial; both; auto; white; } </style> </head> <body> <output id='output'></output> <script> settings = ['grid-auto-flow', 'justify-content', 'align-items', 'align-content', 'column-gap', 'row-gap', 'columns', 'rows'] values = [['row', 'column', 'dense', 'row dense', 'column dense'], ['normal', 'start', 'end', 'center', 'left', 'right', 'space-between', 'space-around', 'space-evenly'], ['normal', 'start', 'end', 'center', 'stretch', 'baseline', 'self-start', 'self-end'], ['normal', 'start', 'end', 'center', 'stretch', 'baseline', 'space-between', 'space-around', 'space-evenly'], ['0px', '10px', '20px', '30px', '40px', '50px', '60px', '70px', '80px', '90px'], ['0px', '10px', '20px', '30px', '40px', '50px', '60px', '70px', '80px', '90px'], ['1','2','3','4','5','6','7','8','9'], ['1','2','3','4','5','6','7','8','9']] counts = []; out1 = ''; out2 = "<br><div id='outer'>\n" for (j = 0 ; j < settings.length ; ++j) { s = settings[j] out1 += `<div class='label'>${s} :&nbsp;</div>\n` | 397
398 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. | Глава 26 for (k = 0 ; k < values[j].length ; ++k) { v = values[j][k] out1 += `<span class='link' id='${s}${v}' ` + `onclick='set(${j},${k})'>${v}</span>\n` } out1 += '<br>' } out1 += "<div class='label'>grid-area :&nbsp;</div>\n" for ( j = 0 ; j < 9 ; ++j) { l = String.fromCharCode(65 + j) counts[j] = 'auto '.repeat(j + 1) out1 += l + ` <input onchange="ch('Box_${l}', this)">\n` out2 += `<div class='box' id='Box_${l}'>${l}</div>\n` } id('output').innerHTML = out1 + out2 + '</div>'; function set(j, k) { s = settings[j]; v = values[j][k] for (x = 0 ; x < values[j].length ; ++x) { style(s + values[j][x], 'font-weight', 'normal') style(s + values[j][x], 'color', 'blue') } style(s + v, 'font-weight', 'bold') style(s + v, 'color', 'red') if (v > 0) style('outer', 'grid-template-' + s, counts[v - 1]) else style('outer', s, v) } function ch(obj1, obj2) { style(obj1,'grid-area',obj2.value) } function id(val) { return document.getElementById(val) } function style(obj, prop, val) { id(obj).style[prop] = val } </script> </body> </html> Чтобы сократить длину документа до 100 строк, не позволяя его распечатке занимать слишком много места в книге, было выбрано применение сценария JavaScript, позволяющего создать над областью сетки всю область управления. Давайте изучим пример, чтобы понять, как он работает и что делает. Но в принципе можно будет обойтись и подробным описанием порядка его использования из следующего раздела и пропустить дальнейшее описание самого примера. Этот пример, если приглядеться, очень похож на пример 25.1 из предыдущей главы и представляет собой его усовершенствованную версию с удаленными параметрами, касающимися только Flexbox и добавленными параметрами только для Grid. В строке 6 телу документа придается цветной фон, поэтому все теги <input>, начиная со строки 7, имеют соответствующий стиль. Все это позже будет применяться для настроек свойства grid-area. Затем в строках с 10 по 15 задаются стили для эле-
CSS Grid | 399 ментов с идентификаторами, используемыми в качестве ссылок с прикрепленными к ним событиями щелчка кнопкой мыши. Начиная со строки 16 задается стилевое оформление <div>-контейнера outer, содержащего дочерние элементы, начинающееся с установки для свойства display значения grid. Тем самым для этого элемента приводится в действие весь модуль Grid. Можно также воспользоваться значением inline-grid, помещающим сам контейнер на одну линию с любыми родственными элементами, но не влияющим на его дочерние элементы. Размер этого родительского элемента может изменить пользователь. Стилизация класса, используемого каждым из девяти дочерних элементов, начинается со строки 26. Заметьте, что для свойства display всех этих блоков указано значение flex, и сделано это по одной единственной причине — для получения простого способа центрирования текста в области содержимого сетки как по горизонтали, так и по вертикали. Размер блоков также может изменять пользователь. Как работает пример Сначала в разделе <script>, начинающемся в строке 43, происходит заполнение нескольких массивов. В массиве settings[] содержатся все имена свойств, к которым мы будем обращаться, а в массиве values[][] (двумерном) содержатся все возможные значения для каждого из свойств. После этого следует пустой массив counts[], который будет заполнен позже, и две переменные, используемые для вывода кода HTML, который будет создаваться сценарием JavaScript. Значение переменной out1 начинается с пустой строки, а переменной out2 — с тега <br> и начала нового элемента <div>. Эта переменная также будет дополнена, прежде чем чуть позже ее значение само будет добавлено к значению переменной out1. Затем в строке 64 начинается цикл, предназначенный для достижения сразу нескольких целей. Во-первых, он извлекает из массивов всю информацию, помещая ее в код HTML. Эту информацию можно увидеть в первых восьми строках раздела в верхней части окна браузера. В этом коде HTML:  Перечисляются различные свойства.  Дается подробное описание возможных значений свойств, на которые можно щелкать кнопкой мыши, чтобы применить их значения к родительскому <div>элементу outer. Созданный код HTML добавляется к значению переменной out1. Затем в строке 75 к значению переменной out1 добавляется дополнительный код HTML, чтобы начать заключительную строку верхнего раздела, поддерживающую ввод значений gridarea за счет отображения имени свойства. Начиная со строки 76, задается еще один цикл, в котором массив counts[] заполняется строкой auto в первом элементе, auto во втором, и так до девяти повторяющихся слов в девятом элементе. Эти девять значений поддерживают настройки ме-
400 | Глава 26 жду 1 и 9 столбцами и (или) чуть позже строками (если пользователь щелкнет кнопкой мыши), назначив одно из значений атрибутам grid-template-columns или grid-template-rows. Каждый экземпляр слова auto добавляет еще один столбец или строку. К значениям переменных out1 и out2 также добавляется код HTML, позволяющий реагировать на изменение значения тега <input> и вызывать в ответ функцию ch(). Кроме того, дочерним grid-элементам присваиваются значения ID, каждому из которых назначаются буквы от A до I для отображения по центру элементов. Весь HTML-код, добавленный к значениям этих двух переменных, затем копируется в свойство innerHTML элемента outer и закрывается тегом </div>. Если захочется увидеть весь собранный код HTML, можно перед строкой 83 добавить следующий код (что уже сделано для вас в файле example_01a.html в бесплатном прилагаемом архиве примеров): console.log(id('output').innerHTML) Теперь обратимся к функции set(), которая очень похожа на ту же функцию в примере 25.1 из предыдущей главы. В ней реализуется реакция на щелчки кнопкой мыши на значениях свойств, заключающаяся в мгновенном присваивании их указанным свойствам. Кроме того, шрифт на текущих используемых значениях свойств становится полужирным красным, а на выведенных из использования возвращается к исходным установкам. В свою очередь, три функции в строках с 94 по 96 применяют значение, введенное в поле, сформированное одним из тегов <input>, к свойству grid-area, возвращают объект, просмотрев его идентификатор, и применяют к объекту стилевые настройки. Работа с примером Если вы пропустили предыдущее объяснение, ничего страшного — оно предназначено для тех, кто программирует на JavaScript и хочет знать, как все это работает. В этом разделе вы в роли веб-дизайнера или разработчика можете поэкспериментировать с различными grid-функциями, загрузив пример в браузер, и получив изображение, показанное на рис. 26.1. В модуле CSS Grid имеется девять основных свойств (некоторые из которых также используются Flexbox и другими модулями), а также ряд связанных вспомогательных свойств. К ним относятся grid-auto-flow, justify-content, align-items, aligncontent, column-gap, row-gap, grid-template-columns, grid-template-rows и grid-area. Некоторые из этих свойств применяются по-разному в зависимости от настроек других свойств. Например, если для grid-auto-flow установлено значение column, а не row, соответствующие свойства будут применяться по вертикали, а не по горизонтали, и т. д. Теперь давайте подробно рассмотрим некоторые из этих свойств.
CSS Grid | 401 Рис. 26.1. Исходные настройки интерактивной среды CSS Grid Задание потока Grid-элементов Направление потока элементов определяется свойством grid-auto-flow, который поддерживает следующие значения:  row: Элементы размещаются, заполняя по мере надобности каждую строку — используется по умолчанию.  column: Элементы размещаются, заполняя по мере надобности каждый столбец.  dense: Попытка заполнить как можно раньше имеющиеся в сетке пустые места, если чуть далее следуют более мелкие элементы.  row dense: Элементы размещаются, заполняя каждую строку, а также заполняя любое ранее оставленное пустое место.  column dense: Элементы размещаются, заполняя каждый столбец, а также за- полняя любое ранее оставленное пустое место.
402 | Глава 26 Если значение этому свойству не задано, по умолчанию используется строка с разреженным заполнением пустых мест. Чтобы исследовать плотную упаковку, нужно оставить в сетке пустые места и посмотреть, как они будут заполняться. На рис. 26.2 показаны девять элементов сетки, со значением column свойства grid-auto-flow. Рис. 26.2. Порядок размещения был переключен на режим столбцов Выравнивание содержимого Чтобы выровнять содержимое различными способами, можно воспользоваться свойством justify-content аналогично тому, как это делалось в технологии Flexbox. Это свойство поддерживает следующие значения:  normal: Это значение, используемое по умолчанию, как будто не установлено никакого выравнивания и исходная позиция — начальный край.  start: Элементы размещаются вплотную друг к другу и выравниваются по на- чальному краю линейной оси контейнера.
CSS Grid | 403  end: Элементы размещаются вплотную друг к другу и выравниваются по конеч- ному краю линейной оси контейнера.  center: Элементы размещаются вплотную друг к другу и выравниваются по цен- тру линейной оси.  left: Элементы размещаются вплотную друг к другу и выравниваются по на- чальному краю контейнера.  right: Элементы размещаются вплотную друг к другу и выравниваются по ко- нечному краю контейнера.  space-between: Элементы равномерно распределяются по линейной оси вплот- ную к краям.  space-around: Элементы равномерно распределяются по линейной оси с не- большими отступами от краев.  space-evenly: Элементы равномерно распределяются по линейной оси с полны- ми отступами от краев. Рис. 26.3. Выравнивание grid-содержимого со значениями left, center и right (начало)
404 | Глава 26 Рис. 26.3. Выравнивание grid-содержимого со значениями left, center и right (окончание)
CSS Grid Рис. 26.4. Влияние установок значений space-between, space-around и space-evenly на распределение свободного пространства (начало) | 405
406 | Глава 26 Рис. 26.4. Влияние установок значений space-between, space-around и space-evenly на распределение свободного пространства (окончание)
CSS Grid | 407 На рис. 26.3 показаны три копии экрана, иллюстрирующие эффекты выравнивания со значениями left, center и right, применяемые к grid-элементам различных размеров (изменяемых с помощью значков изменения размера в правом нижнем углу каждого элемента). Кроме того, как в Flexbox, расстояние между grid-элементами и вокруг них можно изменять. Были сделаны еще три копии экрана, показанные на рис. 26.4, при разных промежутках и с множеством grid-элементов разного размера в сетке 3 × 3 ячейки. Grid-элементы, которым не заданы какие-либо размеры, зачастую автоматически уменьшаются или увеличиваются до нужного размера путем сжатия или растяжения. При практическом применении примера станет понятно, что это нежелательный эффект. Также вы поймете, когда нужно использовать абсолютный размер, чтобы он соответствовал макету, и (или) относительный размер, например с процентными значениями или со значениями, выраженными в em, и т. д. Выравнивание элементов В grid-макете свойство align-items управляет выравниванием элементов в пределах их grid-области по оси блока. Это свойство поддерживает следующие значения:  normal: Используется по умолчанию и ведет себя как при установке для grid- элементов значения stretch или start.  start: Элементы размещаются вплотную друг к другу на одном уровне с началь- ным краем контейнера по соответствующей оси.  end: Элементы размещаются вплотную друг к другу на одном уровне с конеч- ным краем контейнера по соответствующей оси.  center: Элементы размещаются по центру макета.  stretch: Элементы растягиваются по мере необходимости, чтобы соответство- вать макету.  baseline: Элементы выравниваются вдоль их основных линий.  self-start: Элементы размещаются вплотную к начальному краю контейнера на соответствующей оси.  self-end: Элементы размещаются вплотную к начальному краю контейнера на соответствующей оси. На рис. 26.5 показаны еще три копии экрана, в которых для свойства align-items заданы значения start, center и end. На рис. 26.6 вы можете увидеть три копии экрана, на которых grid-элементы более плотно сгруппированы в начальной, центральной и конечной позициях сетки. Это свойство также поддерживает spacing-значения, определяющие распределение пустых пространств вокруг элементов. На рис. 26.7 показано размещение элементов при задании значений spacing-between, spacing-around и spacing-evenly.
408 | Глава 26 Рис. 26.5. Значения выравнивания start, center и end отображаются вверху, посередине и внизу (начало)
CSS Grid Рис. 26.5. Значения выравнивания start, center и end отображаются вверху, посередине и внизу (окончание) Рис. 26.6. Элементы выровнены по содержимому с применением значений start, center и end (начало) | 409
410 | Глава 26 Рис. 26.6. Элементы выровнены по содержимому с применением значений start, center и end (окончание)
CSS Grid | Рис. 26.7. Распределение пустого пространства между grid-элементами при задании значений spacing-between, spacing-around и spacing-evenly (начало) 411
412 | Глава 26 Рис. 26.7. Распределение пустого пространства между grid-элементами при задании значений spacing-between, spacing-around и spacing-evenly (окончание) Задание промежутков Свойства column-gap и row-gap позволяют также указывать промежутки между gridэлементами как для столбцов, так и для строк. Для них могут применяться любые стандартные значения CSS-измерений, хотя для простоты в примере используются только пиксели. На рис. 26.8 показан эффект отсутствия промежутков, задания промежутка в 30 пикселей между столбцами и промежутка в 30 пикселей между столбцами и строками. Чтобы лучше проиллюстрировать эти значения, содержимое элементов и сами элементы отцентрированы. Изменение местоположения и размеров Теперь настал черед весьма интересной части CSS Grid, позволяющей точно указать, где в grid-макете должен располагаться каждый grid-элемент, а также объем пространства (или количество ячеек сетки), который он должен занимать.
CSS Grid Рис. 26.8. Различные размеры промежутков в действии (начало) | 413
414 | Глава 26 Рис. 26.8. Различные размеры промежутков в действии (окончание) Задать соответствующие условия можно с помощью четырех основных свойств: на какой строке сетки начинается элемент — grid-row-start, на какой строке сетки заканчивается элемент — grid-row-end, на каком столбце сетки начинается элемент — grid-column-start и на каком столбце сетки заканчивается элемент — grid-column-end. Как уже можно было догадаться, с ними можно точно указать, где должен располагаться каждый элемент сетки и где должны заканчиваться его ширина и (или) высота. Но есть также свойство grid-area, которое используется в примере, задающее в краткой форме область сетки. Оно позволяет указать один или несколько из данных аргументов в одном правиле, разделив их прямым слэшем. Например, чтобы элемент начинался во второй строке снизу и во втором столбце от начала, и занимал пространство вплоть до четвертой строки вниз и пятого столбца вдоль включительно, можно задать следующее правило: grid-area : 2 / 2 / 5 / 6; Если вы в недоумении, почему для последних двух аргументов это правило использует значения 5 и 6, то тут ничего странного, потому что мы хотели распространить элемент только на 4-ю строку и на 5-й столбец. Но значения, указывающие, насколько далеко может распространяться элемент, должны следовать сразу же после последних значений, используемых элементом. Иными словами, первые два значения указывают точное место начала, а вторые указывают, что расширение элемента
CSS Grid | 415 должно заканчиваться до предоставленных значений. Как только это будет усвоено и запомнено, все проблемы на этот счет сразу отпадут. Чтобы проиллюстрировать все это на практике, на рис. 26.9 используется сетка 6 на 5 ячеек, заданием местоположений создается макет с верхним, нижним колонтитулом и двумя боковыми панелями. В основной области внутри сетки есть один широкий и четыре менее широких элемента. Рис. 26.9. Все девять элементов размещены в выбранных местах Все получилось благодаря эквиваленту следующих правил, позволивших добиться изображения, показанного на рис. 26.9. #boxa #boxb #boxc #boxd #boxe #boxf #boxg #boxh #boxi { { { { { { { { { grid-area grid-area grid-area grid-area grid-area grid-area grid-area grid-area grid-area : : : : : : : : : 1/1/2/7; 2/1/5; 2/6/5; 2/2/3/6; 3/2/4/4; 3/4/4/6; 4/2/5/4; 4/4/5/6; 5/1/6/7; } } } } } } } } }
416 | Глава 26 Заметьте, что для элементов 2 и 3, боковых панелей без дополнительной горизонтальной протяженности, четвертое значение было опущено. Если захочется добавить правильное значение, для #boxb им будет 2/1/5/2, поскольку ширина столбца не должна распространяться на 2-й столбец, а для #boxc — 2/6/5/7, поскольку ширина столбца не должна распространяться на 7-й столбец. Чаще всего, наверное, придется работать с меньшим количеством grid-элементов, возможно, только с заголовком, нижним колонтитулом, двумя боковыми панелями и основной областью содержимого. В этом случае в целях тестирования примера можно в строке 97 перед закрывающим тегом </script> просто добавить несколько строк кода JavaScript, чтобы на время удалить ненужные элементы. Эти строки впоследствии всегда можно будет убрать или же, если захочется скрыть еще несколько элементов сетки, придется всего лишь добавить еще несколько строк. style('Box_F', style('Box_G', style('Box_H', style('Box_I', 'display', 'display', 'display', 'display', 'none') 'none') 'none') 'none') Рис. 26.10. Макет «Святой Грааль», использующий 5 grid-элементов Теперь после загрузки примера в браузер для работы останется только пять элементов, показанных на рис. 26.10, где применяется ранее рассмотренный макет (часто
CSS Grid | 417 называемый из-за своей высокой популярности, но непростой реализуемости макетом «Святого Грааля»). Для вашего удобства в бесплатный прилагаемый архив примеров включена именно такая модифицированная версия, которая находится в файле example_01b.html. Разумеется, используемый пример — всего лишь интерактивная среда для проверки идей. С его помощью, прежде чем создавать собственные макеты CSS Grid, можно будет увидеть, что, скорее всего, сработает. Например, чтобы создать макет, показанный на рис. 26.10, необходимо было вытянуть grid-элементы в требуемые размеры, но на реальном веб-сайте вы, скорее всего, воспользовались бы значениями для атрибутов grid-контейнера grid-template-columns или grid-template-rows, похожими на применяемые для так называемого макета «Святой Грааль»: grid-template-columns : 10% auto 10%; grid-template-rows : 50px auto 100px; Получится grid-макет 3 × 3 с заголовком высотой 50 пикселей и нижним колонтитулом высотой 100 пикселей, боковыми панелями между ними по 10% доступного пространства каждая и областью контента с автоматически задаваемым размером в оставшемся пространстве. После этого нужно будет решить, какими будут промежутки между столбцами и строками, направление потока, продольное и поперечное выравнивание и т. д. Чтобы продолжить путешествие и увидеть, как CSS Grid работает, по мнению разработчиков этой технологии, можно воспользоваться следующим URL-адресом, и зайти на сайт, где очень подробно описывается эта тема: tinyurl.com/css3-grid Заключение Ну вот и все! Вы дошли до конца раздела о CSS3 и всех его фантастических преимуществах. Но путешествие по CSS еще не завершено, поскольку в следующем разделе состоится знакомство с удивительно мощным языком сценариев препроцессора Sass или Syntactically Awesome Style Sheets, который соответствует слову Awesome (потрясающий) в своем названии, поскольку он действительно потрясающий!
ГЛАВА 27 Знакомство с Sass Введение Итак, после изучения всех новых возможностей, предоставляемых CSS3, у вас, наверное, уже сложилось впечатление, что технология CSS — весьма эффективная и похожая на компьютерный язык технология. Именно похожая, поскольку классифицировать ее в качестве пригодного для использования языка программирования не позволяет отсутствие минимального набора функций. Во-первых, языки должны где-то хранить временные (и финальные) результаты, в виде переменных или массивов (которые, как известно, представляют собой не переменные с одним именем, а наборы переменных, к которым можно обращаться по их индексу). Затем нужны будут структуры принятия решений, которые могут выполнять операции типа if... then... else. Языку также нужны циклы, осуществляющие перебор данных или элементов массивов и т. д. До сих пор для реализации функциональных возможностей программирования в CSS в этой книге использовался язык JavaScript, но есть способ получше, и он называется предварительной обработкой или препроцессингом. Хороший препроцессор CSS позволяет для описания желаемого стилевого оформления создаваемого веб-документа использовать такой же синтаксис, как у языков программирования, после чего он на основе предоставленных инструкций проведет предварительную обработку, превращая их в чистый CSS, который вставит в ваш проект. Препроцессор, как вы понимаете, открывает совершенно новый мир возможностей CSS. Структура В этой главе рассматриваются следующие темы:  Что такое Sass, зачем он был разработан, и что он может делать.  Установка и использование Sass на различных платформах.  Как работают пути к файлам и зачем они используются.  Как Sass-препроцессинг превращает содержимое файлов в обычный код CSS.
420 | Глава 27 Цели Здесь можно получить сведения о том, что такое Sass, зачем этот препроцессор был разработан и почему он существенно облегчает задание веб-стиля. Изучение материалов главы позволит разобраться в основах препроцессора и подготовиться к освоению порядка использования переменных, вложенного кода, миксинов и многого другого в следующих главах. Sass — достойное решение Первоначально разработанная в 2006 году с использованием языка программирования Ruby технология Syntactically Awesome Style Sheets (Sass) постоянно развивалась, и к настоящему моменту она де-факто стала используемой в повседневной практике системой предварительной обработки, которая по-прежнему полностью поддерживается ее командой разработчиков. Популярность этой системы, помимо наличия специально предназначенной для ее поддержки основной команды, обусловлена следующими причинами:  Полной постоянной совместимостью со всеми версиями CSS.  Наличием большего количества функций и возможностей по сравнению с лю- быми другими языками расширений CSS.  Принятием его использования многими ведущими мировыми веб-разработчи- ками, что превратило Sass в отраслевой стандарт. Причем хорошее знание Sass существенно увеличивает шансы на получение более выгодной работы в области веб-разработки. Более того, теперь Sass сам по себе служит основой для растущего числа платформ разработки, построенных на основе его технологии, в числе которых Compass, Bourbon и Susy. Итак, давайте все же выясним, как работает Sass, что он делает и как его использовать. Сведения о Sass Система Sass фактически состоит из двух разных синтаксисов. Есть оригинальный синтаксис Indented (похожий на систему шаблонов Haml) и более новый синтаксис SCSS (также известный как Sassy CSS), использующий блочное форматирование, как и сам CSS. Indented Sass использует расширение имен файлов .sass, а Sassy CSS — .scss. Sass используется для расширения CSS за счет предоставления ряда функций, присущих традиционным языкам программирования. Это требует навыков создания сценариев на SassScript, которые затем интерпретируются в блоки правил CSS. В SassScript предоставляются переменные, вложенности, миксины и наследование, подробно рассматриваемые в этой и последующих главах.
Знакомство с Sass | 421 Для использования систему Sass сначала нужно настроить под свои проекты, установив соответствующее программное обеспечение. Базовая программа работает с использованием инструкций командной строки, но при желании можно получить и приложения (как платные, так и бесплатные), предоставляющие более удобный интерфейс. Дополнительную информацию на этот счет можно найти по следующему URL-адресу: sass-lang.com/install Различные версии Sass На данный момент существует три версии Sass, включая исходную версию Ruby Sass, LibSass, версию, переписанную на C/C++, и нынешнюю основную, рекомендованную к использованию реализацию DartSass. Ниже приводится краткое описание этих версий:  Ruby Sass была первоначальной реализацией Sass, но ее жизнь подошла к концу, и она больше не поддерживается. И тем не менее, она все еще довольно широко используется.  LibSass — это реализация Sass на C/C++, разработанная с прицелом на легкую интеграцию во множество различных языков. Но по прошествии времени эта версия стала отставать от Dart Sass по функциональным возможностям и совместимости с CSS, и поэтому теперь она считается устаревшей, и в новых проектах вместо нее следует использовать Dart Sass.  Dart Sass теперь стала основной реализацией Sass, т. е. именно она получает но- вые функции раньше любой другой реализации. Она работает быстро, проста в установке и компилируется в чистый JavaScript, что позволяет легко интегрировать получаемый код в современные рабочие процессы веб-разработки. Установка под Windows Самый простой способ загрузить и установить Sass под Windows — зайти в его GitHub-репозиторий по следующему URL-адресу: tinyurl.com/getsass Под списком активов будет набор файлов, показанный на рис. 27.1. Из этих файлов ниже показаны только файлы для Windows (имена файлов в зависимости от номера версии могут отличаться):  dart-sass-1.49.9-windows-ia32.zip  dart-sass-1.49.9-windows-x64.zip Теперь нужно загрузить соответствующий файл и воспользоваться стандартными средствами используемой операционной системы для распаковки его содержимого. И наконец, в системный путь нужно добавить подпапку dart-sass (или указать другое имя извлеченной папки).
422 | Глава 27 Рис. 27.1. GitHub-репозиторий Sass Как известно, путь — это набор имен папок, сохраненных в качестве настроек на вашем компьютере. Когда вводится имя программы, отсутствующей в текущей папке, компьютер может пройти по этому пути, выполняя поиск местоположения запускаемого файла. То есть программа может не находиться в текущей используемой папке, что позволяет хранить системные программы отдельно от документов проекта. Рассмотрим один из способов добавления названия папки к пути Windows: 1. Наберите в поле поиска меню «Пуск» advanced (Дополнительно). 2. Из предлагаемых вариантов выберите View Advanced System Settings (Просмотреть дополнительные параметры системы). 3. Убедитесь, что в появившемся окне выбрана вкладка Advanced (Дополнительно). 4. Щелкните мышью на кнопке Environment Variables (Переменные среды). В этом разделе выделите Path (Путь) в подразделе User variables for… (Пользовательские переменные для…) и нажмите кнопку Edit (Изменить). На рис. 27.2 показано окно System Properties (Свойства системы) с кнопкой Environment Variables (Переменные среды), и окно переменных среды, показывающее текущий путь и значения других переменных. Теперь можно добавить путь, для чего нужно щелкнуть на кнопке Edit (Редактировать), а затем на кнопке New (Создать) и ввести дополнение к пути. Например, если распакованная папка dart-sass помещена в корень диска C, можно ввести c:\dartsass, как показано на рис. 27.3, а затем нажать кнопку OK (Готово).
Знакомство с Sass Рис. 27.2. Окна System Properties и Environment Variables Рис. 27.3. Добавляется новый путь | 423
424 | Глава 27 Причина изменения пути в разделе User variables for… (Пользовательские переменные для…) вызвана желанием сделать изменение применимым только к вам и вашей учетной записи. Путь можно было бы добавить к основному системному пути, чтобы им могли пользоваться все пользователи, но, если при этом допустить ошибку, можно остановить работу компьютера, поскольку в этом случае он больше не сможет найти необходимые системные файлы. В любом случае, чтобы убедиться, что изменение пути активировано, теперь нужно будет перезагрузить компьютер (или, по крайней мере, выйти из системы и снова войти в нее). После этого вызовите командную строку или Windows PowerShell и введите следующую команду: sass --version Если все в порядке, будет получен простой ответ, например вот такой (для версии 1.49.9): 1.49.9 Другие установщики под Windows Если вы используете систему Node.js, Sass можно также установить с помощью npm, введя в командной строке следующую команду: npm install -g sass Но в данном случае будет установлена реализация Sass на чистом JavaScript, которая будет работать медленнее, чем другие версии, но будет использовать тот же интерфейс, поэтому позже при желании будет нетрудно перейти на другую реализацию. Или, если используется диспетчер пакетов Chocolatey для Windows, то Dart Sass можно установить путем ввода следующей команды: choco install sass Установка под MacOS На компьютере с операционной системой MacOS самый простой способ получить Sass связан с предварительной установкой менеджера пакетов Homebrew, который выполнит за вас все необходимые действия. Если Homebrew еще не установлен, нужно открыть окно Terminal. Сделать это можно, щелкнув на значке Launchpad в Dock и ввести в поле поиска Terminal. Затем нужно осторожно ввести одной строкой следующую команду, поставив после fsSL вместо перевода на новую строку пробел: ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)” Этот процесс показан на рис. 27.4 (где запрашивается пароль для продолжения операции sudo).
Знакомство с Sass | 425 Рис. 27.4. Установка MacOS Homebrew ожидает ввода пароля При каждом запросе пароля вашего компьютера вводите его и нажимайте Enter (Ввод). Установка Homebrew выполняется средой языка Ruby, который уже должен быть на вашем Mac, и в зависимости от скорости интернет-соединения может занять несколько минут. Во время установки, как показано на рис. 27.5, можно будет заметить несколько запущенных программ и различные инструменты, установленные для использования с XCode: Рис. 27.5. Готовность к началу установки Homebrew После выполнения всех необходимых действий введите в терминал для запуска установки Sass следующую команду: brew install sass/sass/sass
426 | Глава 27 Сам процесс установки показан на рис. 27.6 (в данном случае установка уже выполнена, но Homebrew кое-что обновил). Рис. 27.6. Sass установлен и (или) обновлен Затем Mac сообщит, что идет загрузка различных файлов, и после установки ее успешное завершение можно подтвердить, введя следующую команду: sass --version Все в порядке! Будет получен простой ответ, похожий на следующий (для версии 1.49.9): 1.49.9 Использование этого метода установки под MacOS означает, что системный путь будет автоматически обновлен, поэтому, в какой бы папке вы ни находились, программу Sass можно запустить, просто введя ее имя в командной строке. Установка под Linux В операционной системе Linux зайдите в GitHub-репозиторий Sass по RL-адресу: https://tinyurl.com/getsass Под списком активов будет набор файлов (показанный ранее на рис. 27.1), из которых здесь перечислены только файлы для Linux (имена файлов в зависимости от номера версии могут быть другими):  dart-sass-1.49.9-linux-ia32.tar.gz  dart-sass-1.49.9-linux-x64.tar.gz Теперь нужно загрузить соответствующий файл, и для распаковки его содержимого воспользоваться стандартными средствами операционной системы. Затем нужно
Знакомство с Sass | 427 будет изменить путь, который используется вашей программой командной строки (например, Bash), чтобы включить в него папку dart-sass (или с другим выбранным вами названием распакованной папки). Как известно, путь — это набор имен папок, сохраненных в качестве настроек на вашем компьютере. Когда вводится имя программы, отсутствующей в текущей папке, компьютер может пройти по этому пути, выполняя поиск местоположения запускаемого файла. То есть программа может не находиться в текущей используемой папке, что позволяет хранить системные программы отдельно от документов проекта. Это можно делать и на временной основе при планировании запуска Sass, для чего вводится команда setenv: setenv PATH "$PATH\:path_to_dart-sass" Замените строку path_to_dart-sass правильным местом распаковки файлов Sass. Это изменение будет действовать в ходе текущего сеанса работы с командной строкой. Чтобы изменить системный путь на постоянной основе, следует обратиться к документации используемого дистрибутива Linux. Чтобы убедиться, что путь был изменен подобающим образом, нужно ввести в командной строке следующую команду: sass --version Все в порядке! Будет получен простой ответ, похожий на следующий (для версии 1.49.9): 1.49.9 Альтернативные установки под Linux Альтернативный способ установки Sass под Linux (хотя и более старой версии) — применение диспетчера приложений. Например, в Ubuntu можно сначала, чтобы убедиться, что все обновлено, выполнить следующую команду: sudo apt-get update -y Затем путем ввода следующей команды можно установить Ruby Sass (несколько отличающийся от Dart Sass): sudo apt-get install -y sass На рис. 27.7 показано применение этих двух команд в оболочке Ubuntu, работающей под управлением операционной системы Windows и поддерживаемой подсистемой Windows для Linux (WSL). Но они будут также хорошо работать и в автономном экземпляре Ubuntu. Чтобы убедиться, что все сработало, просто введите следующую команду: sass --version При желании можно провести установку с помощью Node.js. Для этого, если эта среда еще не установлена в вашей системе Linux, нужно ввести следующую команду: sudo apt-get install -y npm
428 | Глава 27 Рис. 27.7. Установка Sass в Ubuntu Linux с помощью apt-get После установки с ее помощью можно будет установить Sass, выдав следующую команду: sudo npm install -g sass Если с реализацией Sass на Ruby или с использованием Node.js для установки Dart Sass возникнут какие-либо проблемы, можно порекомендовать ручной режим установки из файла tar.gz, имеющегося на GitHub, с последующей рассмотренной ранее проверкой работоспособности всех установок и обновлений. Препроцессинг в CSS Теперь в командной строке всех трех основных операционных систем можно выполнить преобразование Sass-файлов в рабочие файлы CSS, выполнив следующую команду, в результате которой из одного места берется файл styles.scss, обрабатывается, а затем уже в другом месте в файле styles.css сохраняется результат этой обработки: sass source/stylesheets/styles.scss build/stylesheets/styles.css Указание исходных и целевых файлов имеет важное значение, и папки, в которых они находятся, рекомендуется хранить в разных местах, чтобы было понятно, где исходные файлы, а где готовые файлы сборки. После того, как это будет сделано, можно настроить Sass на просмотр исходного файла и автоматическую обработку его после каждого изменения, тем самым будет сэкономлено время, и нужная работа, словно по волшебству, будет выполнена в фоновом режиме. Для этого нужно ввести следующую команду: sass --watch source/stylesheets/styles.scss build/stylesheets/styles.css
Знакомство с Sass | 429 Теперь при каждом сохранении новой версии исходного файла вы можете просто предположить, что версия сборки чуть ли не сразу доступна для тестирования (при условии, что файл обрабатывается достаточно быстро, что обычно бывает со всеми, кроме самых больших и сложных файлов Sass). Можно также задавать просмотр целых папок и обновлять содержимое соответствующих им папок сборок, используя в следующей команде в качестве разделителя двоеточие: sass –watch source/stylesheets:build/stylesheets Теперь при обновлении любого файла в исходной папке он будет обработан и сохранен как соответствующий файл с тем же именем, но с расширением .css в папке сборки. Заключение Итак, у вас уже сложилось общее представление о Sass, его различных реализациях, о том, что он делает и как его использовать на различных платформах. Теперь можно приступать к самостоятельному применению препроцессора Sass и глубокому погружению в его использование с переменными, вложенностью, миксинами и многим другим при изучении последующих глав книги.
ГЛАВА 28 Переменные и потоки выполнения в Sass Введение Несомненно, CSS вряд ли можно назвать языком программирования, и поэтому на создание сложных макетов может уйти уйма времени. И тут на помощь приходит Sass, для полноценного применения которого нужно освоить ряд приемов программирования. Но не стоит переживать, это намного проще, чем может показаться, поскольку это практически то же самое, что и указание простых CSS-инструкций в сочетании с небольшой долей математики. Если вы в состоянии составить список покупок с возможными заменами по логике «если, иначе», то с кодом Sass вполне справитесь. Структура В этой главе рассматриваются следующие темы:  Чем переменные CSS отличаются от переменных Sass.  Что такое переменная, и как она работает.  Приобретение навыков выверенного применения операторов Sass.  Освоение способов применения функций управления потоком выполнения ин- струкций Sass. Цели Изучив материалы главы, вы освоите передовые методы, предлагаемые препроцессором Sass. Научитесь использовать переменные и циклические структуры и сможете создавать выражения для управления потоком выполнения кода, точно сообразуясь со своими потребностями.
432 | Глава 28 Переменные в CSS Вспомним, что в CSS3 последние версии браузеров поддерживают ограниченное использование переменных, а в качестве префикса переменной используется двойной дефис (--): #element { --main-bg-color: cyan; } В этом выражении переменная называется --main-bg-color и имеет значение cyan. Далее переменную можно будет применять в любых элементах с идентификатором element (и в их дочерних элементах). Но вне этой области переменная будет проигнорирована, поэтому вместо нее используются унаследованные значения. Чтобы у переменных были глобальные области видимости, позволяющие повсеместно применять их в вашем CSS, можно воспользоваться псевдоклассом :root: :root { --main-bg-color: cyan; } Чтобы затем присвоить значение переменной свойству, следует воспользоваться функцией var(): #mydiv { background-color: var(--main-bg-color); } Встроенный синтаксис языка для обработки переменных с помощью операторов отсутствует, но для достижения аналогичного результата можно воспользоваться CSS-функцией calc(). Например, можно создать пару переменных, содержащих значения пикселей: :root { --default-width : 100px; --default-height : 80px; } А затем ими можно будет воспользоваться в функции calc(), применяя их с использованием функции var(): #mydiv { width : calc(var(--default-width) + 20px); } Давайте объединим эти выражения в примере 28.1 и посмотрим на результаты их применения. Пример 28.1 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. <!DOCTYPE html> <html> <head> <title>CSS Variables</title> <style> :root { --default-width : 100px; --default-height : 80px; #div1 { width : var(--default-width ); height : var(--default-height); #div2 { } }
Переменные и потоки выполнения в Sass 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. width : height : div { background-color : float : margin : border : </style> </head> <body> <div id='div1'>This is <div id='div2'>This is </body> </html> | 433 calc(var(--default-width ) + 20px); calc(var(--default-height) + 20px); } lime; left; 10px; 1px solid black; } div1</div> div2</div> В строке 16 примера видно, что изначально у всех элементов <div> имеется черная граница, светло-зеленый фон, внешний отступ в 10 пикселей и свойство свободного плавания, позволяющее им выстраиваться в ряд. Чуть выше, в строках 7 и 8 документа, присваиваются значения переменным, а в строках с 9 по 14 для элементов с идентификаторами div1 и div2, которые ниже будут указаны для элементов <div>, задаются правила стилевого оформления. И наконец, в разделе документа <body>, начиная со строки 22, задается отображение двух элементов. Результат выполнения кода показан на рис. 28.1, где четко видно, что второй элемент на 20 пикселей шире и глубже первого, что стало результатом добавления этой величины к каждой из переменных и последующего применения результатов вычислений к размерам элемента. Рис. 28.1. Второй элемент больше по размерам в результате применения переменных и функций CSS Используя ряд функций с довольно длинными именами, можно также читать и устанавливать значения этих переменных из сценария JavaScript. Например, чтобы получить значение переменной CSS, можно вызвать функцию getComputedStyle(), которая вернет соответствующий элемент, и как только он будет получен, можно
434 | Глава 28 будет вызвать в отношении этого элемента функцию getPropertyValue(), применив следующую инструкцию: getComputedStyle(document.body).getPropertyValue('--default-width') Чтобы изменить значение, можно для свойства стиля соответствующего элемента вызвать функцию setProperty(), применив следующую инструкцию: document.body.style.setProperty('--default-width', '50px') А если открыть в браузере консоль разработчика и ввести в ней последнюю из этих двух инструкций, новое значение будет тут же применено, и результат будет таким, как показано на рис. 28.2 (где окно консоли наплывает на окно браузера): Рис. 28.2. Переменная CSS была обновлена в коде JavaScript Переменные в Sass Одной из основных причин быстрого роста популярности Sass было то, что в CSS долгое время не поддерживалось применение переменных. Но к нашему удовольствию, сейчас их уже поддерживают все основные браузеры, за редким исключением, куда входят Opera Mini и большинство браузеров Android до 2022 года — так что имейте это в виду! Но наряду со всеми другими стимулами к использованию Sass реализация переменных в CSS остается весьма примитивной и неудобной в использовании. Поэтому пользователи Sass довольно редко работают со встроенными функциями переменных CSS, полагаясь в основном на более высокую эффективность работы с самим Sass. Переменную в Sass можно создать в любой момент, поставив перед ее именем знак доллара и присвоив ей значение. В ранее рассмотренном примере 28.1 создавалась переменная с именем --default-width и, чтобы задать ей глобальную область видимости, ее нужно было применять к псевдоклассу :root. Если же ей не задана глобальная область видимости, переменная может быть использована только в выбранном элементе и его дочерних элементах. Получается, что переменная CSS в зависимости от того, где и как она используется, может иметь разные значения!
Переменные и потоки выполнения в Sass | 435 А вот в Sass, как только переменная инициализирована, она имеет неизменное значение везде, где используется, если только это значение не было изменено, но в таком случае далее уже применяется именно это новое значение. Следовательно, можно начать с переменной $default-width со значением 100px, а потом изменить его на 150px, и новое значение будет применяться только при последующем использовании этой переменной, а при более раннем сохранится прежнее значение 100px. А переменные CSS в случае их обновления распространяют изменение на все свои экземпляры, там, где они использовались в пределах своей области видимости. То есть, когда значение переменной CSS меняется со 100px на 150px, то для всех применений в этой области видимости устанавливается новое значение 150px. Подобное поведение пригодится, например, для анимации и событий наведения указателя мыши или же для других динамических взаимодействий, и в таком случае всегда можно воспользоваться как переменными CSS, так и переменными Sass. Главное о переменных Sass — они после препроцессинга исчезают и заменяются во вновь сгенерированном CSS фиксированными значениями. Такое явление называется императивом, поскольку во время применения переменной используется только ее текущее значение. А переменные CSS называются декларативными, поскольку при изменении их значений также обновляются и все значения при всех предыдущих использованиях переменной. Переменные CSS и Sass чувствительны к регистру, т. е. важно придерживаться точного применения символов верхнего и (или) нижнего регистра. Иными словами, переменные CSS --Text-Color и --text-color отличаются друг от друга, поскольку у одной из них заглавные начальные буквы в словах, а у другой нет. По аналогичной причине отличаются друг от друга и Sass-переменные $Text-Color и $text-color. Но у Sass есть одна особенность: он одинаково обрабатывает знаки подчеркивания (_) и дефисы (-). Их при желании можно поменять местами, и Sass по-прежнему будет работать как ни в чем не бывало. Это связано с тем, что Sass изначально использовал символ подчеркивания в качестве предпочтительного разделителя, и только позже также принял в этом же качестве дефис, чтобы стать более совместимым с CSS. В результате в CSS дефис и подчеркивание — разные символы, а в Sass они считаются одинаковыми. Значения переменных, используемые по умолчанию Когда переменной присваивается значение, она принимает его независимо от того, было ей уже присвоено значение или нет. Иными словами, если у переменной не было значения, оно присваивается, а если оно значение уже было, оно перезаписывается. Но иногда нужен более четкий контроль над тем, когда именно перезаписывать существующее значение, и поэтому, чтобы помочь защитить ранее назначенные
436 | Глава 28 значения, предоставляется флаг !default. Переменные, созданные с его использованием, не могут быть изменены, за исключением случаев, когда им еще не присвоено значение или когда их значение равно null. Но с библиотеками Sass может использоваться @use, позволяющее изменить значение переменной с установленным флагом !default. Предположим, у вас есть файл библиотеки с именем library.scss (при условии, что вы используете формат SCSS, а не SASS, в котором, как вы помните, вместо фигурных скобок, применяемых в SCSS, используются отступы). Поскольку эта библиотека будет импортирована, рекомендуется придерживаться соглашения о предварении имени файла символом подчеркивания, например: _library.scss. Идея состоит в том, чтобы хранить все импортированные библиотеки в одном месте, и поскольку они будут сортироваться, начиная с символа подчеркивания, то и показываться в списках каталогов они будут в самом начале. Придерживаться этого соглашения совершенно необязательно, поэтому решение остается за вами, и в книге этот стиль задания имен не используется. В примере 28.2 показано, как может выглядеть содержимое, помещаемое вами в такой библиотечный файл, включая использование флага !default. Пример 28.2 1. 2. 3. 4. 5. 6. 7. 8. 9. // library.scss $black : #000 !default; $border-radius : 0.25rem !default; $box-shadow : 0 0.5rem 1rem rgba($black, 0.15) !default; code { border-radius : $border-radius; box-shadow : $box-shadow; } А теперь давайте создадим пример 28.3 с кодом файла style.scss, который будет импортировать эту библиотеку: Пример 28.3 1. 2. 3. 4. 5. // style.scss @use 'library' with ( $black : #222, $border-radius : 0.1rem ); Давайте разберемся, что же происходит с этими двумя файлами. Итак, в library.scss создается несколько переменных: $black в строке 2, которой присваивается значение цвета #000, а также для нее указывается флаг !default. Для двух дру-
Переменные и потоки выполнения в Sass | 437 гих переменных, $border-radius и $box-shadow также устанавливаются исходные значения под флагом !default. После этого для HTML-элемента code задается такой стиль, при котором значения переменных $border-radius и $box-shadow применяются к его соответствующим свойствам. В файле style.scss файл библиотеки library.scss импортируется за счет применения правила @use, но с переопределением переменных $black и $border-radius, которым присваиваются новые значения. Но давайте вспомним, что переменные, объявленные во встроенном модуле, не могут быть изменены. К примеру, если, как показано ниже, попытаться переопределить значение PI, сделав его равным 3, произойдет сбой: @use "sass:math" as math; math.$pi : 3; Область видимости переменных Точно также, как и почти в любом языке программирования, использующем переменные, необходимо учитывать их область видимости. Область видимости переменной — это часть программы, в которой применяется ее значение. Например, в верхней части таблицы стилей переменная по умолчанию будет иметь глобальную область действия, поскольку она находится вне каких-либо подразделов. Это называется верхним уровнем. Но, переменные, объявленные в блоке в фигурных скобках (или в разделе с отступом в форматировании SASS), считаются локальными. Это означает, что их область действия применяется только в этом разделе кода. Более того, локальная переменная может иметь точно такое же имя, как и глобальная, и они не будут мешать друг другу. В примере 28.4 имеется верхний уровень и два локальных блока правил. Пример 28.4 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. $global-bg : #000; .content { $local-fs : italic; background : $global-bg; font-style : $local-fs; } .sidebar { background : $global-bg; font-style : $local-fs; }
438 | Глава 28 Здесь, в строке 1, объявлена глобальная переменная с именем $global-bg (ее имя может и не начинаться со слова global-, это просто удобное соглашение, которым можно воспользоваться, чтобы напомнить себе о том, что происходит). В этой переменной хранится значение цвета #000, предназначенное для использования в качестве фона (отсюда и bg в имени переменной). Ниже находятся два раздела кода, содержащие правила для содержимого (content) и боковой панели (sidebar) веб-страницы. В разделе .content в строке 4 создается локальная переменная $local-fs со значением italic. Очевидно, fs в имени переменной указывает на то, что она используется для применения в атрибуте font-style, но не забудьте, что вы можете использовать какое угодно соглашение об именовании переменных (или же соглашение, установленное вашим работодателем), и его соблюдение принесет реальную пользу вам и всем, кто получает доступ к вашему коду. Затем в строке 5 свойству background присваивается значение переменной $global-bg. Этот код срабатывает, поскольку переменная имеет глобальную область видимости. После этого в строке 6 свойству font-style присваивается значение переменной $local-fs, что также срабатывает, поскольку эта переменная находится в локальной области видимости. Но взгляните на раздел .sidebar, где свойству background в строке 10 вполне законно присвоено значение глобальной переменной $global-bg. Как вы думаете, что произойдет в строке 11? Дело в том, что $local-fs не находится ни в локальной области видимости, поскольку она не была определена в этом разделе, ни в глобальной области видимости, поскольку единственный другой экземпляр этого имени переменной находится в другом разделе, который имеет свою собственную локальную область видимости. Получается, что задание в строке 11 не будет выполнено. Принудительное задание глобальной видимости Иногда может понадобиться обновить глобальную переменную из подраздела таблицы стилей, и это можно сделать с помощью флага !global. Проще говоря, добавление !global после присваивания переменной значения позволяет обновить ранее существовавшую глобальную переменную из раздела кода, который обычно запрещает это. Обратите внимание, что создать таким образом новую глобальную переменную невозможно, но флаг !global можно применить для обновления глобальной переменной: .content { $global-bg : #246 !global; background : $global-bg; } Не забывайте, что при изменении значения глобальной переменной независимо от того, где это делается, новое значение используется с данного места и далее везде, где осуществляется доступ к переменной.
Переменные и потоки выполнения в Sass | 439 Управление потоком выполнения Один из наиболее важных аспектов языка программирования — возможность управления потоком выполняемых инструкций, осуществляемая в соответствии с различными правилами управления потоком в сочетании с целым рядом различных операторов. В Sass есть четыре основных правила управления потоком:  @if … @else … if  @each … in  @for … from … through/to  @while Чтобы объяснить, как они работают по отдельности или в различных комбинациях, необходимо уяснить порядок использования операторов Sass. В их роли выступают хорошо известные вам символы: +, -, * и /, а также более интересные операторы: ==, !=, >, < и другие. Операторы позволяют также сравнивать значения и заставлять их взаимодействовать друг с другом различными способами. Итак, давайте углубимся в эту тему. Sass-операторы В Sass поддерживаются шесть типов операторов:  Равенства: == и !=  Арифметические: +, -, *, /, = и %  Сравнения: <, <=, > и >=  Булевы: and, or и not  Конкатенации: +, - и /  Приоритета: ( и ) Хотя тех, кто никогда не занимался программированием, это может отпугнуть, но на самом деле все довольно просто. Например, оператор == (двойной знак равенства) используется для сравнения двух значений, чтобы определить, равны они друг другу или нет. Двойной знак равенства используется, чтобы его не путали с одинарным знаком равенства, используемым для присвоения значений. Группа символов != просто используется для проверки, равны или не равны два значения друг другу. По арифметическим операторам у вас не должно быть вопросов, за исключением, может быть, оператора %, который используется для вычисления остатка после деления. Например, 15pt % 6pt — это 2pt с остатком 3pt, поэтому получается значение 3pt (15/6 равно 2 с остатком 3). И здесь можно использовать любые допустимые значения CSS-измерения, а не только числа и различные типы.
440 | Глава 28 Операторы сравнения также должны иметь четкий смысл. Например, выражение 2 < 3 вычисляется в true, потому что < — это оператор «меньше, чем». Есть также оператор <= для «меньше или равно», и их противоположности — > для «больше, чем» и >= для «больше или равно». Поскольку типы измерений в CSS могут смешиваться и сопоставляться, эти операторы действительно пригодятся, следовательно, когда результат смешанного вычисления между смешанными типами измерений с первого взгляда не очевиден (в противном случае можно было бы просто ввести значение результата), можно взамен воспользоваться таким выражением, как 1in < 73pt, которое вычисляется в true, поскольку в дюйме 72 пункта. Теперь обратимся к, возможно, менее очевидным операторам, начиная с булевых операторов and, or и not (соответственно, «и», «или» и «не»). С их помощью можно создавать составные выражения типа «если это и это», или, может быть, «если не это», или если «это или то». Думайте об их использовании точно так же, как это было бы сказано в обычной речи, поскольку именно так они и работают. Эти операторы называются булевыми в честь человека, который их изобрел (Джордж Буль), и представляют значения истинности в логических выражениях. Остается еще несколько операторов конкатенации и приоритета. Конкатенация просто означает соединение двух элементов вместе, которые обычно являются строковыми значениями, но в процессе числовые значения могут присоединяться к строковым значениям для создания новой строки. Здесь следует проявлять осмотрительность, так как оператор + также используется для операции сложения. Следовательно, 1 + 2 равно числу 3, а Light + Blue в строке задания цвета CSS равно значению LightBlue. Оператор, обозначаемый знаком минуса (–) при использовании для конкатенации работает необычным образом в качестве сокращения для таких выражений, как sans- + serif, которые вычисляются в sans-serif. Вместо этого для получения точно такого же результата можно воспользоваться выражением sans - serif. Точно так же для конкатенации можно использовать оператор /, если он помещается перед не полностью числовым значением, например: / 24pt, что после конкатенации превратится в значение /24pt, как, собственно, и оператор -, использованный таким образом: - moz, после конкатенации выдаст результат -moz. Но эти последние варианты использования предназначены для исторической совместимости и не рекомендованы к использованию. И все же вам следует знать о них, чтобы понять уже существующий код, который может использовать эти операторы так. Sass-выражения (Sass-сценарий) Выражением в Sass считается все, что находится в правой части объявления свойства или переменной. Каждое выражение создает значение, и любое допустимое значение свойства CSS — также выражение Sass. Выражения Sass передаются в качестве аргументов миксинам и функциям, используются для управления потоком
Переменные и потоки выполнения в Sass | 441 выполнения инструкций и управляются с помощью арифметики. Синтаксис выражений Sass называется SassScript. Мы уже рассмотрели операторы, используемые в Sass, а также кратко рассмотрели поддерживаемые типы управления потоком, поэтому теперь давайте рассмотрим каждый из этих четырех типов по очереди. @if … @else Как и следовало ожидать, тип управления потоком @if принимает выражение, при вычислении которого в true выполняет следующую инструкцию, объявление или присваивание. Если также используется необязательное ключевое слово @else, и, если выражение не вычисляется в true, то все, что следует за @else, будет выполнено. Давайте посмотрим, как это работает, в примере 28.5. Пример 28.5 1. 2. 3. 4. 5. 6. 7. 8. $bord-rad : false; @if $bord-rad { border-radius : 10px; } @else { border-radius : 0; } В строке 1 создается переменная с именем $bord-rad, которой присваивается значение false. Затем инструкция @if в строке 3 проверяет это значение, и, если оно вычисляется в true, следующему свойству border-radius присваивается значение 10px. Если же $bord-rad не вычисляется в true, выполняется инструкция @else в строке 6, гарантирующая, что у границ не будут радиуса. В исходном варианте в этом примере не будут отображаться закругленные углы границ из-за того, что $bord-rad имеет значение false. Это очень простой пример выражения, в котором вычисляется значение только одной переменной. Любое значение, равное null или нулю, рассматривается Sass как ложное и поэтому вычисляется в false. Любое другое значение считается истинным и будет вычисляться в true. Это правило распространяется даже на пустые строки, пустые списки и даже на число 0. Все это считается истинным. А в документах Sass действительно используются слова falsey и truthy («фальшивый» и «правдивый»)! Итак, что это означает на практике? Помимо возможности присваивать переменным значения true или false, вам придется также работать с любыми значениями, которые они могут иметь (или не иметь), и они все равно будут вычисляться либо в true, либо в false. Например, значение 24pt истинно, так же как и «Arial Bold».
442 | Глава 28 Единственные одиночные значения переменной, которые будут вычисляться в false, — false и null. А вот сложные выражения — совсем другое дело, поскольку, как показано в примере 28.6, для получения логического результата либо true, либо false, вычисляется все выражение. Пример 28.6 1. 2. 3. 4. 5. 6. 7. 8. 9. $margin : 10px; $padding : 10px; @if $margin + $padding >= 20px { border-color : green; } @else { border-color : black; } В этом примере есть две переменные с именами $margin и $padding, каждой из которых присвоено значение 10px. В строке 4 эти два значения складываются, и результат проверяется на соответствие выражению «больше или равно 20px». Если это так, то свойству border-color в строке 5 присваивается значение green, в противном случае в строке 8 ему присваивается значение black. Конечно же, можно применить любое другое сравнение, например <= или == и т. д., все зависит от того, что именно нужно оценить. В качестве альтернативы может появиться желание протестировать более одного выражения, как в примере 28.7, в котором две переменные проверяются независимо друг от друга. Пример 28.7 1. 2. 3. 4. 5. 6. 7. 8. 9. $margin : 10px; $padding : 10px; @if ($margin == 10px) and ($padding >= 10px) { border-color : green; } @else { border-color : black; } Здесь проводится тест с целью определения, имеется ли у $margin значение, в точности равное 10px, а также является ли значение переменной $padding большим или равным 10px. При одном только условии, что оба эти выражения вычисляются в true
Переменные и потоки выполнения в Sass | 443 (из-за использования ключевого слова and), свойству border-color будет в строке 5 присвоено значение green. Влияние скобок Обратите внимание на использование скобок в примере 28.7 для заключения в них каждого выражения и для того, чтобы и вам, и Sass было понятно, что и для чего предназначено. Используя круглые скобки, можно гарантировать, что их содержимое будет вычислено перед вычислением элементов, находящихся снаружи. Например, круглые скобки можно использовать для переопределения естественного приоритета операторов. Дело в том, что по соглашению операторы * и / имеют более высокий приоритет, чем операторы + и -, поскольку обладают гораздо более сильным эффектом. Следовательно, выражение со сложением, 2 + 3 * 5 - 4 вычисляется в 13, а не в 21 (что стало бы верным ответом, если бы в Sass вычисление велось строго слева направо). Но по соглашению в Sass сначала выполняется умножение 3 на 5, и только затем прибавляется 2 и вычитается 4. При желании заставить Sass вычислять все строго слева направо, это можно сделать с помощью скобок: (2 + 3 ) * 5 - 4, и тогда действительно будет получен результат 21. Обратите внимание, что (2 + 3) * (5 - 4) будет уже совершенно другим вычислением, приводящим к ответу 5, потому что сначала будут вычисляться два выделенных выражения, а потом они будут перемножаться. @else if Простое выражение @if … @else как тип управления потоком можно расширять до бесконечности, добавляя if после любого @else. Как это делается на практике, показано в примере 28.8. Пример 28.8 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. $margin : 10px; @if $margin == 10px { border-color : green; } @else if $margin == 15px { border-color : blue; } @else { border-color : black; }
444 | Глава 28 В этом примере в строке 6 показано использование @else if с целью проверки значения переменной $margin, отличной от той проверки, что была в строке 3. В данном случае, если $margin имеет значение 15px, в строке 7 свойству border-color присваивается значение blue. И наконец, в строке 9 имеется отдельный оператор @else, завершающий последовательность, и при необходимости между ними может быть больше операторов @else if. @each … in Теперь, освоив выражения @if … @else, давайте перейдем к чему-либо более сложному с ключевым словом @each. Чтобы оценить эффективность функции, представьте, что вам нужно создать несколько значков разных размеров, но вы не хотите записывать несколько отдельных наборов правил. Из примера 28.9 следует, что Sass позволяет легко справиться с этой задачей. Пример 28.9 1. 2. 3. 4. 5. 6. 7. 8. 9. $sizes : 40px, 60px, 80px, 100px; @each $size in $sizes { .icon-#{$size} { font-size : $size; height : $size; width : $size; } } Конечно же, может возникнуть вопрос: «А это еще что такое?» Расслабьтесь, поскольку вам это понравится. Эти 9 строк Sass превратятся в гораздо большее количество строк CSS. В строке 1 создается переменная по имени $sizes. Но это особый тип переменной, называемый списком. Он создается обычным способом, но с добавлением дополнительных значений, разделенных запятыми, чтобы переменная превратилась в список. В данном случае это набор из четырех значений в диапазоне от 40px до 100px. Сила списка демонстрируется начиная со строки 3 с ключевого слова @each. Этот оператор поочередно извлекает каждое значение списка $sizes при каждом проходе цикла. Всякий раз в цикле значение, извлеченное из $sizes, помещается в переменную $size (обратите внимание, что это слово — единственное число от слова $sizes, но на его месте может быть любое выбранное вами имя), а затем в строке 4 доступ к этому значению осуществляется с помощью выражения #{$size}, который заменяется фактическим значением, а затем добавляется к строке .icon-. Так, например, значение первого элемента списка равно 40px, и это значение добавляется к .icon-, в результате чего получается .icon-40px.
Переменные и потоки выполнения в Sass | 445 Затем команда @each переходит к оставшимся трем значениям в списке, создавая CSS, показанный в примере 28.10. Пример 28.10 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. .icon-40px { font-size : 40px; height : 40px; width : 40px; } .icon-60px { font-size : 60px; height : 60px; width : 60px; } .icon-80px { font-size : 80px; height : 80px; width : 80px; } .icon-100px font-size height width } { : 100px; : 100px; : 100px; Теперь имеются готовые к использованию четыре класса CSS. Видите, как использование @each может избавить вас от написания множества утомительных сценариев CSS. С помощью этого метода можно оптимизировать любой набор значений, доступный к сохранению в списке, а затем преобразовать его в несколько наборов правил. @for … from … through В эффективности применения ключевого слова @each уже нет никаких сомнений, но в Sass есть еще более эффективные приемы обращения с циклическими структурами, например применение команды @for. С ее помощью можно вести счет вверх (или вниз) от одного числа к другому, вычисляя блок правил для каждого шага между ними. Как и в случае с @each, каждое значение присваивается переменной при каждом проходе цикла. Давайте рассмотрим случай, когда нужно присвоить значения свойству font-size различных элементов от h1 до h5, чтобы заменить их значения по умолчанию,
446 | Глава 28 в диапазоне от 24pt для h1 до 8pt для h2. Один из способов выполнения этой задачи в Sass показан в примере 28.11: Пример 28.11 1. 2. 3. 4. 5. 6. 7. $heading-size: 28pt; @for $i from 1 through 5 { h#{$i} { font-size : $heading-size - ($i * 4); } } Здесь происходит следующее: в строке 1 создается переменная с именем $headingи со значением 28pt. Затем в строке 3 ключевое слово @for используется с ключевыми словами from и through для последовательного перебора значений от 1 до 5, а в строке 4 к каждому из этих чисел добавляется буква h, чтобы составлялись имена элементов от h1 и до h5. size Затем в строке 5 для каждого из этих элементов устанавливается свойство font-size путем вычитания значения в $i, умноженного на 4, из значения в $heading-size. В результате h1 будет иметь значение свойства font-size, равное 24pt, h2 — равное 20pt, и далее до h5, у которого свойство font-size будет иметь значение всего 8pt. Созданный препроцессором код CSS будет выглядеть, как показано в примере 28.12: Пример 28.12 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. h1 { font-size : 24pt; } h2 { font-size : 20pt; } h3 { font-size : 16pt; } h4 { font-size : 12pt; } h5 { font-size : 8pt; }
Переменные и потоки выполнения в Sass | 447 @for … from … to В примере 28.11 все просто замечательно, но в Sass нужен был небольшой обходной путь, поскольку первая строка должна была начинаться со свойства font-size со значением на 4pt больше, чем требовалось, чтобы учесть вычитание кратных сумм по 4pt в цикле. Вместо этого лучше воспользоваться конструкцией @for … from … to, которая будет выполнять итерацию от значения from и до значения to, но не включая значение to. Эта конструкция отличается от той, что была в предыдущем примере, где использовалось ключевое слово through и выполнялись итерации до значения through включительно. В примере 28.13 показано, как немного улучшить предыдущий код. Пример 28.13 1. 2. 3. 4. 5. 6. 7. 8. $heading-size : 24pt; @for $i from 5 to 0 { h#{$i} { font-size : $heading-size; $heading-size : $heading-size - 4pt; } } В этом примере в сроке 1 свойству $heading-size сразу присваивается правильное значение, а затем цикл @for в строке 3 ведет обратный отсчет от 5 до 1, но не до 0, поскольку вместо through используется ключевое слово tо. При каждом проходе цикла это значение присваивается свойству font-size элементов от h5 до h1, а затем в строке 6 из значения переменной вычитается 4pt, чтобы при следующем проходе цикла ее значение было меньше именно на эту величину. Конечный результат аналогичен тому, что был при выполнении кода примера 28.12, за исключением того, что элементы с h5 по h1 фигурируют здесь в обратном порядке. Конечно, пример 28.13 также можно превратить в пример 28.14, используя through вместо to, показывая тем самым, что выбор между ключевыми словами to и through, как правило, просто вопрос личных предпочтений, поскольку вы, конечно же, можете найти способы, заставляющие работать на вас любое ключевое слово. Пример 28.14 1. 2. 3. 4. 5. 6. 7. 8. $heading-size : 24pt; @for $i from 5 through 1 { h#{$i} { font-size : $heading-size; $heading-size : $heading-size - 4pt; } }
448 | Глава 28 @while И последний способ управления потоком выполнения и циклами — @while. Им следует пользоваться осмотрительно, поскольку он допускает создание бесконечного цикла, который никогда не будет остановлен. Дело в том, что при использовании @while цикл повторяется до тех пор, пока вычисляемое им выражение имеет значение true. Если оно никогда не будет вычислено в false, цикл будет повторяться вечно. Исходя из этого, лучше будет воспользоваться циклами @each или @for, ведь их проще использовать, и другим будет легче разобраться в вашем коде. Кроме того, не будет риска бесконечного зацикливания. И хотя бывают случаи, когда применение @while предпочтительнее, из-за сложности их описание не сочетается с темой книги. И все же в качестве упражнения для понимания порядка работы цикла, задаваемого этим ключевым словом, давайте внесем изменения в пример 28.14, чтобы получился, код, показанный в примере 28.15, где используется цикл @while. Пример 28.15 1. 2. 3. 4. 5. 6. 7. 8. $heading-size : 24pt; @while $heading-size >= 8pt { h#{$i} { font-size : $heading-size; $heading-size : $heading-size – 4pt; } } Заметьте, что здесь изменилась только строка 3. Теперь при каждом проходе цикла выполняется только один простой тест. Пока значение $heading-size больше или равно 8pt, цикл продолжается. Но когда значение становится меньше 8pt, цикл завершается. Отчасти этот код может показаться проще, чем при использовании @for, но если забыть или неподобающим образом уменьшить значение в $heading-size до размера менее 8pt, то цикл никогда не завершится. Поэтому применять это ключевое слово нужно с особой осторожностью. Заключение На этом весьма подробное введение в использование переменных и управление потоком выполнения в Sass завершается. Теперь на основании полученных знаний можно будет в следующей главе перейти к изучению вложенности и наследования.
ГЛАВА 29 Расширенный Sass Введение Sass позволяет создавать более понятный и самодостаточный код CSS, чем тот, что поддерживается самой технологией CSS. Например, для создания списка в CSS требуются отдельные наборы правил, но в Sass можно вложить все соответствующие правила в один раздел. В этой главе рассматриваются функции, предоставляющие вам всю эту мощь. Например, Sass предлагает посредством наследования непревзойденную поддержку совместного использования свойств CSS одного селектора другими. Уже не нужно многократно повторять наборы правил, поскольку при желании использовать уже имеющийся в другом месте, можно просто расширить область его действия без набора большого объема кода. Более того, можно также воспользоваться функциональной возможностью под названием миксины, с помощью которой можно копировать стили в текущее правило стиля. Вскоре будет показано, как миксины используются для группировки кода CSS, предназначенного для повторного использования, и как они могут также принимать параметры. Благодаря этим функциям Sass все больше, чем когда либо, превращает CSS в язык программирования. Sass допускает простые и логичные конструкции, максимально упрощающие понимание и отладку кода CSS, а также позволяет сделать работу быстрее и приятнее. Структура В этой главе рассматриваются следующие темы:  Изучение имеющихся в Sass способов, позволяющих создавать вложенные раз- делы правил.  Осознание разницы между наследованием и использованием примесей.  Изучение возможности загрузки и использования объемных дополнительных функций в модулях Sass.
450 | Глава 29  Получение дополнительных сведений о Sass и отслеживание хода развития этой системы. Цели Цель главы — заполнить оставшиеся пробелы в знаниях Sass, чтобы к завершению изучения материала были усвоены все основные функции и преимущества, предоставляемые им. Усвоив изложенные здесь сведения, вы будете знать, откуда можно взять дополнительную информацию, если она вам понадобится. Кроме того, завершив работу с книгой, вы станете выпускником мастер-класса по HTML5 и CSS3. Вложенность, используемая в Sass О концепции вложенности списков уже шла речь во введении. А теперь давайте посмотрим, как это работает, обратившись к примеру 29.1, представляющему собой простой документ HTML5 с элементами CSS и HTML. Пример 29.1 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. <!DOCTYPE html> <html> <head> <title>Navigation List</title> <style> nav ul { margin : 0; padding : 0; list-style : none; } nav li { display : inline-block; } nav a { display : block; padding : 3px 8px; font-weight : bold; text-decoration : none; } nav a:hover { text-decoration : underline; } </style> </head> <body>
Расширенный Sass 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. <nav> <ul> <li><a <li><a <li><a <li><a </ul> </nav> </body> </html> | 451 href='https://google.com'>Google</a></li> href='https://microsoft.com'>Microsoft</a></li> href='https://apple.com'>Apple</a></li> href='https://amazon.com'>Amazon</a></li> Код примера просто выводит на экран список переходов по ссылкам навигации из расположенных в ряд четырех элементов, и, когда указатель мыши наводится на один из них, он становится подчеркнутым, показывая, что на нем можно щелкнуть мышью. Соответствующий этому замыслу код CSS находится между строками 7 и 22, а код HTML — между строками 26 и 33. На рис. 29.1 показана ссылка на Apple, подчеркнутая из-за наведения на нее указателя мыши (браузер для удобства пользователя также отобразил внизу слева пункт назначения ссылки): Рис. 29.1. Список навигации с одной ссылкой, выделенной подчеркиванием А теперь давайте посмотрим, как можно сделать раздел CSS максимально самодостаточным, воспользовавшись кодом Sass, показанным в примере 29.2. Пример 29.2 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. nav { ul { margin padding list-style li { display a { display padding font-weight text-decoration : 0; : 0; : none; : inline-block; : : : : block; 3px 8px; bold; none;
452 13. 14. 15. 16. 17. 18. 19. | Глава 29 } a:hover { text-decoration : underline; } } } } Заметьте, что теперь в самом начале имеется только одно упоминание об элементе <nav>, а все элементы, присутствующие внутри него в HTML, теперь также находятся в Sass. Это вполне логично, поскольку здесь отражается способ размещения HTML в строках с 26 по 33 примера 29.1. Фактически, здесь воспроизводится даже вложение элементов <a> в элементы <li>, и все это внутри элемента <nav>. Разумеется, при желании появления подэлементов в элементе <nav> в произвольном порядке (а не только в порядке вложенности, показанном в примере 29.1), можно просто поместить их все в один нижний уровень вложенности. Привлекательность такого подхода в том, что он полностью зависит от вас и соответствует желаемому результату. Вложенные свойства Конечно, такое количество вложений создает массу удобств и не создает трудностей для понимания, но Sass обладает еще большей эффективностью, продвигая вложенность на более высокий уровень с помощью вложенных свойств. Рассмотрим, к примеру, все правила шрифтов и текста (font- и text-), поддерживаемые CSS, используя разные имена правил. Если вы посмотрите Sass-код в примере 29.3, то увидите, как все эти правила могут быть вложены друг в друга, в результате чего макет становится куда более простым для понимания, чем простой CSS. Пример 29.3 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. font: { family size weight } : Courier New, monospace; : 16px; : bold; text: { align transform indent overflow } : : : : justify; capitalize; 7px; hidden;
Расширенный Sass | 453 Здесь есть только два основных раздела: один для шрифта, а другой для текста, и в каждом находятся те части правил, которые обычно появляются после дефиса, но здесь они сами по себе. Вложение можно использовать везде, где есть тип правила CSS, написанный через дефис, чтобы все можно было изложить с помощью Sass гораздо четче и логичнее. И помните, что с сокращенными именами свойств, когда все значения свойств относятся к разным типам, так работать гораздо проще, чем вспоминать правильный порядок размещения нескольких значений, используя, к примеру, заученное правило: «Сомневаешься — иди по часовой стрелке». Наследование в Sass Вы ведь нервничали, когда создавали правила CSS, постоянно копируя и вставляя наборы правил, применяемые не только в одном разделе? Тогда у Sass есть для вас отличное решение — использование наследования, позволяющего классам наследовать свойства друг друга. Оно работает с помощью директивы Sass @extend и является эффективным способом добавления ясности и простоты в ваш CSS. В примере 29.4 показано применение набора правил для отображения сообщений. Пример 29.4 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. .messagebox { border : 2px dashed #000; border-radius : 10px; background : #222; padding : 10px; color : #ddd; } .loggedin { @extend .messagebox; background : darkgreen; color : #dfd; } .notloggedin { @extend .messagebox; background : dimgrey; color : #dad; } .badlogin { @extend .messagebox; background : darkred; color : #fdd; }
454 | Глава 29 Начиная со строки 1 создаются правила для класса окна сообщений messagebox. В них задается двухпиксельная пунктирная граница черного цвета с закругленными углами, темно-серый фон, не совсем белый цвет и внутренний отступ. Далее следуют правила еще для трех классов (loggedin, notloggedin и badlogin), в которые расширяется messagebox, изменяются свойства фона и цвета, но сохраняются при необходимости все остальные атрибуты. А теперь давайте посмотрим, как этого же самого можно достичь в простом CSS, код которого показан в примере 29.5, где одновременно задаются правила сразу для нескольких классов. Пример 29.5 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. .messagebox, .loggedin, .notloggedin, .badlogin { border : 2px dashed #000; border-radius : 10px; background : #222; padding : 10px; color : #ddd; } .loggedin { background : darkgreen; color : #dfd; } .notloggedin { background : dimgrey; color : #dad; } .badlogin { background : darkred; color : #fdd; } Обратите внимание на то, что в строке 1 все имена классов разделены запятыми. Благодаря этому все правила в фигурных скобках применяются ко всем перечисленным классам. Затем чуть ниже последние три названных класса получают свои уникальные значения свойств. В примере CSS возникает проблема, связанная с тем, что в правилах для этих классов нет явного указания на унаследованные значения. Здесь с точки зрения ясности Sass — лучшее решение, чем CSS, так как в его коде используется более логичный подход, обеспечивающий, что в правилах каждого последующего класса четко сообщается, откуда они унаследовали другие свойства. С точки зрения программиста, разобраться в CSS может непросто, особенно если правила для класса messagebox находятся на некотором удалении от других классов. А вот код Sass полностью понятен с первого взгляда, в силу чего менее подвержен
Расширенный Sass | 455 появлению ошибок стиля, допускаемых как вами, так и другими людьми, сопровождающими код. Именно здесь удачно сочетаются хороший стиль и эффективные приемы программирования, облегчающие жизнь всем причастным. Использование миксинов Теперь, разобравшись с наследованием, следует прейти к изучению миксинов, схожих по эффекту, но обладающих собственными уникальными особенностями. В понятиях программирования, как было показано, для поддержки наследования используется @extend, т. е. ссылка расширяется для получения точно такого же тела, как и у правила. А использование @include подобно вызову функции (с параметрами или без них), что похоже на вызов функции JavaScript. В примере 29.6 создается миксин по имени fullres, предназначенный для установки значений свойств width и height любого использующего его объекта равными 100%. Чуть ниже для элементов body и p документа эти значения устанавливаются с помощью ключевого слова @include, используемого для вызова миксина fullres. Пример 29.6 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. @mixin fullres { width : 100%; height : 100%; } body { @include fullres; } p { @include fullres; } Здесь можно спросить: а чем это выгоднее использования ключевого слова @extend, предназначенного для наследования значений свойств? Хороший вопрос, на который лучше всего ответить в примере 29.7, где вдобавок ко всему передаются параметры. Пример 29.7 1. 2. 3. 4. 5. @mixin fullres($w: 100%, $h: 100%) { width : $w; height : $h; } body {
456 6. 7. 8. 9. 10. | Глава 29 @include fullres(960px); } p { @include fullres; } Теперь становится очевидной вся эффективность миксинов: в строке 1 примера 29.7 две переменные с именами $w и $h (для ширины и высоты) имеют значение 100%, затем ниже, в строках 2 и 3, значения этих переменных применяются к свойствам ширины и высоты. Но самое интересное происходит в строке 6, где вызывается миксин, которому передается значение 960px. Теперь это значение передается миксину fullres, где он переписывает исходное заданное ему при определении значение 100%. В силу этого теперь переменная $w имеет значение 960px, и поэтому миксин возвращает для свойства width значение 960px, а для свойства height возвращается исходное значение 100% (поскольку второе значение миксину не передавалось). В строке 9 fullres вызывается без аргументов, и поэтому для свойств width и height возвращаются исходные значения 100%. Следовательно, общее правило гласит: @extend следует использовать для наследования набора свойств от другой функции, а @include — для вызова функции миксина с возможной передачей аргументов и возвратом значений для их применения к свойствам. Модули Sass Как, наверное, и следовало ожидать, Sass поставляется с рядом готовых модулей (с семью, если быть точным), которые можно вызывать как миксины для достижения различных результатов, охватывающих области от математики до обработки цвета и совершения многих других дел. Прежде чем воспользоваться модулями, следует знать, что до введения модульной системы все функции были глобально доступны в любой момент, и любые функции по-прежнему имеют глобальные псевдонимы. Например, можно получить глобальный доступ к sass:math.$pi. И все же команда Sass не одобряет подобное использование, поскольку планирует отказаться от этого средства доступа в будущем. Поэтому для загрузки любых нужных модулей рекомендуется сначала применить команду @use: @use "sass:math"; Теперь с помощью следующей инструкции можно получить доступ к функциям из модулей, загруженных с использованием @use: $twopi : calc(math.$pi * 2);
Расширенный Sass | 457 Разобравшись с этой особенностью, давайте изучим список доступных модулей:  sass:math: Набор функций для работы с числами.  sass:string: Набор функций для объединения, поиска или разбиения строк.  sass:color: Набор функций для создания новых цветов на основе уже сущест- вующих.  sass:list: Набор функций, позволяющих получать доступ к спискам и изменять значения в них.  sass:map: Набор функций для поиска значений, связанных с ключом в ассоциа- тивном массиве.  sass:selector: Набор функций, обеспечивающих доступ к механизму селекторов Sass.  sass:meta: Набор функций, раскрывающих детали внутренней работы Sass. Подробное описание каждого отдельно взятого модуля и всех его функций достойно целой книги, поэтому сейчас настало время отослать вас к исчерпывающей документации, доступной в Sass по следующему URL-адресу, где даются подробные ответы на все возникающие у вас вопросы: tinyurl.com/sassmodules Будущие версии Новые версии Sass спроектированы таким образом, чтобы быть максимально совместимыми с предыдущими, но иногда возникает необходимость во внесении критических изменений, чтобы идти в ногу с постоянно развивающейся спецификацией CSS, а порой необходимо исправлять и старые проектные ошибки языка. Перед выпуском каких-либо критических изменений реализации Sass будут выдавать предупреждения об отказе от стилей с изменившимся поведением, и по мере возможностей эти предупреждения будут включать в себя предложения по обновлению устаревших стилей, чтобы сделать их совместимыми с последующими версиями. Нужно учесть, что разные реализации придерживаются разных политик в отношении критических изменений и устаревания стилей. Например, команда Dart Sass будет выдавать предупреждения об устаревании как минимум за три месяца до выпуска критического изменения и выпустит его с новым основным номером версии, если это изменение не потребуется для поддержки совместимости с CSS. Изменения, связанные с поддержкой совместимости с CSS, как правило, недеструктивные и своевременные, поэтому они могут быть выпущены с новыми младшими номерами версий. Все это означает, что Sass находится в постоянном развитии, не допускающем отставания от развития CSS, поэтому, приступая к его использованию, оставайтесь в курсе событий, подписывайтесь на группы Sass в социальных сетях, проверяйте Sass-страницу в GitHub и регулярно посещайте сайт sass-lang.com, чтобы не отстать от жизни.
458 | Глава 29 Заключение Ну вот и все! Вы прошли путь до конца всеобъемлющего и подробного руководства по использованию с максимальной эффективностью как HTML5, так и CSS3, и теперь вы освоили все, что нужно для применения новых знаний во всех без исключения проектах с вашим участием. Хотя этого можно и не осознавать, но в этой книге вам действительно удалось охватить весьма большой объем информации, и очень хорошо, что вы с этим справились, поскольку теперь вам известно все об установке веб-серверов и таких инструментов программирования, как Visual Studio Code. Состоялось также полное знакомство с консолью разработчика, встроенной во все современные браузеры. Удалось разобраться во всех тонкостях доступа к холсту HTML5, создании на нем надписей и рисунков, освоить обработку геолокации, расширенную обработку форм, работу с локальным хранилищем и с другими возможностями, предоставляемыми HTML5, такими как аудио и видео. Вдобавок ко всему, удалось вполне достаточно разобраться в возможностях CSS3, позволяющих создавать высококачественные веб-сайты, начиная с методов создания фона, использования цвета и прозрачности, добавления текстовых и шрифтовых эффектов и многого другого, вплоть до добавления двумерных и даже трехмерных преобразований и переходов. Теперь вполне освоенными инструментами станут самые последние улучшения, появившиеся в CSS3 — макеты Flexbox и сетка CSS Grid. И чтобы поднять разработку таблиц CSS на новый уровень, теперь вам можно получить доступ к чрезвычайно мощному набору инструментов и функций Sass, повышающему скорость разработки и точность проектирования макетов. Вот вы и овладели всеми этими инструментами и готовы применить их на практике. Большое спасибо за чтение книги. Если она помогла вам в веб-разработке и дизайне, оставьте онлайн-отзыв, чтобы о книге могли узнать другие люди. А теперь идите и создавайте фантастические вещи!
Метаданные НАЗВАНИЕ КНИГИ: Мастер-класс по HTML5 и CSS3 ПОДЗАГОЛОВОК: От новичка к эксперту за 29 простых шагов ИМЯ АВТОРА: Робин Никсон (Robin Nixon) КАТЕГОРИИ: Веб-разработка, Веб-дизайн, Программирование РЕКЛАМНЫЙ СЛОГАН: Все, о чем нужно знать, чтобы стать мастером вебразработки ОСНОВНЫЕ МОМЕНТЫ:  Изучение или освежение в памяти основ HTML и CSS  Освоение лучших инструментов разработки веб-дизайна  Приобретение навыков создания надписей и рисунков на холстах HTML5  Освоение приемов использования геолокации и картографирования для улучше- ния пользовательского восприятия  Изучение способов вставки аудио- и видеоинформации в веб-страницы и при- ложения  Приобретение навыков создания усовершенствованных форм ввода информации с простой обработкой ошибок  Освоение приемов доступа к локальному хранилищу с целью создания веб-стра- ниц с моментальным откликом  Приобретение навыков создания усовершенствованных макетов с двумерными и трехмерными преобразованиями и анимацией  Изучение эффективных приемов веб-дизайна с применением CSS Grid  Освоение возможностей, предоставляемых макетом Flexbox  Изучение порядка использования Sass, чтобы поднять приемы разработки CSS на следующий уровень Описание Мастер-класс по HTML5 и CSS3 — исчерпывающее руководство, предполагающее лишь наличие поверхностных знаний HTML и CSS и желание перевести имеющие-
460 | Метаданные ся навыки веб-разработки на новый уровень. Каждый шаг на этом пути выполняется последовательно с готовыми рабочими примерами и многочисленными рисунками, четко иллюстрирующими то, чему здесь учат. Написанная в дружественном и легком для восприятия стиле, с большим количеством авторских наблюдений и наработок, эта книга отправит вас в путешествие по всему, что нужно узнать, чтобы наиболее эффективно воспользоваться новейшими инструментами, доступными в настоящее время в арсенале передовых веб-разработчиков. Разбирая приводимые в книге примеры, вы поочередно изучите, а затем освоите каждый новый прием, и только после этого состоится переход к следующим. По мере изучения материалов книги будет складываться все более четкое представление о типах функций, доступных вам благодаря новым мощным технологиям, добавленным как в HTML, так и в CSS. В начале каждой главы подробно рассказывается о ключевых элементах, подлежащих изучению, и ставится цель, к которой нужно стремиться с позиции тех знаний и навыков, которые следует приобрести к моменту завершения изучения главы. Учитывая объем знаний, подлежащих усвоению, и уровень глубокого понимания, которого следует достичь, эта книга станет мощным шагом на пути повышения ваших возможностей по трудоустройству, а также гораздо более успешного и быстрого продвижения по избранной вами карьерной лестнице. Чему вы сможете научиться  Вы получите полноценное представление о текущем уровне технологий и инст- рументов, предоставляемых как в HTML5, так и в CSS3.  Вы приобретете навыки, необходимые для создания веб-сайтов, не уступаю- щих по своим стандартам лучшим доступным в настоящее время в Интернете образцам.  Вы овладеете приемами, всего лишь несколько лет назад считавшимися особо трудоемкими и сложными при разработке на JavaScript, но в настоящее время вполне доступными и готовыми к простому применению во всех современных браузерах. Для кого эта книга Книга предназначена для тех, кто уже занимается веб-разработкой или только ступил на эту стезю, а также для всех желающих сделать успешную карьеру в области интерфейсного веб-дизайна.
Метаданные Содержание  Глава 1: Начальные сведения о HTML5 и CSS3  Глава 2: Установка веб-сервера  Глава 3: Visual Studio Code  Глава 4: Консоль разработчика  Глава 5: Введение в HTML5  Глава 6: Использование холста в HTML5  Глава 7: Прямоугольники и заливки  Глава 8: Надписи на холсте  Глава 9: Рисование на холсте  Глава 10: Работа с холстом  Глава 11: Расширенные возможности работы с холстом  Глава 12: Применение геолокации  Глава 13: Работа с формами  Глава 14: Локальное хранилище и многое другое  Глава 15: Аудио и видео  Глава 16: Введение в CSS3  Глава 17: Селекторы атрибутов CSS3  Глава 18: Создание фона  Глава 19: Построение границ  Глава 20: Свойства блока и текста  Глава 21: Цвета и прозрачность  Глава 22: Текстовые эффекты и шрифты  Глава 23: Двумерные преобразования  Глава 24: Трехмерная графика и анимация  Глава 25: Макет Flexbox  Глава 26: CSS Grid  Глава 27: Знакомство с Sass  Глава 28: Переменные и потоки выполнения в Sass  Глава 29: Расширенный Sass | 461
462 | Метаданные КЛЮЧЕВЫЕ СЛОВА (7):  Веб-разработка  HTML и CSS  HTML5 и CSS3  Геолокация  Веб-аудио и видео  Холсты HTML5  2D и 3D CSS-преобразования КЛЮЧЕВЫЕ СЛОВА (15):  Веб-разработка  HTML и CSS  HTML5 и CSS3  Геолокация  Веб-аудио и видео  Холсты HTML5  2D и 3D CSS-преобразования  Веб-дизайн  Доступ к локальному хранилищу  Стилевые таблицы Sass  Flexbox-макет  CSS Grid  Текстовые эффекты CSS  Работа с фоном в CSS  Работа с формами в CSS Биография автора Робин Никсон — веб-разработчик и преподаватель, активно занимающийся программированием с 1980-х годов. Ранее он редактировал компьютерный журнал, был директором нескольких компаний-разработчиков программного обеспечения, а в последнее время стал автором ряда самых продаваемых книг о компьютерах и компьютерных технологиях. Области интересов Робина — фронтенд-разработка с использованием HTML, CSS и JavaScript, а также управление серверной частью с помощью PHP и MySQL. Он также активный исследователь в области искусственного интеллекта.
Метаданные СЛОГАНЫ И БРОСКИЕ ФРАЗЫ:  Станьте мастером веб-разработки.  Запустите на взлет свою карьеру веб-разработчика.  Здесь все, что нужно знать о современной веб-разработке.  Создавайте ошеломляющие веб-страницы и приложения.  Существенно расширьте перспективы своего заработка.  Станьте экспертом на ниве веб-дизайна.  Превратите свой веб-дизайн в выдающийся образец творчества. | 463