Введение
Разработка для мобильного Интернета в наши дни является горячей темой. В этом году впервые смартфоны продавались лучше ПК . Все больше и больше пользователей используют мобильные устройства для работы в Интернете, а это означает, что разработчикам становится критически важно оптимизировать свои сайты для мобильных браузеров.
«Мобильное» поле битвы все еще остается неизведанным для большого числа разработчиков. У многих людей есть устаревшие сайты, которые вообще игнорируют мобильных пользователей. Вместо этого сайт был разработан в первую очередь для просмотра на настольных компьютерах и плохо ухудшается в мобильных браузерах. Этот сайт (html5rocks.com) не является исключением. При запуске мы приложили мало усилий к мобильной версии сайта.
Создание удобного для мобильных устройств сайта html5rocks.com
В качестве упражнения я подумал, что было бы интересно взять html5rocks (существующий сайт HTML5) и дополнить его версией, удобной для мобильных устройств. В основном меня волновал минимальный объем работы, необходимый для ориентирования на смартфоны. Целью моего упражнения было не создание совершенно нового мобильного сайта и поддержка двух кодовых баз. Это заняло бы целую вечность и было бы огромной тратой времени. Мы уже определили структуру сайта (разметку). У нас был внешний вид (CSS). Основная функциональность (JS) присутствовала. Дело в том, что многие сайты находятся в одной лодке.
В этой статье рассказывается, как мы создали мобильную версию html5rocks, оптимизированную для устройств Android и iOS. Просто загрузите html5rocks.com на устройство, поддерживающее одну из этих ОС, и вы увидите разницу. Нет никаких перенаправлений на m.html5rocks.com или других дураков такого рода. Вы получаете html5rocks «как есть»… с дополнительным преимуществом: он отлично выглядит и хорошо работает на мобильных устройствах.
CSS-медиа-запросы
HTML4 и CSS2 уже некоторое время поддерживают таблицы стилей, зависящие от носителя . Например:
<link rel="stylesheet" media="print" href="printer.css">
будет нацелен на устройства печати и обеспечит определенный стиль для содержимого страницы при ее печати. CSS3 развивает идею медиа-типов на шаг дальше и расширяет их функциональность с помощью медиа-запросов. Медиа-запросы расширяют возможности медиа-типов, обеспечивая более точную маркировку таблиц стилей. Это позволяет настроить представление контента для определенного диапазона устройств вывода без необходимости изменения самого контента. Звучит идеально для существующего макета, который необходимо изменить!
Вы можете использовать медиа-запросы в атрибуте media
ваших внешних таблиц стилей для определения ширины экрана, ширины устройства, ориентации и т. д. Полный список см. в спецификации медиа-запросов W3C .
Таргетинг на размеры экрана
В следующем примере phone.css
будет применяться к устройствам, которые браузер считает «карманными», или к устройствам с экранами шириной <= 320 пикселей.
<link rel='stylesheet'
media='handheld, only screen and (max-device-width: 320px)' href='phone.css'>
Использование префикса к медиа-запросам с ключевым словом « only
» приведет к тому, что браузеры, не совместимые с CSS3, будут игнорировать это правило.
Ниже приведены целевые размеры экрана от 641 до 800 пикселей:
<link rel='stylesheet'
media='only screen and (min-width: 641px) and (max-width: 800px)' href='ipad.css'>
Медиа-запросы также могут появляться внутри встроенных тегов <style>
. Следующее предназначено для all
типов мультимедиа в книжной ориентации:
<style>
@media only all and (orientation: portrait) { ... }
</style>
media="handheld"
Нам нужно остановиться на минутку и обсудить media="handheld"
. Дело в том, что Android и iOS игнорируют media="handheld"
. Утверждается, что пользователи будут скучать по высококачественному контенту, предоставляемому таблицами стилей, ориентированными на media="screen"
, а разработчики с меньшей вероятностью будут поддерживать версию media="handheld"
более низкого качества. Таким образом, в рамках своего девиза «полноценный Интернет» большинство современных браузеров для смартфонов просто игнорируют таблицы стилей для портативных устройств.
Было бы идеально использовать эту функцию для таргетинга на мобильные устройства, но в разных браузерах она реализована по-разному:
- Некоторые читают только таблицу стилей для портативных устройств.
- Некоторые читают только таблицу стилей портативного устройства, если таковая имеется, но в противном случае по умолчанию используют таблицу стилей экрана.
- Некоторые читают и таблицу стилей портативного устройства, и таблицу стилей экрана.
- Некоторые читают только таблицу стилей экрана.
Opera Mini не игнорирует media="handheld"
. Чтобы заставить Windows Mobile распознавать media="handheld"
нужно использовать значение атрибута media для таблицы стилей экрана:
<!-- media="handheld" trick for Windows Mobile -->
<link rel="stylesheet" href="screen.css" media="Screen">
<link rel="stylesheet" href="mobile.css" media="handheld">
Как html5rocks использует медиа-запросы
Медиа-запросы активно используются в мобильных html5rocks. Они позволили нам настроить макет без необходимости внесения существенных изменений в разметку шаблона Django… настоящий спаситель! Кроме того, их поддержка в различных браузерах довольно хороша.
В <head>
каждой страницы вы увидите следующие таблицы стилей:
<link rel='stylesheet'
media='all' href='/static/css/base.min.css' />
<link rel='stylesheet'
media='only screen and (max-width: 800px)' href='/static/css/mobile.min.css' />
base.css
всегда определял основной внешний вид html5rocks.com, но теперь мы применяем новые стили ( mobile.css
) для ширины экрана менее 800 пикселей. Его медиа-запрос охватывает смартфоны (~320 пикселей) и iPad (~768 пикселей). Результат: мы постепенно переопределяем стили в base.css
(только по мере необходимости), чтобы все выглядело лучше на мобильных устройствах.
Некоторые изменения стиля, которые обеспечивает mobile.css
:
- Уменьшает лишние пробелы/отступы на сайте. Маленькие экраны означают, что пространство в дефиците!
- Удаляет состояния
:hover
. Их никогда не видели на сенсорных устройствах. - Настраивает макет на один столбец. Подробнее об этом позже.
- Удаляет
box-shadow
вокруг основного контейнера div сайта. Большие тени блока снижают производительность страницы. - Использована гибкая модель CSS
box-ordinal-group
для изменения порядка каждого раздела на главной странице. Вы заметите, что надпись «ИЗУЧЕНИЕ ОСНОВНЫМИ ГРУППАМИ ФУНКЦИЙ HTML5» находится перед разделом «УЧЕБНЫЕ ПОСОБИЯ» на главной странице, но после него в мобильной версии. Такой порядок имел больше смысла для мобильных устройств и не требовал изменений разметки. CSS-флексбокс, кстати! - Удаляет изменения
opacity
. Изменение альфа-значений снижает производительность на мобильных устройствах.
Мобильные метатеги
Mobile WebKit поддерживает несколько функций, которые улучшают работу пользователей в Интернете на определенных устройствах.
Настройки видового экрана
Первый мета-параметр (и тот, который вы будете использовать чаще всего) — это свойство viewport. Настройка области просмотра сообщает браузеру, как контент должен размещаться на экране устройства, и сообщает браузеру, что сайт оптимизирован для мобильных устройств. Например:
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
сообщает браузеру, что область просмотра должна соответствовать ширине устройства с начальным масштабом 1. Этот пример также позволяет масштабировать, что может быть желательно для веб-сайта, но не для веб-приложения. Мы могли бы запретить масштабирование с помощью user-scalable=no
или ограничить масштабирование до определенного уровня:
<meta name=viewport
content="width=device-width, initial-scale=1.0, minimum-scale=0.5 maximum-scale=1.0">
Android расширяет метатег области просмотра, позволяя разработчикам указывать, для какого разрешения экрана был разработан сайт:
<meta name="viewport" content="target-densitydpi=device-dpi">
Возможные значения для target-densitydpi
: device-dpi
, high-dpi
, medium-dpi
, low-dpi
.
Если вы хотите изменить свою веб-страницу для различной плотности экрана, используйте медиа-запрос CSS -webkit-device-pixel-ratio
и/или свойство window.devicePixelRatio
в JavaScript, а затем установите для мета-свойства target-densitydpi
значение device-dpi
. Это не позволяет Android выполнять масштабирование вашей веб-страницы и позволяет вам внести необходимые настройки для каждой плотности с помощью CSS и JavaScript.
Дополнительную информацию о настройке разрешения устройства см. в документации Android WebView .
Полноэкранный просмотр
Есть еще два метазначения, специфичные для iOS. apple-mobile-web-app-capable
и apple-mobile-web-app-status-bar-style
отобразят содержимое страницы в полноэкранном режиме, подобном приложению, и сделают строку состояния полупрозрачной:
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
Дополнительную информацию обо всех доступных мета-параметрах см. в справочной документации Safari .
Значки главного экрана
Устройства iOS и Android также принимают для ссылок rel="apple-touch-icon"
(iOS) и rel="apple-touch-icon-precomposed"
(Android). Они создают яркий значок, похожий на приложение, на главном экране пользователя, когда он добавляет ваш сайт в закладки:
<link rel="apple-touch-icon"
href="/static/images/identity/HTML5_Badge_64.png" />
<link rel="apple-touch-icon-precomposed"
href="/static/images/identity/HTML5_Badge_64.png" />
Как html5rocks использует мобильные метатеги
Собрав все вместе, вот фрагмент из раздела <head>
html5rocks:
<head>
...
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
<link rel="apple-touch-icon"
href="/static/images/identity/HTML5_Badge_64.png" />
<link rel="apple-touch-icon-precomposed"
href="/static/images/identity/HTML5_Badge_64.png" />
...
</head>
Вертикальная планировка
На небольших экранах гораздо удобнее прокручивать по вертикали, чем по горизонтали. Для мобильных устройств предпочтительнее хранить контент в вертикальном макете в одну колонку. Для html5rocks мы использовали медиа-запросы CSS3, чтобы создать такой макет. Опять же без изменения разметки.
Мобильная оптимизация
Большинство оптимизаций, которые мы сделали, — это то, что следовало бы сделать в первую очередь. Такие вещи, как уменьшение количества сетевых запросов, сжатие JS/CSS, gzipping (бесплатно доступно в App Engine) и минимизация манипуляций с DOM. Эти методы являются общепринятыми передовыми практиками , но иногда их упускают из виду, когда сайт срочно закрывается.
Автоматически скрывать адресную строку
Мобильным браузерам не хватает экранного пространства, как у их настольных аналогов. Что еще хуже, на разных платформах иногда в верхней части экрана появляется большая адресная строка… даже после того, как страница загружается.
Один из простых способов справиться с этим — прокручивать страницу с помощью JavaScript. Даже если сделать это на один пиксель, вы избавитесь от надоедливой адресной строки. Чтобы принудительно скрыть адресную строку на html5rocks, я прикрепил обработчик события onload
к объекту window
и прокрутил страницу по вертикали на один пиксель:
// Hides mobile browser's address bar when page is done loading.
window.addEventListener('load', function(e) {
setTimeout(function() { window.scrollTo(0, 1); }, 1);
}, false);
Мы также обернули этот прослушиватель нашей переменной шаблона is_mobile
, поскольку на рабочем столе он не нужен.
Уменьшите сетевые запросы, сэкономьте пропускную способность
Известно, что уменьшение количества HTTP-запросов может значительно повысить производительность. Мобильные устройства еще больше ограничивают количество одновременных подключений, которые может установить браузер, поэтому мобильные сайты получат еще большую выгоду от сокращения этих посторонних запросов. Более того, удаление каждого байта имеет решающее значение, поскольку на телефонах пропускная способность часто ограничена. Вы можете стоить пользователям денег!
Ниже приведены некоторые подходы, которые мы использовали для минимизации сетевых запросов и уменьшения пропускной способности html5rocks:
Удалите iframe — iframe работают медленно! Большая часть наших задержек возникла из-за сторонних виджетов обмена (Buzz, Google Friend Connect, Twitter, Facebook) на страницах руководств. Эти API были включены через теги
<script>
и создавали iframe, которые снижали скорость страницы. Виджеты были удалены для мобильных устройств.display:none
— в некоторых случаях мы скрывали разметку, если она не соответствовала мобильному профилю. Хорошим примером являются четыре закругленных прямоугольника вверху главной страницы :
Они отсутствуют на мобильном сайте. Важно помнить, что браузер по-прежнему выполняет запрос для каждого значка, несмотря на то, что их контейнер скрыт с помощью display:none
. Поэтому просто скрыть эти кнопки было недостаточно. Это не только приведет к потере полосы пропускания, но и пользователь даже не увидит плодов этой потраченной впустую полосы пропускания! Решение заключалось в том, чтобы создать логическое значение «is_mobile» в нашем шаблоне Django, чтобы условно опускать разделы HTML. Когда пользователь просматривает сайт на смарт-устройстве, кнопки не отображаются.
Кэш приложений. Это не только дает нам автономную поддержку, но и ускоряет запуск.
Сжатие CSS/JS — мы используем компрессор YUI вместо компилятора Closure, главным образом потому, что он обрабатывает как CSS, так и JS. Одна из проблем, с которой мы столкнулись, заключалась в том, что встроенные медиа-запросы (медиа-запросы, которые появляются внутри таблицы стилей) не отображались в компрессоре YUI 2.4.2 (см. эту проблему ). Использование YUI Compressor 2.4.4+ устранило проблему.
Там, где это возможно, используются спрайты изображений CSS.
Использовал pngcrush для сжатия изображений.
Используются dataURI для небольших изображений. Кодировка Base64 увеличивает размер изображения примерно на 30%+, но сохраняет сетевой запрос.
Пользовательский поиск Google автоматически загружается с использованием одного тега скрипта, а не динамически загружается с помощью
google.load()
. Последний делает дополнительный запрос.
<script src="//www.google.com/jsapi?autoload={"modules":[{"name":"search","version":"1"}]}"> </script>
- Наш принтер Code Beautiful и Modernizr были включены на каждую страницу, даже если они никогда не использовались. Modernizr великолепен, но при каждой загрузке он выполняет кучу тестов. Некоторые из этих тестов вносят дорогостоящие изменения в DOM и замедляют загрузку страницы. Теперь мы включаем эти библиотеки только на те страницы, где они действительно необходимы. -2 просьбы :)
Дополнительные настройки производительности:
- Переместил весь JS в низ страницы (там, где это возможно).
- Удалены встроенные теги
<style>
. - Поиск в кэше DOM и минимизация манипуляций с DOM. Каждый раз, когда вы касаетесь DOM, браузер выполняет перекомпоновку . Перекомпоновка на мобильном устройстве обходится еще дороже.
- Выгрузил ненужный клиентский код на сервер. В частности, проверка устанавливает стиль навигации текущей страницы:
js var lis = document.querySelectorAll('header nav li'); var i = lis.length; while (i--) { var a = lis[i].querySelector('a'); var section = a.getAttribute("data-section"); if (new RegExp(section).test(document.location.href)) { a.className = 'current'; } }
- Элементы с фиксированной шириной были заменены на гибкую
width:100%
илиwidth:auto
.
Кэш приложений
Мобильная версия html5rocks использует кэш приложений для ускорения начальной загрузки и позволяет пользователям читать контент в автономном режиме.
При реализации AppCache на своем сайте очень важно не кэшировать файл манифеста (либо явно в самом файле манифеста, либо неявно с тяжелыми заголовками управления кэшем). Если ваш манифест кэшируется браузером, отладка становится кошмаром. iOS и Android особенно хорошо кэшируют этот файл, но не предоставляют удобного способа очистки кеша, как это делают браузеры для настольных компьютеров.
Чтобы предотвратить указанное кэширование нашего сайта, мы сначала настроили App Engine так, чтобы он никогда не кэшировал файлы манифеста:
- url: /(.*\.(appcache|manifest))
static_files: \1
mime_type: text/cache-manifest
upload: (.*\.(appcache|manifest))
expiration: "0s"
Во-вторых, мы использовали JS API, чтобы информировать пользователя о завершении загрузки нового манифеста. Им будет предложено обновить страницу:
window.applicationCache.addEventListener('updateready', function(e) {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
window.applicationCache.swapCache();
if (confirm('A new version of this site is available. Load it?')) {
window.location.reload();
}
}
}, false);
Чтобы сэкономить сетевой трафик, сохраняйте простой манифест. То есть не называйте каждую страницу вашего сайта. Просто перечислите важные изображения, файлы CSS и JavaScript. Меньше всего вам нужно заставить мобильный браузер загружать большое количество ресурсов при каждом обновлении кэша приложения. Вместо этого помните, что браузер неявно кэширует html-страницу при посещении пользователем (и она включает атрибут <html manifest="...">
).