Задумываясь о разработке html5 приложения, многим сразу на ум приходит jQuery, или точнее jQueryMobile. И попробовав написать даже самое простенькое приложение используя jQueryMobile, очень легко разочароваться, так как производительность и отзывчивость получившегося html5 приложения куда ниже ожидаемого, и уж совсем его не сравнить с нативными приложениями.

Соответственно, если продолжить идти по пути html5, вы постепенно узнаёте, что тормоза и плохая отзывчивость из-за того, что есть множество тонкостей, например, что jquery далеко не самый быстрый вариант для приложения или по-умолчанию любое нажатие пользователя срабатывает с 300мс задержкой, что ухудшает отзывчивость.
Также важным моментом является есть ли набор готовых типичных компонентов, таких как список, кнопки, боковое меню итд, время на повторную разработку которых нет смысла трат��ть. Можно добавить еще к этому списку то, что как-то всё таки нужно решить проблему производительности, чтобы конкурировать с нативными приложениями.
И мы, наконец, подходим к самому главному, чтобы не забивать себе голову решением таких проблем, а получить сразу готовый инструмент для разработки быстрых, отзывчивых и функциональных html5 приложений, существует Framework7. Сам я с ним столкнулся совершенно случайно, и удивился тому, насколько он прост в использовании без необходимости искать решения в разных местах, достаточно просто подключить framework7.js.
Стоит отметить, что для работы с Framework7 не нужно использовать какие-то сторонние модули или библиотеки, так как он всё уже содержит:
На сайте есть огромное кол-во примеров (работают в браузере), инструкций и обучающих статей (например, работа Framework7 совместно с AngularJS)
www.idangero.us/framework7

Чтобы далеко не ходить, создадим небольшое приложение-пример, где можно будет посмотреть, как объединить отдельные компоненты фреймворка в единое приложение. Будем использовать slide menu, pull to refresh, infinite scroll, смену material/ios style на лету и огромным списком на 8000 элементов, который не тормозит (virtual list).
Структура приложения довольно простая:
Больше ничего не потребуется, другие библиотеки или фреймворки для создания приложения не нужны. Но при желании можно использовать require.js, angular.js, matreshka.js итд.
В итоге получается очень отзывчивое, легкое и быстрое html5 приложение, которое можно использовать как и где угодно.
Хоть у нас и получилось очень быстрое и легкое приложение, на старых версиях андроид оно всё равно будет недостаточно производительным.
Дело в том, что на версиях андроид до 4.4 используется очень тормозной webview (убедиться в этом можно, например, если на 4.1 андроид поставить chrome beta и запустить приложение в нём, а потом сравнить с тем, что есть во встроенном браузере, то разница в скорости будет очень заметна). Поэтому, если просто запаковать html5 приложение в apk, оно будет использовать именно встроенный тормозной webview.
Только начиная с 5.x андроида, webview обновляется отдельно и базируется на свежем chromium, благодаря чему html5 приложение будет работать быстро и плавно.
Проще говоря, если нужна хорошая производительность от html5 приложения на любых устройствах и любых версиях андроид, нужно чтобы оно работало на chromium движке. Проект, который позволяет это сделать, называется crosswalk и вместо встроенного webview используется свой собственный, который работает на последней версии chromium.

Самый простой способ проверить как ваше html5 приложение будет работать с использованием crosswalk, это установить Intel XDK, создать пустой «Standart HTML5» проект, и заменить в созданном проекте папку www на вашу.
После этого выбрать Build и нажать на Crosswalk for Android. Приложение будет скомпилировано на удаленном сервере, и спустя несколько минут вы получите ссылку на apk (версия для arm и x86). К минусам можно отнести тот факт, то размер приложения увеличится на ~19мб.
Сайт framework7: www.idangero.us/framework7
Онлайн пример готового приложения: comedian-ant-73047.bitballoon.com (так как онлайн, то немного тормозит загрузка стилей)
Исходники: yadi.sk/d/Quu2VfApgcGXA
Готовые apk файлы, созданные через Intel XDK: yadi.sk/d/marrZA5-gcGuQ
Онлайн пример большинства возможностей (kitchen-sink): framework7.io/kitchen-sink-ios или framework7.io/kitchen-sink-material
Тоже самое в material дизайне: poacher-bear-12003.bitballoon.com/kitchen-sink-material/index.html

Соответственно, если продолжить идти по пути html5, вы постепенно узнаёте, что тормоза и плохая отзывчивость из-за того, что есть множество тонкостей, например, что jquery далеко не самый быстрый вариант для приложения или по-умолчанию любое нажатие пользователя срабатывает с 300мс задержкой, что ухудшает отзывчивость.
Также важным моментом является есть ли набор готовых типичных компонентов, таких как список, кнопки, боковое меню итд, время на повторную разработку которых нет смысла трат��ть. Можно добавить еще к этому списку то, что как-то всё таки нужно решить проблему производительности, чтобы конкурировать с нативными приложениями.
Framework7
И мы, наконец, подходим к самому главному, чтобы не забивать себе голову решением таких проблем, а получить сразу готовый инструмент для разработки быстрых, отзывчивых и функциональных html5 приложений, существует Framework7. Сам я с ним столкнулся совершенно случайно, и удивился тому, насколько он прост в использовании без необходимости искать решения в разных местах, достаточно просто подключить framework7.js.
Стоит отметить, что для работы с Framework7 не нужно использовать какие-то сторонние модули или библиотеки, так как он всё уже содержит:
- High-performance Animation — хочется выделить это отдельно, так как анимации и правда очень быстрые
- fast-clicks — решает проблему задержки 300мс без сторонних библиотек
- Template7 — движок шаблонов, синтаксис как у Handlebars, но меньше весит и скорость до 3х раз быстрее
- Dom7 — более быстрая и прозрачная замена jQuery
- Navigation / Router — множество вариантов переходов и их контроля
- Поддержка стилей, включая частичную поддержку material design
- Огромный список встроенных компонентов, таких как forms, buttons, list view, pull to refresh, infinite scroll, slide menu итд
- Свайпы — встроенные свайпы на все случаи жизни: вызвать меню свайпом, возврат к предыдущему экрану, удалить элемент итд
- И множество других полезных вещей
На сайте есть огромное кол-во примеров (работают в браузере), инструкций и обучающих статей (например, работа Framework7 совместно с AngularJS)
www.idangero.us/framework7
Пример приложения

Чтобы далеко не ходить, создадим небольшое приложение-пример, где можно будет посмотреть, как объединить отдельные компоненты фреймворка в единое приложение. Будем использовать slide menu, pull to refresh, infinite scroll, смену material/ios style на лету и огромным списком на 8000 элементов, который не тормозит (virtual list).
Структура приложения довольно простая:
- index.html — дизайн приложения
- about.html — дизайн другого view
- app.js — файл инициализации и настроек приложения
- css/app.css — этот файл в общем-то не нужен, так как в framework7.css есть уже все настройки дизайна, но можно, например, сменить цвет фона бокового меню
- lib/framework7.js — сам фреймво��к
- lib/framework7.css — дизайн всех элементов и компонентов в стиле ios
- lib/framework7.material.css — дизайн всех элементов и компонентов в стиле material
Больше ничего не потребуется, другие библиотеки или фреймворки для создания приложения не нужны. Но при желании можно использовать require.js, angular.js, matreshka.js итд.
index.html
Для начала рассмотрим каркас index.html:
Добавление компонентов очень просто реализовано (для каждого компонента есть инструкция на сайте), например, чтобы добавить pull-to-refresh, достаточно добавить в
класс pull-to-refresh-content, и дизайн стрелочки, которая будет показываться при обновлении:
Теперь надо добавить table view (list view), в котором будет список наших элементов. Для создания коротких списков подойдет List View (Media List итд, список можно создавать статически или динамически):
Но для очень длинных списков требуется выгрузка элементов, которые сейчас не видны на экране, это необходимо для того, чтобы ничего не тормозило, и приложение работало как и нативное. Такий список называется Virtual List, и создается так же просто:
В дальнейшем список надо будет проинициализировать и заполнить в app.js
Сюда же добавим infinite-scroll, который добавляет так же, добавлением одноименного класса, дизайна крутилки и указанием начиная с какого расстояния вызывать infinite-scroll:
Чтобы сменить ios стиль на material стиль и наоборот, добавим 2 кнопки, например, в левом меню:
Позже на класс changestyle повесим обработчик, чтобы реагировал на нажатие и менял css файл на указанный в rel.
<!DOCTYPE html>
<html>
<head>
<!-- Добавляем необходимые meta-тэги -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<title>My App</title>
<!-- подключаем framework7 стили, и добавляем id, чтобы можно было менять стиль на лету -->
<link id="pagestyle" rel="stylesheet" href="lib/framework7.css">
<!-- подключаем наши кастомные стили -->
<link rel="stylesheet" href="css/app.css">
</head>
<body>
<!-- statusbar-overlay для правильной поддержки полноэкранного режима -->
<div class="statusbar-overlay"></div>
<!-- тоже самое для panel -->
<div class="panel-overlay"></div>
<!-- если нужно левое боковое меню с reveal эффектом -->
<div class="panel panel-left panel-reveal">
</div>
<!-- самое главное, добавляем views -->
<div class="views">
<!-- главный экран, должен содержать класс view-main -->
<div class="view view-main">
<!-- если требуется верхняя панель, так же указываем что у нее будет белая тема -->
<div class="navbar theme-white">
</div>
<!-- собственно содержимое страницы, указываем что navbar и toolbar будет зафиксированы -->
<div class="pages navbar-through toolbar-through">
<!-- в data-page указываем название страницы, которое желательно для всех страниц быть разным -->
<div data-page="index" class="page">
<div class="page-content">
</div>
</div>
</div>
<!-- если нужная нижняя панель -->
<div class="toolbar">
<div class="toolbar-inner">
</div>
</div>
</div>
</div>
<!-- подключаем framework7 и наш файл инициализации -->
<script type="text/javascript" src="lib/framework7.js"></script>
<script type="text/javascript" src="app.js"></script>
</body>
</html>
Добавление компонентов очень просто реализовано (для каждого компонента есть инструкция на сайте), например, чтобы добавить pull-to-refresh, достаточно добавить в
<div class="page-content">
</div>
класс pull-to-refresh-content, и дизайн стрелочки, которая будет показываться при обновлении:
<div class="page-content pull-to-refresh-content">
<div class="pull-to-refresh-layer">
<div class="preloader"></div>
<div class="pull-to-refresh-arrow"></div>
</div>
</div>
Теперь надо добавить table view (list view), в котором будет список наших элементов. Для создания коротких списков подойдет List View (Media List итд, список можно создавать статически или динамически):
<div class="list-block media-list"><ul>тут данные</ul></div>
Но для очень длинных списков требуется выгрузка элементов, которые сейчас не видны на экране, это необходимо для того, чтобы ничего не тормозило, и приложение работало как и нативное. Такий список называется Virtual List, и создается так же просто:
<div class="list-block virtual-list media-list">тут оставить пусто</div>
В дальнейшем список надо будет проинициализировать и заполнить в app.js
Сюда же добавим infinite-scroll, который добавляет так же, добавлением одноименного класса, дизайна крутилки и указанием начиная с какого расстояния вызывать infinite-scroll:
<div class="page-content pull-to-refresh-content infinite-scroll" data-distance="100">
<div class="pull-to-refresh-layer">
<div class="preloader"></div>
<div class="pull-to-refresh-arrow"></div>
</div>
<div class="list-block virtual-list media-list"></div>
<div class="infinite-scroll-preloader">
<div class="preloader"></div>
</div>
</div>
Чтобы сменить ios стиль на material стиль и наоборот, добавим 2 кнопки, например, в левом меню:
<div class="list-block left-menu">
<div class="row theme-white" style="width:90%;margin-left: auto;margin-right: auto;">
<div class="col-50">
<a href="#" class="button changestyle" rel="lib/framework7.css">iOS style</a>
</div>
<div class="col-50">
<a href="#" class="button changestyle" rel="lib/framework7.material.css">Android style</a>
</div>
</div>
</div>
Позже на класс changestyle повесим обработчик, чтобы реагировал на нажатие и менял css файл на указанный в rel.
app.js
Теперь рассмотрим файл app.js, в котором производится настройка приложения, инициализация списков итд.
// Инициализируем движок фреймворка
var myApp = new Framework7({
animateNavBackIcon:true,
pushState: true, //при переходе между экранами, чтобы работала кнопка back на android
modalTitle: "MyApp",
modalButtonCancel: "Отмена", //текст Cancel кнопки
swipePanel: 'left', //включаем левого меню свайпом
});
// если запускается на ios, то кнопки back нету, и поэтому можно отключить
if (Framework7.prototype.device.os == "ios")
myApp.params.pushState = false;
// вместо jQuery используем встроенный Dom7, переменную можно назвать $, чтобы было привычнее, но если оставить $$, то в дальнейшем можно будет легко подключить jQuery, если понадобится
var $$ = Dom7;
// по клику меняем css файл, меняя ios и material стиль. Выбор запоминаем в localStorage, чтобы при перезапуске приложения загружался нужный css
$$(".changestyle").click(function() {
$$("#pagestyle").attr("href",$$(this).attr('rel'));
localStorage.setItem("css", $$(this).attr('rel'));
return false;
});
// при первой загрузке загружаем запомненный css
if(localStorage.getItem("css")) {
$$("#pagestyle").attr("href",localStorage.getItem("css"));
}
// инициализируем главную вьюху
var mainView = myApp.addView('.view-main', {
dynamicNavbar: true,
domCache: true, //чтобы навигация работала без сбоев и с запоминанием scroll position в длинных списках
});
// инициализируем и заполняем вирутальный список используя шаблон (один из вариантов использования Template7)
var myList = myApp.virtualList('.list-block.virtual-list', {
items: [
{
id: 1,
title: 'Item 1',
picture: 'http://lorempixel.com/88/88/abstract/1'
},
{
id: 2,
title: 'Item 2',
picture: 'http://lorempixel.com/88/88/abstract/2'
}
],
height:44,
template:
'<li class="contact-item" data-id="{{id}}" >' +
'<a href="about.html" class="item-link">' +
'<div class="item-content">' +
'<div class="item-media"><img src="{{picture}}" width="22"></div>' +
'<div class="item-inner">' +
'<div class="item-title">{{title}}</div>' +
'</div>' +
'</div>' +
'</a>' +
'</li>'
});
// пример функции, которая будет обновлять содержимое виртуального списка
function reloadTable(table, array)
{
table.items = array;
table.update();
}
// заполним виртуальный лист 20 новыми элементами
var itemsArray = [];
function firstInitList(text, count)
{
itemsArray = [];
for (var i = 0; i < count; i++ )
{
itemsArray.push({ id: i, title: text + ' ' + i, picture: 'http://lorempixel.com/88/88/abstract/' + i });
}
}
firstInitList("Item", 20);
reloadTable(myList, itemsArray);
// инициализируем pull-to-refresh
var ptrContent = $$('.pull-to-refresh-content');
ptrContent.on('refresh', function (e) {
// Эмулируем 0.5секундную задержку
setTimeout(function () {
refreshIt();
}, 500);
});
// просто случайные данные для генерации виртуального листа
var authors = ['Beatles', 'Queen', 'Michael Jackson', 'Red Hot Chili Peppers'];
function refreshIt()
{
// первые 10 элементов создадим с надписью Refresh
firstInitList("Refresh", 10);
myList.deleteAllItems();
myList.appendItems(itemsArray);
// остальные 8000 случайным образом
var temparr = [];
for(var i = 0; i<8000; i++)
{
var picURL = 'http://lorempixel.com/88/88/abstract/' + Math.round(Math.random() * 10);
var author = authors[Math.floor(Math.random() * authors.length)];
temparr.push({ id: i, title: author, picture: picURL });
}
myList.appendItems(temparr);
myApp.pullToRefreshDone();
}
// инициализируем infinite-scroll
$$('.infinite-scroll').on('infinite', function () {
loadMore();
});
// флаг
var loading = false;
//прячем крутилку infinite-scroll'а
$$('.infinite-scroll-preloader').hide();
function loadMore()
{
// если уже загружаем данные, то ничего не делаем
if (loading) return;
$$('.infinite-scroll-preloader').show();
// Эмулируем 1 секундную задержку
setTimeout(function () {
for (var i = lastIndex + 1; i <= lastIndex + itemsPerLoad; i++) {
itemsArray.push({ id: i, title: 'Item ' + i, picture: 'http://lorempixel.com/88/88/abstract/1' });
}
reloadTable(myList, itemsArray);
// сбрасываем флаг, после загрузки данных
loading = true;
}, 1000);
}
app.css
// дизайн крутилки для infinite-scroll
.infinite-scroll-preloader {
margin-top:-20px;
margin-bottom: 10px;
text-align: center;
}
.infinite-scroll-preloader .preloader {
width:34px;
height:34px;
}
// сменим цвет фона navbar
.navbar {
border-bottom: none;
background: #2196f3;
color: #ffffff;
}
.navbar a.link {
color: #ffffff;
}
// сменить цвет фона левого меню
.panel, .left-menu .list-button {
background-color: #3f4041;
}
.left-menu .item-link.list-button {
text-align: left;
}
В итоге получается очень отзывчивое, легкое и быстрое html5 приложение, которое можно использовать как и где угодно.
Ускоряем html5 приложения на старых версия android. Crosswalk
Хоть у нас и получилось очень быстрое и легкое приложение, на старых версиях андроид оно всё равно будет недостаточно производительным.
Дело в том, что на версиях андроид до 4.4 используется очень тормозной webview (убедиться в этом можно, например, если на 4.1 андроид поставить chrome beta и запустить приложение в нём, а потом сравнить с тем, что есть во встроенном браузере, то разница в скорости будет очень заметна). Поэтому, если просто запаковать html5 приложение в apk, оно будет использовать именно встроенный тормозной webview.
Только начиная с 5.x андроида, webview обновляется отдельно и базируется на свежем chromium, благодаря чему html5 приложение будет работать быстро и плавно.
Проще говоря, если нужна хорошая производительность от html5 приложения на любых устройствах и любых версиях андроид, нужно чтобы оно работало на chromium движке. Проект, который позволяет это сделать, называется crosswalk и вместо встроенного webview используется свой собственный, который работает на последней версии chromium.

Самый простой способ проверить как ваше html5 приложение будет работать с использованием crosswalk, это установить Intel XDK, создать пустой «Standart HTML5» проект, и заменить в созданном проекте папку www на вашу.
После этого выбрать Build и нажать на Crosswalk for Android. Приложение будет скомпилировано на удаленном сервере, и спустя несколько минут вы получите ссылку на apk (версия для arm и x86). К минусам можно отнести тот факт, то размер приложения увеличится на ~19мб.
Сайт framework7: www.idangero.us/framework7
Онлайн пример готового приложения: comedian-ant-73047.bitballoon.com (так как онлайн, то немного тормозит загрузка стилей)
Исходники: yadi.sk/d/Quu2VfApgcGXA
Готовые apk файлы, созданные через Intel XDK: yadi.sk/d/marrZA5-gcGuQ
Онлайн пример большинства возможностей (kitchen-sink): framework7.io/kitchen-sink-ios или framework7.io/kitchen-sink-material
Тоже самое в material дизайне: poacher-bear-12003.bitballoon.com/kitchen-sink-material/index.html
