Как всегда, если уже существует реализация, спецификация будет опираться на нее, а не изобретать велосипед. В Internet Explorer уже несколько лет существует API для перетаскивания объектов, поэтому она и стала фундаментом для перетаскивания в HTML5. К сожалению, у API Microsoft – как бы помягче сказать – есть свои проблемы. Может быть, иногда не так уж плохо заново изобретать велосипед, если у тебя есть только велосипед с квадратными колесами.
API в HTML5 могут очень многое. И еще они полностью за гранью моего понимания. Я предоставлю возможность писать о них разработчикам, которые умнее меня. Эти API заслуживают своей собственной, отдельной книги.
В то же время в HTML5 есть еще очень много нового, что приведет нас, веб-разработчиков, в полный восторг. И этот восторг начинается прямо в следующей главе.
3. Мультимедиа
История веба пестрит технологическими нововведениями. Одним из самых ранних добавлений к HTML стал элемент img, и это фундаментально изменило веб. Затем появление JavaScript позволило вебу стать более динамической средой. Наконец, быстрый рост количества Ajax-приложений позволил вебу стать средой, в которой возможны полноценные приложения.
Веб-стандарты продвинулись настолько, что сейчас возможно разработать практически все что угодно с помощью HTML, CSS и JavaScript.
В разнообразном наборе веб-стандартов есть пробелы. Если вы хотите опубликовать текст и картинки, вам ничего не нужно, кроме HTML и CSS. Но если вы хотите опубликовать аудио и видео, вам понадобится технология, существующая в виде плагинов, – например, Flash или Silverlight.
«Плагин» (дословно «подключаемый модуль») – вполне точный термин для этого типа технологий: они помогают заткнуть дырки в вебе. С помощью плагинов относительно просто выложить онлайн-игры, фильмы и музыку. Но эти технологии не являются открытыми. Они не создаются сообществом разработчиков, а контролируются отдельными компаниями.
Flash – мощная технология, но когда используешь ее, иногда кажется, что ты заключил договор с дьяволом. Мы получили возможность публиковать мультимедиа в вебе, но при этом в какой-то степени потеряли независимость.
HTML5 заполняет эти пробелы. По сути, язык становится прямым конкурентом проприетарных технологий (таких, как Flash и Silverlight). Но вместо того чтобы быть зависимыми от плагинов, мультимедиа-элементы в HTML5 являются встроенными в браузеры.
Canvas
Когда браузер Mosaic добавил возможность встраивать на веб-страницы картинки, это дало вебу огромный импульс для развития. Но с тех пор картинки оставались статическими. Вы можете создать анимированные гифки. Можете обновлять стили картинки при помощи JavaScript. Можете генерировать картинку динамически на сервере. Но после того как браузер загрузил картинку, ее содержимое больше нельзя обновить.
Элемент canvas – среда для создания динамических картинок.
Сам по себе элемент очень прост. Все, что вам нужно определить в открывающем теге, – его размеры:
<canvas id="my-first-canvas" width="360" height="240">
</canvas>
Если вы напишете что-нибудь между открывающим и закрывающим тегом, то это будет отображено только в тех браузерах, которые не поддерживают работу с Canvas (рис. 3.01):
<canvas id="my-first-canvas" width="360" height="240">
<p>Браузер не поддерживает canvas? Тогда картинка,по-старинке:</p>
<img src="puppy.jpg" alt="очаровательный щенок">
</canvas>
Браузер не поддерживает canvas? Тогда картинка по старинке:
Рис. 3.01. Пользователи, браузеры которых не поддерживают canvas, увидят картинку очаровательного щенка
Вся сложная работа делается на JavaScript. Сначала вам нужно будет создать переменную, указывающую на Canvas и его контекст. Слово «контекст» в данном случае означает просто API. В настоящий момент контекст есть только один – двумерный:
var canvas = document.getElementById(‘my-first-canvas’);
var context = canvas.getContext(‘2d’);
Теперь вы можете начать рисовать на двумерной поверхности элемента canvas, используя API, задокументированное в спецификации HTML5 по адресу: http://bkaprt.com/html5/.[4]
В 2D API есть довольно большое количество тех же самых инструментов, которые есть в графическом редакторе (например, Adobe Illustrator), – обводка, заливка, градиент, тень, формы, кривые Безье. Разница в том, что вместо того чтобы использовать графический интерфейс, вам нужно писать все на JavaScript.
Танец вокруг архитектуры: как рисовать с помощью кода
Вот так вы определяете, что цвет обводки должен быть красным:
context.strokeStyle = ‘#990000’;
Теперь у всего, что вы нарисуете, будет красный контур. Например, если вы хотите нарисовать прямоугольник, используйте такой синтаксис:
strokeRect (left, top, width, height)
Если вы хотите нарисовать прямоугольник размерами 100×50 пикселей, расположенный в 20 пикселях от левого края и в 30 пикселях от верхнего края элемента canvas, вы напишете так (рис. 3.02):
context.strokeRect(20,30,100,50);
Это очень простой пример. 2D API предоставляет очень много методов: fillStyle, fillRect, lineWidth, shadowColor и многие другие.
Рис. 3.02. Прямоугольник, нарисованный на canvas
В теории любое изображение, которое можно реализовать в программе, аналогичной Illustrator, можно создать внутри элемента canvas. На практике делать это очень утомительно и, скорее всего, приведет к безумно длинному коду на JavaScript. Да и вообще смысл Canvas несколько не в этом.
Canvas. Ага! И для чего он нужен?
Создавать картинки на лету с использованием JavaScript и Canvas – это все здорово и прекрасно, но если вы не убежденный мазохист, то зачем?
Истинная сила Canvas заключается в том, что его содержимое может быть обновлено в любой момент, на нем можно нарисовать новое содержимое в зависимости от действий пользователя. Эта способность реагировать на события, вызванные действиями пользователя, делает возможным создавать инструменты и игры, для которых раньше потребовалась бы технология плагина, например Flash.
Одна из первых флагманских демонстраций возможностей Canvas была разработана в Mozilla Labs. Приложение Bespin (https://bespin.mozilla.com) – редактор кода, работающий внутри браузера (рис. 3.03).
Он очень мощный. Очень впечатляющий. Но это прекрасный пример того, чего с Canvas делать как раз совершенно не нужно.
Рис. 3.03. Приложение Bespin, разработанное на Canvas
Доступ запрещен
Редактор кода по своей природе имеет дело с текстом. Редактор Bespin работает с текстом внутри элемента canvas – вот только на самом деле это уже не текст; это набор фигур, которые выглядят как текст.
Каждый документ в вебе можно описать объектной моделью документа (Document Object Model, DOM). DOM может содержать большое количество различных узлов, самыми важными из которых являются узлы элементов, текстовые узлы и атрибуты. У элемента canvas нет DOM. Содержимое, нарисованное внутри canvas, нельзя представить как дерево узлов.
Программы, читающие с экрана, и другие технологии специальных возможностей разбирают документ благодаря тому, что имеют доступ к объектной модели документа. Нет DOM – доступа тоже нет.
Недоступность содержимого Canvas для технологий специальных возможностей – большая проблема для HTML5. К счастью, очень умные люди работают вместе в рамках рабочей группы, которая может предложить решение этой проблемы (http://bkaprt.com/html5/2)[5].
Доступ к Canvas – очень важный вопрос, и я не хотел бы, чтобы какие-либо внесенные предложения принимались поспешно. С другой стороны, мне не хотелось бы также, чтобы Canvas задерживал все остальное в спецификации HTML5.
Умный Canvas
Пока проблема с доступом технологий специальных возможностей не решена, может показаться, что Canvas – неактуальная технология для веб-разработчиков. Но это не на сто процентов верно.
Когда я использую на сайте JavaScript, я использую его не как основную функциональность, а как дополнение к уже имеющейся. Посетителям, у которых нет JavaScript, все равно будет доступно все содержимое, но оно будет вести себя несколько менее динамично, чем в среде с включенным JavaScript.
Этот многоуровневый подход, называющийся еще «ненавязчивый JavaScript», можно применить и к Canvas. Вместо того чтобы использовать Canvas для создания содержимого, используйте его, чтобы иначе отобразить существующее содержимое.
Предположим, у вас есть таблица с данными. Скажем, вы хотите проиллюстрировать аналитические выводы из этих данных в диаграмме. Если данные статичны, то вы можете сгенерировать картинку диаграммы – например, используя Google Chart API. Если же данные редактируемы, если они меняются в ответ на события, вызванные действиями пользователя, тогда Canvas – отличный инструмент для того, чтобы сгенерировать изменившуюся диаграмму. Ключевой момент здесь тот, что то содержимое, которое выводится внутри элемента canvas, уже доступно в существующем элементе table.
Умные парни из Filament Group разработали jQuery-плагин как раз для такой ситуации (рис. 3.04; http://bkaprt.com/html5/3)[6].
Рис. 3.04. Сгенерированная с помощью Canvas диаграмма из данных, введенных пользователями
Есть и другой вариант. Canvas – не единственная API для генерации динамических картинок. SVG (Scalable Vector Graphics, масштабируемая векторная графика) – XML-формат, в котором можно описать те же самые формы, что и в Canvas.
Поскольку XML – текстовый формат данных, содержимое SVG теоретически доступно программам, читающим текст на экране.
На практике SVG не захватило воображение разработчиков настолько, насколько это получилось у Canvas. Хотя Canvas – новый паренек в классе, у него уже отличная браузерная поддержка. Safari, Firefox, Opera и Chrome поддерживают Canvas. Есть даже JavaScript-библиотека, которая добавляет поддержку Canvas в Internet Explorer (http://bkaprt.com/html5/4)[7].
Учитывая мантры WHATWG – «асфальтируйте тропинки» и «не изобретайте велосипед», – может показаться странным, что при этом они выступают за включение Canvas в HTML5, когда уже существует стандарт SVG. Как часто и бывает, спецификация HTML5 только документирует то, что браузеры уже поддерживают. Элемент canvas не был задуман специально для HTML5; он был разработан Apple и реализован в Safari. Другие производители браузеров увидели, что делает Apple, им это понравилось, они это скопировали.
Звучит как-то несуразно, но зачастую именно так рождаются наши веб-стандарты. Например, в конце XX века Microsoft создала объект XMLHttpRequest для Internet Explorer 5.
Десятилетие спустя все браузеры поддерживают эту функцию, и в W3C она находится в статусе последней версии рабочего черновика.
В развивающемся по законам Дарвина мире веб-браузеров Canvas распространяется вширь и вдаль. Если он сможет приспособиться к технологиям специальных возможностей, выживание ему обеспечено.
Audio
Первым сайтом, который я сделал в жизни, был маленький сайт-визитка моей группы. Я хотел, чтобы посетители сайта могли слушать песни, которые исполняет моя группа. Так начался мой спуск в подземное царство огромного количества форматов и музыкальных проигрывателей. Многие из них боролись за мое внимание: QuickTime, Windows Media Player, Real Audio, – и я потратил слишком много времени, переживая из-за доли каждого на рынке и кросс-платформенной совместимости.
В последующие годы битву за повсеместное распространение выиграл формат MP3. Но для того чтобы простым способом дать послушать звуковой файл посетителю сайта, все еще нужна проприетарная технология. Эту битву выиграл проигрыватель Flash.
Теперь на ринг, чтобы сразиться с действующим чемпионом, входит HTML5.
Встроить аудиофайл в HTML5-документ очень просто:
<audio src="witchitalineman.mp3">
</audio>
Наверное, это даже слишком просто. Наверняка вы хотите несколько более конкретно указать, что должен делать элемент audio.
Предположим, что живет на свете злой урод, который ненавидит веб и всех пользователей Интернета. Этому господину наверняка плевать, что встраивать на страницу аудиофайл, который начинает проигрываться автоматически, невероятно грубо и глупо. С помощью атрибута autoplay можно удовлетворить его глубоко порочные желания.
<audio src="witchitalineman.mp3" autoplay>
</audio>
Если вы когда-нибудь будете так использовать атрибут autoplay, знайте: я вас найду.
Обратите внимание, что у атрибута autoplay нет значения. Такие атрибуты называются булевыми, в честь Джорджа Буля, великого математика из Корка[8].
Компьютерная логика целиком основана на булевой логике: электрический ток либо течет, либо нет; двоичное значение – либо единица, либо ноль; результат расчета – либо истина (true), либо ложь (false).
Не перепутайте булевы атрибуты и булевы значения. Вас можно понять, если вы подумаете, что булев атрибут будет принимать значения true и false. В действительности булево по природе само существование элемента: присутствует он или нет. Даже если напишете атрибуту значение, никакого эффекта это иметь не будет. Написать autoplay="false" или autoplay="no thanks" – то же самое, что написать autoplay.
Если вы используете синтаксис XHTML, можете написать autoplay="autoplay". Этот синтаксис используется в официальных документах Управления по управлению управлением избыточной информацией.
Если ставить аудиофайл на автоматическое проигрывание не кажется вам достаточно зловредным, вы можете принести еще больше скорби в этот мир, заставив аудиофайл бесконечно повторяться. Другой булев атрибут, loop, позволит вам совершить этот низкий поступок:
<audio src="witchitalineman.mp3" autoplay loop>
</audio>
Использование атрибута loop вместе с атрибутом autoplay заставит меня искать вас с удвоенной энергией.
Вырваться из-под контроля
Элемент audio можно использовать не только для злых, но и для благих целей. Дать пользователю контроль над управлением проигрывания аудиофайла – здравая идея, которую легко осуществить с помощью булева атрибута controls:
<audio src="witchitalineman.mp3" controls>
</audio>
Присутствие атрибута controls заставляет браузер отобразить встроенные элементы управления того, чтобы проигрывать аудиофайл и ставить его на паузу – и для того, чтобы настраивать громкость (рис. 3.05).
Рис. 3.05. Используйте атрибут controls, для того чтобы отобразить элементы управления «проиграть», «пауза» и управления громкостью
Если вам не нравятся встроенные в браузер элементы управления, можете создать свои собственные. С помощью JavaScript вы можете взаимодействовать с Audio API, которое дает вам доступ к методам (play и pause) и свойствам (volume и др.). Вот быстрый и простой пример, как использовать элементы button и ужасные обработчики событий, написанные прямо в коде страницы (рис. 3.06):
<audio id="player" src="witchitalineman.mp3">
</audio>
<div>
<buttononclick="document.getElementById(‘player’). play()">Проиграть
</button>
<buttononclick="document.getElementById(‘player’). pause()">Пауза
</button>
<buttononclick="document.getElementById(‘player’). volume+= 0.1">
Громче
</button>
<buttononclick="document.getElementById(‘player’). volume-= 0.1">
Тише
</button>
</div>
Рис. 3.06. Элементы управления (Проиграть, Пауза, Громче, Тише), сделанные с помощью элементов button
Буферизация
В какой-то момент спецификация HTML5 включала еще один булев атрибут для элемента audio. Атрибут autobuffer был более вежливым и продуманным вариантом неприятного атрибута autoplay. Он позволял авторам сообщить браузеру, что хотя аудиофайл и не нужно начинать проигрывать автоматически, скорее всего в какой-то момент пользователь начнет его проигрывать, поэтому браузеру стоит начать подгружать файл в фоновом режиме.
Это был бы полезный атрибут, но, к сожалению, Safari сделал лишний шаг вперед. Этот браузер начал подгружать аудиофайлы вне зависимости от того, присутствует атрибут autobuffer или нет. Не забывайте, что из-за того, что autobuffer – булева переменная, не было никакого способа сказать Safari, что подгружать аудиофайл не нужно: autobuffer="false" – то же самое, что autobuffer="true" или любое другое значение (http://bkaprt.com/html5/5)[9].
В данный момент атрибут autobuffer заменен атрибутом preload. Это не булев атрибут. Он принимает одно из трех возможных значений: none, auto и metadata. Написав preload="none", вы можете явным образом указать браузеру, что подгружать аудиофайл заранее не нужно:
<audio src="witchitalineman.mp3" controls preload="none">
</audio>
Если у вас на странице только один элемент audio, возможно, стоит использовать preload="auto", но чем больше элементов audio появляется, тем больше интернет-канал посетителей вашей странички будет загружен из-за излишней предварительной подгрузки.
Его вам сразу вклю́чат, а может быть, включáт
Элемент audio выглядит практически идеальным. Где-то должен быть подвох, правда? Он есть.
Проблемы с элементом audio не в спецификации. Главная проблема – с форматами аудиофайлов.
Хотя формат MP3 и распространен повсеместно, это не открытый формат. Из-за того, что на этот формат навешано множество патентов, нельзя написать декодер MP3, не заплатив отчислений по патенту. У корпораций вроде Apple или Adobe с этим нет проблем, но для маленьких компаний или опенсорс-групп это не так просто. Поэтому Safari будет с удовольствием проигрывать MP3-файлы, a Firefox – нет.