Статьи

HTML5 сейчас: больше узнать о полифиллах

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

Но хотя некоторые функции законно не готовы к использованию в производстве, многие из новых API в HTML5 достаточно укрепились, чтобы на них можно было полагаться в новых браузерах, таких как Chrome, Firefox 4 и Internet Explorer 9. Фактически, даже Internet Explorer 6 включает поддержку одна из «новых» функций HTML5 — contentEditable . Что еще более важно, многие из новых функций в HTML5 достаточно убедительны, поэтому ждать еще десять лет, чтобы начать их использовать, не имеет смысла.

Кросс-браузерная поддержка

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

Полифиллинг — это термин, придуманный Реми Шарпом для описания подхода к обратной засыпке отсутствующей функциональности, который дублирует отсутствующий API. Использование этого метода позволяет вам писать код для конкретного приложения, не беспокоясь о том, реализует ли браузер каждого пользователя его изначально. На самом деле, полифиллы не являются новой техникой или привязаны к HTML5. Мы годами использовали полифилы, такие как json2.js, ie7-js, и различные запасные варианты для обеспечения прозрачной поддержки PNG в Internet Explorer. Разница заключается в распространении полифилов HTML5 в прошлом году.

Что делает Polyfill?

Для конкретного примера того, о чем я говорю, взгляните на json2.js. В частности, вот первая строка кода в его реализации JSON.parse :

 if (typeof JSON.parse !== 'function') { // Crockford's JavaScript implementation of JSON.parse } 

Защищая код с помощью теста typeof , если браузер имеет встроенную реализацию JSON.parse , json2.js не пытается вмешиваться или переопределять его. Если нативный API недоступен, json2.js реализует JavaScript-версию JSON.parse таким образом, чтобы он был полностью совместим с нативным JSON API JavaScript. В конечном итоге это означает, что вы можете включить json2.js на страницу и быть уверенным в использовании JSON.parse не обращая внимания на то, в каком браузере работает ваш код.

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

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

Одна из новых функций в HTML5, которую проще всего заполнить, — это набор семантических элементов, которые были добавлены, такие как <article> , <aside> , <header > и <time> . Большинство из этих элементов отображаются именно так, как это делают почтенные <div> и <span> , но они придают более конкретный смысл.

Поскольку эти элементы являются действительными SGML, хорошей новостью является то, что даже старые браузеры, такие как Internet Explorer 6, будут отображать их сегодня. Однако одна из странностей Internet Explorer заключается в том, что он применяет стилизацию CSS только к элементам, которые он распознает. Таким образом, хотя старые версии Internet Explorer отображают содержимое новых семантических элементов HTML5, при этом они игнорируют любые пользовательские стили.

К счастью, Sjoerd Visscher обнаружил легкий обходной путь для Internet Explorer, и его подход стал популярен у Джона Резига . Выполнение вызова document.createElement() с любым произвольным типом элемента, указанным в качестве аргумента, заставляет Internet Explorer распознавать элементы этого типа и правильно применять к ним стили CSS, как и ожидалось.

Например, добавление одиночного вызова document.createElement('article') в <head> документа, показанного ниже, укрощает Internet Explorer и заставляет его применять стили CSS к элементу <article> .

 <html> <head> <title>HTML5 Now?</title> <style> article { margin: 0 auto; width: 960px; } </style> <script> document.createElement('article'); </script> </head> <body> <article> <!-- TODO: Write article… --> </article> </body> </html> 

Этот вызов document.createElement меняет то, как Internet Explorer применяет стили CSS.

Конечно, никто не хочет вручную добавлять операторы createElement для каждого из множества новых семантических элементов, добавленных в HTML5. Абстрагирование от этой скуки — это именно то место, где сияет полифилл. В этом случае существует полифил с именем html5shim (также известный как html5shiv), который автоматизирует процесс инициализации совместимости Internet Explorer с новыми семантическими элементами.

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

 <html> <head> <title>HTML5 Now!</title> <style> article { margin: 0 auto; width: 960px; } </style> <!--[if lt IE 9]> <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> </head> <body> <article> <!-- TODO: Write article… --> </article> </body> </html> 

Использование html5shim polyfill

Обратите внимание на условный комментарий, окружающий ссылку на скрипт на html5shim. Это гарантирует, что полизаполнение будет загружено и выполнено только в версиях Internet Explorer более ранних, чем версия 9. Не тратится время на загрузку, анализ и выполнение этого кода в браузерах, которые уже обеспечивают надлежащую поддержку новых элементов.

Еще одна альтернатива для рассмотрения

Если вы достаточно заинтересованы в HTML5, чтобы читать эту статью, вы, вероятно, уже знаете или используете Modernizr. Однако одна вещь, о которой вы можете не знать, это то, что Modernizr имеет встроенную функциональность html5shim createElement . Если вы используете Modernizr для обнаружения объектов, у вас уже есть обратная совместимость для семантических элементов HTML5.

Постоянное клиентское хранилище

В течение многих лет у нас не было другого выбора, кроме как собирать вместе комбинации расширений DOM для конкретных поставщиков и собственных плагинов, чтобы решить проблему сохранения долгосрочного состояния в браузере. Эти решения включали globalStorage Firefox, пользовательские globalStorage Internet Explorer, файлы cookie и плагины, такие как Flash или Google Gears. Несмотря на жизнеспособность, эти взломанные обходные пути утомительны, сложны в обслуживании и подвержены ошибкам.

Чтобы исправить это, одно из самых приятных дополнений в HTML5 — это основанный на стандартах API для постоянного хранения данных в браузере: localStorage . Этот API хранилища обеспечивает согласованное хранилище ключей и значений клиент-сервер, которое может хранить до 5 МБ изолированных данных для каждого веб-сайта, который посещает пользователь. Вы можете думать о localStorage как о массивном cookie- localStorage с которым проще работать и который не нужно бесполезно передавать назад и вперед между браузером и сервером при каждом HTTP-запросе. Функция localStorage идеально подходит для задач, которые требуют специфических для браузера данных, таких как запоминание предпочтений и локальное кэширование удаленных данных.

Функция localStorage уже поддерживается во всех браузерах класса A, включая Internet Explorer 8, но отсутствует в более старых версиях большинства браузеров. Между тем, появилось несколько решений для того, чтобы заполнить кросс-браузерное хранилище в этих старых браузерах. Они варьируются от простоты многофиллера хранения Remy Sharp до всесторонней обратной совместимости, обеспечиваемой store.js и PersistJS , до полнофункционального API LawnChair и модуля хранения AmplifyJS .

Например, вот как вы можете использовать модуль хранения AmplifyJS для сохранения некоторых данных в браузере пользователя без обращения к cookie-файлам, даже если этот пользователь использовал Internet Explorer 6:

 

Вытащить эти данные на более поздний срок становится чрезвычайно легко:

 // The values we stored before could then be used at a later time, even // during a different session. var $personLink = $('<a>', { text: amplify.store('name'), href: amplify.store('website').url }); $personLink.appendTo('body'); 

Опять же, localStorage особенностью использования localStorage или API на основе localStorage является то, что эти данные не нужно сохранять в cookie- localStorage а затем передавать вместе с каждым HTTP-запросом, а также не требует, чтобы вы вызывали тяжелый плагин, такой как Flash. просто чтобы сохранить немного данных. Данные хранятся в реальном изолированном локальном механизме хранения, что делает его отличным для локального кэширования данных или разработки сайтов, которые имеют широкую поддержку автономного использования.

Что использовать?

Полифиллер хранилища Реми Шарпа — единственный, который действительно квалифицируется как полифилл, потому что другие не совсем имитируют HTML5 localStorage API. Однако store.js и модуль хранения AmplifyJS обеспечивают поддержку более широкого диапазона резервных подходов для достижения совместимости в старых браузерах. Прагматично, это трудно игнорировать.

геолокации

Geolocation — это еще одна особенность HTML5, готовая к заполнению. Если и браузер, и операционная система поддерживают geolocation и работают на устройстве с датчиком GPS, HTML5 предоставляет доступ к API geolocation который позволяет коду JavaScript определять, откуда осуществляется доступ к вашей странице.

Мобильные устройства являются наиболее впечатляющим примером geolocation основе браузера. Соединяя встроенное оборудование GPS с современными браузерами, которые поддерживают API geolocation HTML5, устройства Android и iOS поддерживают geolocation HTML5 с такой же точностью, как и их собственные приложения.

JavaScript, необходимый для доступа к данным geolocation в этих оптимальных средах, очень прост:

 navigator.geolocation.getCurrentPosition(function(position) { var lat = position.coords.latitude; var long = position.coords.longitude; console.log('Current location: ', lat, log); }); 

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

В JavaScript текущий обходной путь заключается в поиске IP-адреса посетителя в базе данных известных IP-адресов. Этот подход страдает от значительно более низкой точности, чем при использовании устройства GPS, но эти базы данных, как правило, способны определять IP-адрес в правильной региональной области, что достаточно для многих приложений.

Возможно, вам известны методы более точной геолокации без GPS, которые не основаны исключительно на поиске IP-адресов. Чаще всего эти расширенные оценки выполняются с помощью нового подхода сравнения видимых идентификаторов точек доступа Wi-Fi с базой данных о том, где эти конкретные комбинации точек доступа были физически расположены в прошлом.

К сожалению, код JavaScript, работающий в браузере, в настоящее время не относится к этим данным из операционной системы. Таким образом, технология Wi-Fi недоступна для полифилов в обозримом будущем, поэтому в качестве единственной альтернативы мы ищем IP-адреса.

Пол Айриш (Paul Irish) написал простой геолокационный полифильтр, который обеспечивает некоторый уровень geolocation в старых браузерах и на оборудовании, где отсутствует датчик GPS. Это достигается с помощью API geolocation Google, чтобы преобразовать IP-адрес посетителя в приблизительное физическое местоположение. Это настоящий polyfill в том смысле, что он включает свои функции geolocation в объект navigator.geolocation , но только если браузер изначально не предоставляет API geolocation .

История браузера и навигация

Поскольку поверхностные эффекты DHTML уступают место более структурным функциям на стороне клиента, таким как пейджинговые интерфейсы на основе AJAX и одностраничные интерфейсы, эти структурные изменения начинают не синхронизироваться со встроенными в браузер функциями навигации и истории. Затем, когда пользователи интуитивно пытаются использовать кнопку «Назад» для перехода на предыдущую страницу или в состояние приложения, дела идут плохо. Поиск по «отключить кнопку назад» показывает, насколько эта проблема мешает современной веб-разработке.

Управление «хэш» частью местоположения браузера помогает решить одну сторону проблемы. Поскольку хэш изначально предназначался для перехода между точками навигации на одной и той же странице, изменение хеша URL-адреса не вызывает обновления страницы, как это делают изменения в базовом префиксе URL-адреса. Использование этого свойства хэша позволяет обновлениям на стороне клиента синхронизировать отображаемый адрес браузера с изменениями на основе JavaScript, которые происходят без традиционных навигационных событий.

Событие onhashchange

Хотя манипулирование хешем браузера хорошо поддерживается и выходит далеко за пределы даже Internet Explorer 6, до недавнего времени стандартизированный метод мониторинга изменений в хэше был более неуловимым. Текущая версия браузеров поддерживает событие onhashchange , которое запускается при изменении хеш-части адреса, что идеально подходит для обнаружения случаев, когда пользователь пытается перемещаться по изменениям состояния на стороне клиента, используя элементы навигации браузера. К сожалению, событие onhashchange реализовано только в относительно новых браузерах с поддержкой, начиная с Internet Explorer 8 и версии Firefox 3.6.

Хотя событие onhashchange недоступно в старых браузерах, в старых браузерах есть библиотеки, обеспечивающие уровень абстракции. Эти прокладки совместимости используют специфичные для браузера особенности для репликации стандартного события onhashchange , даже прибегая к мониторингу location.hash несколько раз в секунду и реагируя на изменения в браузерах без использования альтернативных методов. Одним из надежных решений в этом направлении является плагин jQuery Hashchange Бена Алмана , который он извлек из своего популярного плагина jQuery BBQ. JQuery Hashchange от hashchange событие hashchange с удивительно глубокой кросс-браузерной совместимостью. Я не решаюсь назвать это полифилом, потому что он требует jQuery и точно не дублирует нативный API, но он прекрасно работает, если вы уже используете jQuery на своих страницах.

За пределами HashState

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

Еще более фундаментальная проблема заключается в том, что браузеры не включают хеш-часть запрошенных URL-адресов в HTTP-запросы. Без доступа к этой части URL невозможно сразу же вернуть страницу, находящуюся в том же состоянии, что и страница, которую пользователь добавил в закладки, получил по электронной почте или обнаружил в социальной сети. Это приводит к тому, что у сайтов нет альтернативы, кроме как отображать страницы в их исходном состоянии по умолчанию, а затем автоматически вызывать резкий переход в состояние, которое пользователь фактически желает. Чтобы найти свидетельство влияния, которое это оказывает на удобство использования, вам нужно взглянуть не дальше, чем на широко распространенную негативную реакцию на Twitter и редизайн Gawker Media «хэш-бэнг».

Введите pushState

К счастью, HTML5 также представил пару более продвинутых API, которые значительно улучшают ситуацию с управлением историей на стороне клиента. Часто называемый просто pushState , комбинация метода window.history.pushState и события window.onpopstate предоставляет возможность асинхронно манипулировать всей частью пути адреса браузера и аналогично реагировать на события навигации вне хеша.

Просмотр исходного кода проекта на GitHub — один из лучших примеров реального использования pushState прямо сейчас. Поскольку манипулирование адресом браузера с помощью pushState не вызывает полного обновления страницы, как при традиционных изменениях адреса, GitHub может обеспечить анимированные переходы между каждой «страницей» кода, сохраняя при этом удобные для пользователя URL-адреса, которые не обрабатываются хэши или строки запросов.

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

Использование onhashchange и pushState в вашем собственном коде

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

Бенджамин Луптон собрал отличную кросс-браузерную библиотеку, чтобы сгладить широкий спектр особенностей и несоответствий, которые сопровождают ведение истории на стороне клиента. Его библиотека охватывает браузеры от Internet Explorer 6 до последней версии Chrome. Использовать библиотеку просто. У этого есть синтаксис, который близко следует за собственным синтаксисом pushState HTML5:

 // This changes the URL to /state1 in HTML5 browsers, and changes it to // /#/state1 in older browsers. History.pushState(null, 'State 1', 'state1'); // Same as before, but /state2 and /#/state2. History.pushState(null, 'State 2', 'state2'); 

Вместо предоставления точной копии события popstate HTML5, history.js включает в себя различные адаптеры для работы с системами обработки событий в этих библиотеках. Например, используя адаптер jQuery, вы можете связать обработчик события с событием history.js statechange следующим образом:

 History.Adapter.bind(window, 'statechange', function() { // Get the new history state from history.js. var state = History.getState(); // Write the URL we've navigated to on the console. console.log(state.url); }); 

Этот обработчик событий statechange запускается каждый раз, когда браузер перемещается по историческим точкам, которые были сохранены с помощью метода pushState history.js. В HTML5-браузере, который поддерживает pushState изначально, или в более старом браузере, который поддерживает только изменения URL-адресов на основе хэша, отслеживание этого отдельного события перехватывает любую активность.

Использовать это в реальных приложениях очень просто. Вероятно, вы можете себе представить его в сочетании с пейджингом и сортировкой по сетке на основе AJAX или даже для навигации по всему сайту (например, Gmail или Twitter), не прибегая к этим универсально ненавистным URL-адресам и перенаправлениям.

Бег с ножницами

При использовании pushState нужно следить за pushState , чтобы ваш сервер правильно реагировал на каждый URL, который вы используете на стороне клиента. Поскольку легко создать URL-адрес на стороне клиента, на который сервер будет реагировать с ошибкой 404 или 500 (например, /undefined ), рекомендуется убедиться, что маршрутизация на стороне сервера или перезапись URL-адреса настроена на обрабатывать неожиданные URL-адреса как можно изящнее. Например, если у вас есть многостраничный отчет в /report , с pushState -driven URL-адресами /report/2 , /report/3 и т. Д. Для каждой страницы, вы должны убедиться, что ваш серверный код корректно отвечает на запросы на URL-адреса, такие как /report/undefined .

Менее желательной альтернативой является использование фрагментов URL pushState querystring в pushState адреса pushState , например /report?page=2 и /report?page=3 . Результирующие URL выглядят не так хорошо, но они, по крайней мере, вряд ли приведут к ошибке 404.

Куда пойти отсюда

В этой статье рассматривается только поверхность экосистемы полифиллов HTML5. Существуют активные проекты, которые обеспечивают кросс-браузерную поддержку таких функций, как SVG и холст, видео HTML5, ECMAScript 5 и даже WebWorkers. Если вы хотите узнать больше об этих проектах, Пол Ирландский собрал фантастический ресурс с краткими описаниями и ссылками на многие из них здесь: https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser- Полифиллы .