Если вы создаете веб-сайт, вы не просто хотите, чтобы он сегодня выглядел потрясающе; Вы хотите, чтобы это ослепило в течение долгого времени. Это означает, что ваш сайт должен работать не только в современных браузерах, но и в будущих версиях. В этой статье я представлю несколько советов и рекомендаций, которые помогут вам достичь этой цели.
Немного истории
Сегодня все веб-браузеры построены с одной общей целью: оптимально отображать веб-страницы в соответствии с последними спецификациями.
Это не всегда так. В прошлом, когда производители браузеров стремительно становились доминирующими, большинство реализовывало функции, которые пользовались высоким спросом, даже если они еще не были стандартизированы. Конечно, каждый браузер делал это по-своему. Вот пример того, как изменяется прозрачность в CSS.
Internet Explorer до версии 8 понимал следующий CSS:
.transparent { /* Internet Explorer < 9 */ width: 100%; filter:alpha(opacity=50); }
в то время как Firefox имел свой собственный атрибут:
.transparent { /* Firefox < 0.9 */ -moz-opacity:0.5; }
как и Safari:
.transparent { /* Safari < 2 */ -khtml-opacity: 0.5; }
Однако теперь в CSS3 есть унифицированный способ установить прозрачность элемента:
.transparent { /* IE >= 9, Firefox >= 0.9, Safari >= 2, Chrome, Opera >= 9 */ opacity: 0.5; }
Хотя браузеру может показаться целесообразным приложить дополнительные усилия для поддержки нестандартных функций, это усложняет жизнь веб-разработчика, чем это необходимо, поскольку он должен принимать во внимание все различные реализации функции при добавлении ее в стр.
Последовательная разметка
Лучший способ обеспечить оптимальную визуализацию вашей веб-страницы во всех браузерах — сосредоточиться на разметке, которая наверняка будет поддерживаться во всех текущих версиях браузеров. До недавнего времени это был HTML 4.01, 10-летний стандарт с очень ограниченными возможностями.
Сегодня все браузеры сходятся к многофункциональному HTML5, но многие новые спецификации, обобщенные под этим общим термином, включая разметку HTML5, его API, такие как DOM Уровни 2 и 3, CSS3, SVG и EcmaScript 262, все еще находятся в разработке. и, следовательно, могут быть изменены. Поставщики браузеров постоянно добавляют поддержку новых функций HTML5, но в разном темпе.
Firefox и Opera обычно очень быстро принимают новые спецификации HTML5, иногда даже те, которые находятся на ранней стадии разработки и подвержены изменениям или имеют проблемы с безопасностью. Хотя разработчикам может быть интересно протестировать новые функции, это может привести к разрыву веб-страниц между выпусками браузера из-за радикальных изменений между спецификацией и ее реализацией. Это разочаровывающий опыт для пользователей и разработчиков. Примером этого является Firefox 4, отключающий Websockets между бета-версиями 7 и 8 по соображениям безопасности.
Chrome, который также очень быстро адаптируется к новым стандартам HTML5, недавно взволновал сообщество HTML5 объявлением о том, что он отказывается от поддержки популярного видеокодека h.264 для элементов HTML5 <video> и вместо этого переключается на бесплатный веб-стандарт WEBM. , Хотя это может быть полезно для разработчиков, которые в настоящее время платят за лицензии h.264, это добавляет еще один выбор, который разработчики должны будут отслеживать, чтобы поддерживать как можно больше браузеров.
Microsoft медленнее внедряет стандарты, но работает в тесном сотрудничестве с W3C для создания тестовых наборов, помогая минимизировать неоднозначность в спецификациях и создавая техническую основу, помогающую поставщикам работать над гомогенизацией способов отображения HTML5 в своих браузерах. Чтобы увидеть последние работы в этой области, взгляните на Internet Explorer 10 Platform Preview, который вы можете найти в IE Test Drive . Вы также захотите проверить HTML5-метки, на которых Microsoft ранее создавала прототипы, нестабильные спецификации от организаций по веб-стандартам, таких как W3C. См. Раздел « Улучшенная совместимость благодаря поддержке стандартов»., »Руководства для разработчиков по Internet Explorer 9 для получения подробной информации о том, как Internet Explorer 9 сегодня поддерживает различные спецификации HTML5.
Тем не менее, поскольку новые стандарты HTML5 остаются движущейся целью, а большинство пользователей Интернета не используют последние версии различных веб-браузеров, правильная разметка важна как никогда.
Обнаружение браузера
Одним из подходов к обработке различий между браузерами является использование обнаружения браузеров. Наиболее распространенный способ сделать это — использовать JavaScript для запроса заголовка user-agent:
<script type="text/javascript"> if ( navigator.userAgent.indexOf("MSIE")>0 ) { // Run custom code for Internet Explorer. } </script>
Проблема с этим подходом имеет две стороны. Во-первых, он объединяет несколько предположений о функциях, поддерживаемых браузером, за одну проверку. Одно неверное предположение может сломать сайт. Поэтому, как разработчику, вы должны отслеживать, какие именно функции поддерживает каждая версия конкретного браузера.
Вторая проблема заключается в том, что эта проверка браузера не учитывает версии браузера и поэтому не рассчитана на будущее. Даже если он работает с сегодняшней версией браузера, следующий выпуск может не потребовать — или, что еще хуже, может вообще исключить поддержку — обходной путь, который обнаружение браузера использовалось для добавления на сайт.
Поэтому, если вам нужно использовать обнаружение браузера, убедитесь, что вы учитываете версию и используете этот подход только для обнаружения устаревших браузеров, как показано на рисунке 1 .
Рисунок 1 Обнаружение устаревших браузеров
<script type="text/javascript"> functiongetInternetExplorerVersion() // Returns the version of Internet Explorer or a -1 for other browsers. { var rv = -1; if(navigator.appName == 'Microsoft Internet Explorer') { var ua = navigator.userAgent; varre = newRegExp("MSIE ([0-9]{1,}[\.0-9]{0,})"); if(re.exec(ua) != null) rv = parseFloat( RegExp.$1 ); } return rv; } functiononLoad() { var version = GetInternetExplorerVersion() if (version <= 7 && version > -1) { // Code to run in Internet Explorer 7 or earlier. } } </script>
Страница библиотеки MSDN « Более эффективное обнаружение браузеров » содержит больше информации, и вы найдете исчерпывающую статью о том, как использовать объект навигатора и регулярные выражения для обнаружения различных браузеров и их точных версий, в руководствах по JavaScript .
Начиная с версии 5, Internet Explorer имеет уникальный способ обнаружения браузеров с помощью условных комментариев. Этот синтаксис расширяет стандартные комментарии HTML. Вы можете использовать эти условные комментарии с CSS для реализации определенных правил CSS для Internet Explorer, которые другие браузеры должны игнорировать. В следующем примере «ie7.css» загружается, только если обнаружен Internet Explorer 7 или более ранней версии:
<!--[if lte IE 7]> <style TYPE="text/css"> @import url(ie7.css); </style> <![endif]-->
Подробную информацию об использовании условных комментариев можно найти на странице библиотеки MSDN « Об условных комментариях ».
Однако, учитывая все проблемы и ограничения обнаружения браузеров, давайте рассмотрим альтернативу.
Обнаружение функций
Гораздо лучшим подходом к обработке различий между веб-браузерами является использование функции обнаружения. Прежде чем использовать функцию, которая, как вам известно, имеет разные реализации в разных браузерах, вы запускаете небольшой тест, который ищет доступность определенного объекта, метода, свойства или поведения. В большинстве случаев это можно сделать, пытаясь создать новый экземпляр рассматриваемой функции, и если это создание возвращает что-то отличное от нуля, исполняющий браузер знает эту функцию. Если нет, то вы можете проверить, проверяя наличие обходного пути или запатентованную унаследованную реализацию этой функции.
Сравнение обнаружения браузера и функций
Давайте использовать диаграммы на рисунках 2, 3 и 4, чтобы помочь визуализировать, как эти два подхода работают в различных ситуациях.
Рисунок 2. Возможные пути кода через тестовый сайт
Результаты рисунка 3 с хорошо известными конфигурациями браузера
Когда сталкиваются с хорошо известными конфигурациями браузера, оба метода работают, но обнаружение браузера имеет фиксированное предположение, что функция A и функция B поддерживаются браузером, тогда как обнаружение функции тестирует каждую функцию в отдельности.
Рисунок 4 Неизвестная конфигурация браузера
Когда сталкиваешься с неизвестной конфигурацией браузера, вещи становятся интересными. Обнаружение функций хорошо справляется с этим и обнаруживает, что браузер способен отображать функцию А, но ему необходим резервный код для функции В. С другой стороны, при обнаружении браузера выбирается путь на основе имени браузера или выбирается путь по умолчанию, поскольку ни один из Запрошенные комбинации браузер / версия совпадают. В любом случае, в этом примере страница не будет отображаться должным образом, потому что нет пути к коду, который соединяет все допустимые сегменты кода, даже если страница фактически содержит весь код, необходимый для правильного отображения в этой неизвестной конфигурации браузера.
Примеры обнаружения функций
Есть две очень важные рекомендации, которые следует учитывать при использовании функции обнаружения:
- Всегда сначала проверяйте стандарты, потому что браузеры часто поддерживают более новый стандарт, а также устаревший обходной путь.
- Всегда проверяйте только связанные функции в одной проверке , эффективно сводя к минимуму предположения о возможностях браузера.
Теперь давайте рассмотрим несколько примеров обнаружения функций.
Следующий скрипт создает два пути кода. Сначала он проверяет, поддерживает ли браузер window.addEventListener, и, если нет, проверяет наличие унаследованной функции window.attachEvent:
<script type="text/javascript"> if(window.addEventListener) { // Browser supports "addEventListener" window.addEventListener("load", myFunction, false); } else if(window.attachEvent) { // Browser supports "attachEvent" window.attachEvent("onload", myFunction); } </script>
Другим хорошим подходом является инкапсуляция обнаружения функций в набор функций, которые затем можно использовать в коде. Вот лучший способ определить, поддерживает ли браузер элемент HTML5 <canvas> и, если да, убедиться, что метод canvas.getContext (‘2d’) также работает. Эта функция просто возвращает true или false, что облегчает повторное использование.
<script type="text/javascript"> functionisCanvasSupported() { var elem = document.createElement('canvas'); return!!(elem.getContext && elem.getContext('2d'); } </script>
При использовании функции обнаружения следует помнить одну вещь: всегда использовать его для вновь создаваемых элементов или объектов, чтобы избежать вероятности того, что любой другой скрипт на странице изменил элемент или объект с момента его создания, что может привести к случайному или ошибочные результаты.
Функция обнаружения также работает напрямую для нескольких элементов HTML, таких как HTML5 <video>, <audio> и <canvas>, в форме «отступления». Браузер отображает первый поддерживаемый подэлемент сверху и визуально скрывает элементы ниже.
Самая простая форма выглядит так:
<video src="video.mp4"> Your browser doesn't support videos natively. </video>
Браузер, который поддерживает элемент <video>, покажет видео «video.mp4», а браузер, который не вернется к предоставленному тексту. Но отступление также работает для различных видеоформатов в теге video:
<video> <source src="video.mp4" type="video/mp4" /> <source src="video.webm" type="video/webm" /> Your browser doen't suppport videos natively. </video>
В этом случае браузер, поддерживающий HTML5 <video>, сначала попытается загрузить видео mp4. Если он не поддерживает этот формат, он вернется к видео в кодировке WebM. Если этот формат не поддерживается или браузер вообще не поддерживает <video>, он вернется к тексту.
Конечно, имеет смысл использовать вместо видеоплеера подключаемый видеоплеер, если браузер вообще не поддерживает HTML5 <video>. В следующем примере используется видеопроигрыватель Silverlight:
<video> <source src="video.mp4" type='video/mp4' /> <source src="video.webm" type='video/webm' /> <object type="application/x-silverlight-2"> <param name="source" value="http://url/player.xap"> <param name="initParams" value="m=http://url/video.mp4"> </object> Download the video <a href="video.mp4">here</a>. </video>
Очень похожая логика работает и в CSS. В CSS нераспознанные свойства просто игнорируются. Поэтому, если вы хотите добавить несколько экспериментальных свойств с префиксом поставщика, как показано ниже в разделе «border-radius», вы можете просто включить все варианты в свой код. Это может показаться немного неточным, но его легко использовать, и работа выполняется в таких случаях, как этот. Обратите внимание, что рекомендуется сначала указывать префиксы, которые вы хотите включить, и стандартную разметку в последнюю очередь.
<style type="text/css"> .target { -moz-border-radius: 20px; -webkit-border-radius: 20px; border-radius: 20px; } </style>
Большой плюс обнаружения функций заключается в том, что он также работает с браузерами, о которых вы даже не задумывались при создании своей страницы, и даже с будущими версиями браузеров, потому что он не основывается на каких-либо предположениях о том, какие функции поддерживает браузер.
Разработка и тестирование функции обнаружения
В F12 Developer Tools в Internet Explorer-отлично подходит для разработки и тестирования функции обнаружения во многих браузерах. Вы можете использовать их для пошаговой отладки скрипта и для изменения строки пользовательского агента браузера, а также для указания Internet Explorer использовать механизм рендеринга предыдущих версий . На рисунках 5, 6, 7 и 8 показаны некоторые примеры того, как вы можете использовать эти инструменты.
Рисунок 5 Использование точек останова при отладке JavaScript в Internet Explorer 9
Рисунок 6. Работа в «режиме документа: стандарты IE9», bBrowser использует современный метод addEventListener
Рис. 7. Запуск в «режиме документа: стандарты IE7», отладчик возвращается к старому методу attachEvent
Рис. 8. Вы можете изменить строку пользовательского агента Internet Explorer на лету и даже добавить свои собственные строки, в том числе для мобильных браузеров
Управление обнаружением функций в больших проектах
При создании сложного веб-проекта создание и управление всем кодом обнаружения функций может быть утомительным. К счастью, есть отличные библиотеки JavaScript, которые помогают в этом, а именно Modernizr и jQuery .
Modernizr имеет встроенное обнаружение для большинства функций HTML5 и CSS3, которые очень легко использовать в вашем коде. Это очень широко распространено и постоянно совершенствуется. И Modernizr, и jQuery поставляются с инструментами ASP.NET MVC.
Взгляните на код на рисунке 9 , который определяет способность браузера отображать веб-шрифты без использования Modernizr, а затем на код на рисунке 10 , который использует Modernizr.
Рисунок 9 без модернизма
function(){ var sheet, bool, head = docHead || docElement, style = document.createElement("style"), impl = document.implementation || { hasFeature: function() { return false; } }; style.type = 'text/css'; head.insertBefore(style, head.firstChild); sheet = style.sheet || style.styleSheet; var supportAtRule = impl.hasFeature('CSS2', '') ? function(rule) { if (!(sheet && rule)) return false; var result = false; try { sheet.insertRule(rule, 0); result = (/src/i).test(sheet.cssRules[0].cssText); sheet.deleteRule(sheet.cssRules.length - 1); } catch(e) { } return result; } : function(rule) { if (!(sheet && rule)) return false; sheet.cssText = rule; return sheet.cssText.length !== 0 && (/src/i).test(sheet.cssText) && sheet.cssText .replace(/\r+|\n+/g, '') .indexOf(rule.split(' ')[0]) === 0; }; bool = supportAtRule('@font-face { font-family: "font"; src: url(data:,); }'); head.removeChild(style); return bool; };
Рисунок 10 с Модернизром
<script type="text/javascript" src"modernizr.custom.89997.js"></script> <script type="text/javascript"> if(Modernizr.fontface){ // font-face is supported } </script>
Добавление поддержки для отсутствующих функций
Обнаружение функций не избавляет от необходимости искать обходной путь, когда протестированный браузер не поддерживает нужную вам функцию. В предыдущем примере HTML5-видео использование Silverlight в качестве запасного варианта было очевидным решением. Но как насчет других функций HTML5, таких как <canvas> или новых семантических тегов, таких как <nav>, <section> и <article>, <aside> или новых <header> и <footer>?
Растущее число готовых «откатов» для многих функций HTML5, известных как прокладки и полифиллы, может облегчить эту нагрузку. Они представлены в виде библиотек CSS и JavaScript, а иногда даже как элементы управления Flash или Silverlight, которые можно использовать в своем проекте, добавляя недостающие функции HTML5 в браузеры, которые в противном случае их не поддерживают.
Общая идея заключается в том, что разработчики должны иметь возможность разрабатывать с помощью API-интерфейсов HTML5, а сценарии могут создавать методы и объекты, которые должны существовать. Разработка таким образом, ориентированным на будущее, означает, что по мере обновления пользователей код не должен изменяться, и пользователи будут переходить к более качественному исходному интерфейсу.
Разница между shims и polyfills заключается в том, что shims имитируют только функцию, и у каждого есть собственный проприетарный API, в то время как polyfills эмулирует как саму функцию HTML5, так и ее точный API. Так что, вообще говоря, использование полифилла избавляет вас от необходимости использовать собственный API.
Коллекция HTML5 Cross Browser Polyfills на github содержит растущий список доступных прокладок и polyfills.
Modernizr, например, включает «HTML5Shim» для поддержки семантических тегов, но легко загрузить другие прокладки и полифиллы, если Modernizr обнаружит, что функция не поддерживается.
Добавление поддержки динамически
Вы можете спросить себя: «Разве добавление всех этих библиотек сценариев не сделает мою страницу огромной и медленно загружаемой?»
Что ж, это правда, что использование многих из этих вспомогательных библиотек может значительно увеличить нагрузку на ваш веб-сайт, поэтому имеет смысл загружать их динамически только тогда, когда они действительно необходимы. В случае с прокладкой или полифилом рекомендуется загружать их только тогда, когда вы обнаружили, что браузер не поддерживает встроенную функцию HTML5.
Опять же, нам повезло, потому что есть отличная библиотека, которая поддерживает именно этот сценарий: yepnope.js
Yepnope is an asynchronous resource loader that works with both JavaScript and CSS and fully decouples preloading from execution. This means that you have full control of when your resource is executed and you can change the order on the fly. Yepnope will be integrated in Modernizr 2, but can also be used on its own. Let’s have a look at its syntax:
<script type="text/javascript" src="yepnope.1.0.2-min.js"></script> <script type="text/javascript"> yepnope({ test : Modernizr.geolocation, yep : 'normal.js', nope : ['polyfill.js', 'wrapper.js'] }); </script>
This example from the Yepnope page tests the browser’s ability to use HTML5 geolocation using Modernizr. If supported, your own code (normal.js) will be loaded; otherwise, a custom polyfill (that consists of polyfill.js and wrapper.js) will be loaded.
The most important points are summarized in Figure 11.
Figure 11 Browser Detection and Feature Detection Dos and Don’ts
DO | DON’T | |
Browser Detection |
Try to avoid altogether. or Test for a specific browser and version. |
Make assumptions for future browsers by only testing for the browser name. |
Feature Detection | Test for standards first. | Assume unrelated features under one test. |
Source: http://msdn.microsoft.com/en-us/magazine/hh475813.aspx