В HTML5 много интересного. Благодаря новым средствам CSS, разметке и JavaScript API возможности Web расширяются семимильными шагами. Добавьте к этому упорное стремление всех поставщиков браузеров добиться преимущества, из-за чего список потрясающих функций растет едва ли не ежедневно. В итоге браузеры меняются очень быстро, а веб-разработчики все так же несутся вперед с головокружительной скоростью.
Но сколько бы сообщества веб-разработчиков и поставщики браузеров ни нагоняли ажиотажа вокруг HTML5, подавляющее большинство людей в Web не пользуется новейшими браузерами. Если вы веб-разработчик в крупной «софтверной» компании или на предприятии с большой аудиторией пользователей, то, вероятно, и сами знаете это. Даже если вы работаете в небольшой компании или «стартапе» (начинающей фирме), которая предоставляет какой-то сервис через Web, вы наверняка тратите массу времени на то, чтобы добиться корректной работы своего сайта с максимально большим количеством браузеров и их версий.
Учитывая эти реалии, легко посмотреть на HTML5 под другим углом зрения — не с позиций его готовности к широкому использованию, а с позиций того, готовы ли вы сами к его применению. Например, вы создали страницу с какими-то новыми семантическими тегами (вроде <header> и <article>), добавили некие новые CSS-стили (скажем, скругление углов и тени) и даже включили элемент <canvas> для прорисовки логотипа HTML5 на этой странице.
В более новых браузерах наподобие Internet Explorer 9, Firefox 4 и выше или в Google Chrome все это будет визуализировано, как на рис. 1. Но если вы попытаетесь загрузить эту страницу в Internet Explorer 8 или ниже, то получите нечто вроде показанного на рис. 2: напрочь изуродованную страницу.
Рис. 1. Семантическая страница со стилями и HTML5-элементом <canvas>, отображаемая в Internet Explorer 9
Рис. 2. Та же страница, визуализированная в Internet Explorer 8 без стилей и элемента <canvas>
Я не стал бы вас винить, если бы вы, глядя на все это великолепие HTML5 и имея некоторый опыт, сказали, что лучше всего будет просто подождать. Независимо от того, готов HTML5 к широкому внедрению или нет, очень легко прийти к заключению, что он не совсем готов для вас или ваших пользователей.
Прежде чем вы решите еще раз взглянуть на HTML5 году эдак в 2022-м, прошу вас только об одном: прочитайте эту статью до конца. Моя цель — дать вам практические стратегии того, как можно начать внедрение технологий HTML5 уже сейчас, не попав впросак, как на странице, продемонстрированной на рис. 2. В этой статье мы рассмотрим:
- сравнение распознавания возможностей браузеров и анализа с помощью пользовательского агента [user agent (UA) sniffing];
- поли-заполнение средствами JavaScript;
- корректное сокращение функциональности (graceful degradation).
Это даст вам достаточное понимание того, как создавать веб-сайты для широкого круга браузеров. К тому моменту, когда мы закончим, вы получите четкую стратегию внедрения технологий HTML5. У вас также появятся некоторые инструменты, с помощью которых вы сможете постепенно расширять свои сайты для более новых браузеров и в то же время корректно сокращать функциональность для остальных.
Важность распознавания возможностей браузеров
Чтобы обеспечить стабильную и согласованную работу сайта с разными браузерами, разработчикам часто требуется получать информацию о браузере пользователя. Исторически сложилось так, что наиболее популярным способом определения этой информации стал такой вариант на основе JavaScript:
var userAgent = navigator.userAgent;
if (userAgent.indexOf('MSIE') >= 0) {
console.log("Hello, IE user");
} else if (userAgent.indexOf('Firefox') >= 0) {
console.log("Hello, Firefox user");
} else if (userAgent.indexOf('Chrome') >= 0) {
console.log("Hello, Chrome user");
}
Эта методика, известная как анализ с помощью пользовательского агента (UA sniffing) (далее для краткости UA-анализ), широко применяется для определения браузера, запрашивающего страницу. Идея состоит в том, что, зная браузер пользователя (например, Internet Explorer 7), вы можете принимать решения в период выполнения насчет того, какие функции вашего сайта следует включить, а какие — отключить. UA-анализ сводится, по сути, к тому, что вы спрашиваете браузер: «Кто ты?». (Подробное рассмотрение UA-анализа и других методик распознавания см. по ссылке bit.ly/mlgHHY.)
Проблема с этим подходом в том, что браузеры можно заставить лгать. UA-строка — блок информации, который может изменяться пользователем, а потому не дает 100%-ной точности распознавания браузера. Более того, после широкого распространения этой методики многие поставщики браузеров добавили дополнительный контент в свои UA-строки, приводящий соответствующие скрипты к неверным предположениям об используемом браузере и тем самым делающий бесполезной такую методику распознавания. В некоторые браузеры теперь даже включают механизм, который дает возможность пользователям несколькими щелчками мыши изменять свои UA-строки.
Однако истинной целью UA-анализа никогда не было стремление определить браузер пользователя и его версию только для того, чтобы сообщить пользователю «пойти и скачать другой браузер», если его браузер кому-то не нравился (увы, некоторые так и применяли UA-анализ). Пользователи имеют право выбирать любой браузер, и наша ответственность как разработчиков — обеспечить им максимально надежную и комфортную работу, а не навязывать свое мнение о предпочтительности какого-либо браузера. Смысл UA-анализа сводится к получению точной картины о возможностях или функциях, которые можно задействовать в данном браузере. Знание самого браузера — не более чем способ получить эту информацию.
Сегодня есть альтернативы UA-анализу, и одна из них набирает все большую популярность (отчасти благодаря jQuery и Modernizr): распознавание объектов (object detection), или возможностей (feature detection). Эти термины по большей части взаимозаменяемы, но в этой статье я буду использовать «распознавание возможностей».
Цель распознавания возможностей — определить, поддерживается ли данная функция или возможность браузером данного пользователя. Если UA-анализ, по сути, спрашивает у браузера «кто ты?», то распознавание возможностей аналогично вопросу «на что ты способен?». Это куда более надежный способ предоставления условной функциональности для пользователей. Пользователям и браузерам гораздо труднее намеренно или ошибочно исказить отчет о поддержке функций — при условии, что скрипты распознавания возможностей написаны корректно.
Распознавание возможностей вручную
Итак, что же представляет собой распознавание возможностей — в противоположность примеру с UA-анализом? Чтобы ответить на этот вопрос, сначала посмотрим, как исправить проблемы, возникшие при просмотре моей HTML5-страницы в Internet Explorer 8 вместо Internet Explorer 9. Разметка этой страницы приведена на рис. 3.
Рис. 3. Страница с новой семантической разметкой HTML5
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>My Awesome Site</title>
<style>
body { font-size: 16px; font-family:
arial,helvetica,clean,sans-serif; }
header h1 { font-size: 36px; margin-bottom: 25px; }
article
{
background: lightblue;
margin-bottom: 10px;
padding: 5px;
border-radius: 10px;
box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.5);
}
article h1 { font-size: 12px; }
</style>
</head>
<body>
<header><h1>My Awesome Site</h1></header>
<article>
<header><h1>An Article</h1></header>
<p>Isn't this awesome?</p>
</article>
<canvas width="250" height="500"></canvas>
</body>
<script src="../js/html5CanvasLogo.js"
type="text/javascript"></script>
</html>
Различия между Internet Explorer 9 и Internet Explorer 8, как иллюстрируют рис. 1 и 2, просто драматические. Создается впечатление, что на моей странице нет никаких стилей — будто CSS для этой страницы отсутствует. Более того, я потерял замысловатый щит с надписью «HTML5» внизу страницы. Каждую из этих проблем можно легко устранить, и распознавание возможностей — первый шаг в этой задаче.
Причина обеих проблем проста: <header>, <article> и <canvas> не являются допустимыми HTML-элементами для Internet Explorer 8, и из-за этого я не могу работать с ними. Чтобы решить проблему <canvas>, вместо UA-анализа для определения того, какой браузер и какой версии используется, следует запросить браузер через JavaScript, поддерживает ли он элемент <canvas> его JavaScript API. Проверка поддержки <canvas> выглядит так:
!!document.createElement('canvas').getContext
Это выражение делает несколько вещей. Во-первых, в нем используется двойное отрицание (!!), чтобы принудительно заменять на false неопределенные значения. Затем в нем создается новый элемент canvas, который подключается к DOM. Наконец, оно вызывает getContext — новую функцию, доступную элементам canvas и позволяющую работать с Canvas API через JavaScript. Если я использую Internet Explorer 9, это выражение возвращает true. В случае Internet Explorer 8 функция getContext вернет undefined, которое за счет двойного отрицания станет false.
Это самое базовое применение распознавания возможностей. С помощью такого и ему подобных выражений у меня теперь есть более надежный способ запрашивать браузер о поддержке той или иной функциональности. Подробнее о распознавании возможностей вручную см. по ссылке diveintohtml5.info/everything.html.
Применение Modernizr для распознавания возможностей
Распознавание возможностей вручную — способ, безусловно, более эффективный, чем UA-анализ, но этот подход все равно оставляет на вас бремя определения доступности конкретной возможности и принятия решения о том, что делать, если такая возможность отсутствует. И хотя пример с canvas был простым и потребовал всего одной строки кода, это отнюдь не так в других случаях; кроме того, код распознавания не для всех браузеров одинаков. Например, определение поддержки модулей CSS3, которые я использовал ранее (скругленные углы и тени), может оказаться потруднее.
К счастью, Modernizr (modernizr.com) ) предлагает подход получше. Modernizr — это библиотека JavaScript, которая «…определяет наличие реализаций веб-технологий следующего поколения, например функциональности, вытекающей из спецификаций HTML5 и CSS3». Добавление ссылки на Modernizr в ваши страницы предоставляет четыре основных средства.
- Внушительный список поддерживаемых функций, добавляемых в вашу разметку и позволяющих использовать условные CSS-определения.
- JavaScript-объект, помогающий в распознавании возможностей на основе скриптов.
- Все новые HTML5-теги, добавляемые в DOM в период выполнения. Благодаря этому ими могут пользоваться Internet Explorer 8 и более ранние версии (подробнее об этом чуть позже).
- Загрузчик скриптов для условной загрузки поли-заполнений в ваши страницы.
Первый пункт мы больше не будем обсуждать в этой статье, но я советую отправиться на сайт modernizr.com и посмотреть на нем документацию и другие функции.
Второй пункт — функциональность, позволяющая превратить эту строку кода:
!!document.createElement('canvas').getContext
в такую:
Modernizr.canvas
Она возвращает булево значение, указывающее, поддерживается ли элемент canvas в этой странице. Самое замечательное в том, что Modernizr — тщательно протестированная, отказоустойчивая и широко применяемая библиотека, которую берет на себя всю тяжелую работу. Twitter, Google, Microsoft и множество других компаний используют Modernizr, так что смело используйте ее и вы. В пакете ASP.NET MVC 3 Tools Update (выпущенном в апреле 2011 г.) Microsoft даже поставляет Modernizr в комплекте с новыми приложениями ASP.NET MVC.
Конечно, к этому моменту я лишь определил, поддерживается ли <canvas>. И ничего не сказал, а что делать дальше. Так вот, на следующем этапе, зная, доступна ли браузеру некая функция, обычно создают условную логику, которая в отсутствие той или иной функции либо запрещает выполнение определенного кода, либо направляет выполнение по альтернативному пути, например:
if (Modernizr.canvas) {
// Здесь выполняем код, относящийся к элементу canvas
}
Расширение функциональности вашего сайта в зависимости от поддержки браузером дополнительных возможностей называют прогрессивным улучшением (progressive enhancement), так как вы улучшаете внешний вид сайт и удобство его использования для браузеров с более широкими возможностями. На другом конце спектра — корректное сокращение функциональности (graceful degradation), когда отсутствие некоей функции в браузере не приводит к ошибке или сбою, а просто ограничивает какую-либо функциональность сайта или вызывает ее замену на альтернативную. Для более старых браузеров корректное сокращение функциональности не обязательно должно быть вариантом по умолчанию. Во многих случаях это даже не лучший вариант. Вместо этого с помощью Modernizr зачастую можно использовать одно из многих поли-заполнений для браузера, чтобы добавить HTML5-подобные средства в браузеры, которые не поддерживают технологии HTML5.
Что такое поли-заполнение?
Согласно веб-сайту Modernizr, поли-заполнение (polyfill) — это «прослойка JavaScript, которая реплицирует стандартный API для юолее старых браузеров». Под «стандартным API» подразумевается конкретная технология или средство HTML5 вроде холста (canvas). «Прослойка JavaScript» означает, что вы можете динамически загружать JavaScript-код или библиотеки, которые имитируют эти API, в браузерах, их не поддерживающих. Например, поли-заполнение Geolocation добавляет глобальный объект geolocation в объект navigator, а также функцию getCurrentPosition и «связующий» объект обратного вызова (callback object) — все, как определено в Geolocation API консорциумом World Wide Web Consortium (W3C). Поскольку поли-заполнение имитирует некий стандартный API, вы можете вести разработку, используя этот API с заделом на будущее для всех браузеров; при этом вы сможете удалить данное поли-заполнение, как только поддержка соответствующего API наберет критическую массу. Никакой дополнительной работы не потребуется.
Добавив ссылку на Modernizr в свою страницу, я сразу же получаю преимущества поли-заполнения, относящиеся к примеру на рис. 3. Страница визуализировалась без стилей из-за того, что Internet Explorer 8 не распознает теги вроде <article> и <header>. А раз не распознает, то и не добавляет в DOM, через которую CSS выбирает элементы для применения стилей.
После добавления тега <script> и ссылки на Modernizr к странице применяются стили, как на рис. 4. Все это благодаря тому, что Modernizr самостоятельно добавляет все новые HTML5-теги в DOM, используя JavaScript (document.CreateElement(‘nav’)), что позволяет CSS выбирать теги и применять к ним стили.
Рис. 4. HTML5-страница в Internet Explorer 8 при использовании Modernizr
Помимо добавления поддержки новых HTML5-элементов в Internet Explorer, библиотека Modernizr не предоставляет никаких дополнительных поли-заполнений в готовом виде. Это уже ваша задача: вы либо пишете собственные скрипты, либо пользуетесь постоянно растущим списком компонентов, документированных на сайте Modernizr. В версии 2.0 библиотека Modernizr предоставляет условный загрузчик скриптов (основанный на yepnope.js — см. сайт yepnopejs.com), который позволяет асинхронно подгружать библиотеки поли-заполнений только по мере необходимости. Очень эффективный вариант — применение Modernizr в сочетании с одной или несколькими библиотеками поли-заполнений, обеспечивающими нужную вам функциональность.
Моделирование функциональности HTML5 с помощью поли-заполнений
В случае canvas вы можете обеспечить поли-заполнение соответствующей поддержки для Internet Explorer 8 и более ранних версий с помощью Modernizr и JavaScript-библиотеки excanvas, которая добавляет поддержку canvas на уровне API в Internet Explorer версий 6, 7 и 8. Эту библиотеку можно скачать по ссылке bit.ly/bSgyNR и после ее добавления в вашу папку скриптов вы можете добавлять какой-либо код в блок script в своей странице, как показано на рис. 5.
Рис. 5. Применение Modernizr для поли-заполнения поддержки canvas
Modernizr.load({
test: Modernizr.canvas,
nope: '../js/excanvas.js',
complete: function () {
Modernizr.load('../js/html5CanvasLogo.js');
}
}]);
Здесь я использую загрузчик скриптов Modernizr, чтобы указать:
- булево выражение для проверки;
- путь к скриптам, которые нужно загрузить, если результат оценки выражения равен false;
- обратный вызов, запускаемый после проверки или по окончании загрузки скрипта.
В контексте canvas это все, что нужно для добавления некоторой интеллектуальности и поли-заполнения в мое приложение. Modernizr будет асинхронно загружать excanvas.js только для браузеров, которые не поддерживают canvas, а затем будет загружать мою библиотеку скриптов для прорисовки эмблемы HTML5 на странице.
Рассмотрим еще один пример, подчеркивающий ценность Modernizr. Дотошные читатели, вероятно, заметили, что страница, оформленная стилями на рис. 4, не идентична оригинальной, которая визуализируется в Internet Explorer 9 и показана на рис. 1. На этой странице в Internet Explorer 8 отсутствуют скругленные углы и тени, так что я вновь призову на помощь Modernizr.
Как и в случае canvas, Modernizr может сообщить мне, что модули CSS3 не поддерживаются, но позаботиться о библиотеке для поли-заполнения должен я сам. К счастью, есть PIE (css3pie.com), которая предоставляет оба модуля в одной библиотеке.
Чтобы добавить поддержку скругленных углов и теней, в скрипт можно добавить код с рис. 6 после скачивания PIE. На этот раз я буду проверять, поддерживается ли каждый из модулей (в противоположность тому, чтобы предполагать, что они оба либо поддерживаются, либо нет), и, если любой из них не поддерживается, динамически загружать PIE.js. Как только загрузка PIE завершается, я выполняю блок jQuery, чтобы выбрать все свои теги <article> и вызвать для них функцию PIE.attach, которая добавляет поддержку стилей скругленных углов и теней, уже определенных в моей CSS. Результат показан на рис. 7.
Рис. 6. Применение Modernizr и PIE для добавления поддержки CSS3
Modernizr.load({
test: Modernizr.borderradius || Modernizr.boxshadow,
nope: '../js/PIE.js',
callback: function () {
$('article').each(function () {
PIE.attach(this);
});
}
});
Рис. 7. Поддержка CSS3, добавленная с помощью Modernizr и PIE
Использование поли-заполнений для корректного сокращения функциональности
Помимо использования уже рассмотренных методик поли-заполнения, Modernizr может помочь и в тех случаях, где требуется корректное сокращение функциональности вашего приложения в противоположность поли-заполнению с помощью другой библиотеки.
Допустим, на моей веб-странице есть элемент управления Bing Maps, и я хочу задействовать Geolocation (подробно о Geolocation мы поговорим в следующей статье), чтобы находить текущее местоположение пользователя, а затем показывать его на карте.
Хотя Geolocation поддерживается в новых версиях всех браузеров, в более старых версиях такой поддержки нет. Кроме того, обеспечить полную поддержку Geolocation API исключительно средствами JavaScript значительно труднее, поэтому, хотя поли-заполнения для Geolocation существуют, я решил реализовать корректное сокращение функциональности своего приложения. В тех случаях, когда браузер не поддерживает Geolocation, я предоставляю форму, в которой пользователь может сам указать свой адрес; после этого я отображаю его позицию на карте и отмечаю это место.
При использовании Modernizr достаточно загружать один из двух скриптов, созданных мной (рис. 8). В данном случае я проверяю свойство Modernizr.geolocation. Если оно равно true (yep), я загружаю скрипт fullGeolocation.js, который будет использовать Geolocation API для определения моего местонахождения (с моего разрешения) и показывать его на карте (рис. 9). С другой стороны, если проверка даст false (nope), я загружу базовый скрипт, который отображает на странице форму для ввода адреса. Когда пользователь отправляет форму, я использую предоставленный адрес для центрирования карты и помечаю его, как на рис. 10. Благодаря этому моя страница позволяет современным браузерам использовать полную функциональность, в то же время предоставляя базовую функциональность более старым браузерам.
Рис. 8. Корректное сокращение функциональности с помощью Modernizr
Modernizr.load({
test: Modernizr.geolocation,
yep: '../js/fullGeolocation.js',
nope: '../js/geolocationFallback.js'
});
Рис. 9. Работа с картами с использованием Geolocation
Рис. 10. Поддержка базового Geolocation
Глядя на некоторые продвинутые средства HTML5 и учитывая большую пользовательскую базу более старых браузеров, можно легко решить, что ваш сайт пока не готов к их внедрению. Однако уже есть много решений, которые не только помогают в корректном сокращении функциональности, но и позволяют выводить старые браузеры на современный уровень. На протяжении этой статьи вы видели с помощью распознавания возможностей браузеров, Modernizr и поли-заполнения HTML5 можно внедрять уже сейчас, не дожидаясь появления критической массы пользователей с современными браузерами, и в то же время не забывать об остальных пользователях.