Введение
Разработка для мобильного интернета – одна из самых популярных тем в наши дни. В этом году впервые смартфонов было продано больше, чем ПК. Все больше пользователей выходят в интернет с мобильных устройств, поэтому разработчикам необходимо оптимизировать сайты для мобильных браузеров.
Мобильные платформы – это неизведанная территория для многих разработчиков. У многих есть старые сайты, которые не оптимизированы для мобильных устройств. Сайт был разработан в первую очередь для браузеров для компьютеров и плохо отображается в мобильных браузерах. Этот сайт (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 для таблицы стилей screen заглавными буквами:
<!-- media="handheld" trick for Windows Mobile -->
<link rel="stylesheet" href="screen.css" media="Screen">
<link rel="stylesheet" href="mobile.css" media="handheld">
Как на сайте html5rocks используются запросы медиа
Запросы медиа активно используются на сайте html5rocks.com. Они позволили нам настроить макет, не внося существенных изменений в разметку шаблона 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 Flexbox
box-ordinal-group, чтобы изменить порядок разделов на главной странице. Обратите внимание, что на главной странице раздел "LEARN BY MAJOR HTML5 FEATURE GROUPS" (Изучение основных групп функций HTML5) находится перед разделом "TUTORIALS" (Учебные пособия), а в мобильной версии – после него. Такой порядок больше подходил для мобильных устройств и не требовал изменений в разметке. CSS Flexbox – это круто! - Будет удалено изменений:
opacity. Изменение значений альфа-канала снижает производительность на мобильных устройствах.
Метатеги для мобильных устройств
Мобильный WebKit поддерживает несколько функций, которые делают просмотр страниц на некоторых устройствах более удобным.
Настройки области просмотра
Первая метанастройка (и та, которую вы будете использовать чаще всего) – это свойство области просмотра. Область просмотра сообщает браузеру, как контент должен размещаться на экране устройства, и указывает, что сайт оптимизирован для мобильных устройств. Пример:
<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 метатег viewport расширен, чтобы разработчики могли указывать, для какого разрешения экрана предназначен сайт:
<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.
Дополнительную информацию о таргетинге на устройства с определенным разрешением экрана можно найти в документации по WebView.
Полноэкранный режим
Есть ещё два метазначения, которые относятся к iOS-sfic. 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, использовать gzip (в 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, так как они замедляют работу сайта. Значительная часть задержки была вызвана сторонними виджетами (Buzz, Google Friend Connect, Twitter, Facebook) на страницах с учебными материалами. Эти API были добавлены с помощью тегов
<script>и создают окна iframe, которые замедляют загрузку страницы. Виджеты были удалены для мобильных устройств.display:none– В некоторых случаях мы скрывали разметку, если она не подходила для мобильных устройств. Хорошим примером были четыре закругленных поля в верхней части главной страницы:
Они отсутствуют на мобильном сайте. Важно помнить, что браузер по-прежнему запрашивает каждый значок, несмотря на то, что их контейнер скрыт с помощью display:none. Поэтому было недостаточно просто
скрыть эти кнопки. Это не только пустая трата трафика, но и пользователь даже не увидит плоды этой потраченной пропускной способности! Решением было создать логическое значение is_mobile в нашем шаблоне Django, чтобы условно опускать разделы HTML.
Если пользователь просматривает сайт на умном устройстве, кнопки не показываются.
Кеш приложения. Он не только обеспечивает поддержку офлайн-режима, но и ускоряет запуск.
Сжатие CSS/JS. Мы используем YUI Compressor вместо Closure Compiler, главным образом потому, что он обрабатывает и CSS, и JS. Одна из проблем, с которой мы столкнулись, заключалась в том, что встроенные запросы медиа (запросы медиа, которые появляются внутри таблицы стилей) не работали в YUI compressor 2.4.2 (см. эту проблему). Использование YUI Compressor 2.4.4+ решило проблему.
По возможности используйте спрайты CSS.
Для сжатия изображений использовался инструмент pngcrush.
Используйте dataURI для небольших изображений. Кодировка Base64 увеличивает размер изображения примерно на 30 %, но позволяет избежать сетевого запроса.
Автоматически загружаемый пользовательский поиск Google, в котором вместо динамической загрузки с помощью
google.load()используется один тег script. В последнем случае выполняется дополнительный запрос.
<script src="//www.google.com/jsapi?autoload={"modules":[{"name":"search","version":"1"}]}"> </script>
- Наш автоформатировщик кода и Modernizr включались на каждой странице, даже если они не использовались. Modernizr – отличная библиотека, но она выполняет множество тестов при каждой загрузке. Некоторые из этих тестов вносят дорогостоящие изменения в DOM и замедляют загрузку страницы. Теперь мы добавляем эти библиотеки только на те страницы, где они действительно нужны. -2 запроса :)
Дополнительные настройки производительности:
- Перенесите весь код JavaScript в нижнюю часть страницы (где это возможно).
- Удалены встроенные теги
<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="...">).