はじめまして。
サイバーエージェントでフロントエンドの開発をしております 原(@herablog) です。

今回は、「HTML5 Web Applicationのつくりかた」と題してスマートフォン版 アメーバピグ新規作成で使用した技術について触れたいと思います。
#ちなみにこの記事ではHTML5を「最新ブラウザ向けのwebアプリケーション作成技術」というかなり広い解釈で使用していますので予めご理解ください。

今までDesktop・Android向けはFlashで作成されていたのですが、今回はiOS, Androidともに対応したいということで、HTML5でできるところまでやってみることにしました。

1 pixel|サイバーエージェント公式クリエイターズブログ-pigg新規作成 for mobile1 pixel|サイバーエージェント公式クリエイターズブログ-pigg新規作成 for mobile

No Lag

作るにあたり大事にしたものは、とにかく速さ。特に、選択してからの待ち時間をなくし、ユーザーのストレスを軽減することを目標としました。

さっそく問題が・・・

しかし、さっそく大きな問題にぶちあたりました。アメーバピグのアバターは型・色合わせて全部で約1700種類のパーツの組み合わせでできています。これだけ多くの種類から選べるからこそ自分そっくりのアバターを作成できるのですが、データサイズの面からは問題となってしまいます。どうやってアバターを描くか、しかも速くストレスなく、といった方法を探す必要があったのです。
1 pixel|サイバーエージェント公式クリエイターズブログ-Piggはたくさんのパーツから成り立っています1 pixel|サイバーエージェント公式クリエイターズブログ-Piggはたくさんのパーツから成り立っています

4つの方法

最適な方法を探すため、4つの方法を試してみました。

1. Image
◯ すでにパーツが用意されていて実装が簡単。
× パーツ数が多すぎて一度にダウンロードできない。必要時にリクエストしてもレスポンスに時間がかかる(特に3G回線では顕著)。

2. CSS Sprites
◯ 画像容量減少。ある程度まとめて先読みできる。
× パーツ数が多いことに変わりなく、すべて読み込んだ時点でメモリを消費しパフォーマンスが悪くなってしまう。

3. SVG
◯ Aiデータとの相性良し。色はcssで変更できるため型のデータのみ所持すればいいので容量削減可能。
× Android非対応...。

4. Canvas
◯ 型、色データともテキスト形式でもてるので容量減少。iOS, Androidともに比較的実装が進んでいる。
× OSのバージョンごとに少々バグあり。うまくいく保証がない。

テストを重ねた結果、今回はCanvasでアバターを描くことにチャレンジすることにしました。

Ai→Canvas

AiデータをCanvasデータに変換するにあたりAi→CanvasというIllustratorプラグインを使用しました。Aiデータを以下のような数値データに変換してくれます。
1 pixel|サイバーエージェント公式クリエイターズブログ-Canvasデータ1 pixel|サイバーエージェント公式クリエイターズブログ-Canvasデータ
これでパーツ(型)データが汎用的に使えるようになりました。

容量激減

さらに容量を削減させるため、すべてのパーツを変換した後、数値データを抜き出し、JSON化しました。すると仮にすべて画像データにする場合(1MB)にくらべJSONデータ (420KB)では53%データサイズを削減することができました。さらにgzip圧縮して転送することで転送量を120KBに、当初に比べ88%削減できました。

容量88%減容量88%減


アバターを描く方法に目処がたったところで、ページの作成に移ります。

控えめなJavaScript

作成にあたり、HTML, CSS, JavaScriptそれぞれの役割を大切にし、JavaScriptに頼り過ぎないように設計しました。

HTML・・・構成する要素を記述
CSS・・・要素をどう表示するか
JavaScript・・・ユーザーアクションに対する動作・処理

もちろん、作ろうとするサイト・アプリケーションにもよりますが、表示内容を変更しようとする際にスクリプトを読む必要がないのは大きなメリットではないでしょうか。今回JavaScriptはページ遷移、アバターの描画を担当しています。

表示要素はHTML1枚で

表示要素は全ページまとめて1枚のHTMLに記述しました。ページごとのリクエストが不要で、遷移時にタイムラグをなくすことができます。

window.onhashchange

ページ遷移にはHTML5で新たに追加されたwindow.onhashchangeを使っています。URLの#以降が変更されたときに指定のページを表示させています。iOS, Androidどちらのブラウザも対応していたこと、サーチエンジンやページキャッシュへの対応が必要なかったため採用しました。

<a href="#eye">次へ</a>をタップ(クリック)
→URLがhttp://~~~.jp/#eyeに変更される
→window.onhashchange, hash = #eyeが起こる
→<div id="eye"></div>を表示させる


Custom Data Attribute

HTML5では「data-」をつけることでHTML属性を設定することができるようになりました。JavaScriptからはgetAttribute, setAttribute, dataset(iOS4.3, Android2.3では未対応)でアクセスでき、CSSからは属性セレクタで指定できます。

今回はdata-parts, data-item2つの値をJavaScriptで取得し、アバターを描画しています。

<ul data-parts="face">
<li data-item="0"></li>
<li data-item="1"></li>
</ul>

Data URI Scheme

Data URI Schemeを使うことで高コストであるHTTPリクエストさせずに画像を表示することができます。画像のバイナリデータをbase64エンコードし、 HTMLもしくはCSSに埋め込みます。

・HTML
<img src="data:image/gif;base64,R0lGODlhTgBOANUAAP////f39+/...">

・CSS
background: url(data:image/gif;base64,R0lGODlhTgBOANUAAP////f39+/...);

今回はローディング画像に使用し、HTMLが読み込まれると同時にいち早く表示させ、ローディング中に画像が出ないことを防いでいます。データサイズが約130%増になってしまうため、すべての画像に適用することが最適ではありませんが、アイコン等小さな画像やCSSによるキャッシュ、gzip圧縮して転送するなど合わせて使用すると効果があります。

Sass

HTML5とは直接関係ありませんが、CSSの記述にSassを使用しました。SassはCSS拡張メタ言語と呼ばれるもので、従来のCSSに構造化、定数・変数、分岐、ループ、関数、Mixinなど強力な機能を追加してくれます。今回はよりCSSに近いSCSSという記法で記述しました。

・構造化
#confirm{
.lead{
margin: 15px 0 0;
font-weight: bold;
text-align: center;
}

.submitArea{
margin: 59px 0 0;
}

・ループ
@for $i from 0 through 6 {
ul[data-parts="face"] li[data-item="#{$i}"] { background-position: removePx((-11 + -$i) * $thumbWidth) removePx(-10 * $thumbWidth); }
}

・関数
@function removePx($v){
@if $v == 0{
@return $v;
} @else {
@return #{$v}px;
}
}

・Mixin
@mixin border-radius($radius: 4) {
-moz-border-radius: removePx($radius);
-webkit-border-radius: removePx($radius);
border-radius: removePx($radius);
}

続いて、今後のWebで重要なトピックスである高速化について、今回実施したことをまとめます。

大前提はHTTPリクエストを減らすこと

Googleが検索順位決定の要素に速度を追加していくと発表したこと、ユーザーの利用時間の奪い合いが激化していること、スマートフォンに代表されるモバイル環境の普及・マルチデバイス化などの理由でWebサイトの高速化はますます重要なトピックスになってきていきます。
Webサイトの速度に関する多くの時間はファイルのダウンロードに費やされています。そのため高速化を考える際にはまずHTTPリクエストを減らすこと、つまりHTML, CSS, JavaScript, 画像ファイル, swf等ファイル数を減らす必要があります。

CSS Sprites

画像のHTTPリクエストを減らす方法として画像をひとまとめにするCSS Spriteがあります。
1 pixel|サイバーエージェント公式クリエイターズブログ-CSS Sprites1 pixel|サイバーエージェント公式クリエイターズブログ-CSS Sprites
CSS でbackground-image, background-positionを指定して表示させます。
また、Data URI Scheme(前述)を使うことも有効な手段です。

画像最適化

PhotoshopやFireworksで書き出された画像データの多くには表示には必要のないデータが含まれています。OptiPNGなどのツールを使うことでそれらのデータを除去し、ファイルサイズを減らすことができます。
今回は約3%(79KB→77KB)データサイズを減らすことができました。

ファイル結合

画像と同様にCSSファイル、JavaScriptファイルを結合することでHTTPリクエストを減らすことができます。今回のプロジェクトでは計7つのファイル(HTML 1つ、CSS 1つ、JavaScript 2つ、JSON 1つ、画像 2つ)に収めています。

Minify

テキスト系のデータは、コメント、改行、空白、タブを削除することでデータサイズを減らすことができます。
1 pixel|サイバーエージェント公式クリエイターズブログ-Minify1 pixel|サイバーエージェント公式クリエイターズブログ-Minify
今回はYUI Compresserを使い、33%(286KB→191KB)データサイズ削減できました。

gzip圧縮

仕上げにgzip圧縮転送の設定をします。こちらはサーバー側の設定になりますが、 Apache, mod_deflateで設定することができます。画像ファイル、pdfファイル等に設定すると容量が増えてしまうことがあるので、テキスト系のデータのみ設定する必要があります。
大体、70%程データサイズを削減することができます。
gzip圧縮で73%削減gzip圧縮で73%削減

トータル

上記の対応をすることで、最初の段階から67% (786KB→246KB)データサイズを減らすことができました。

67%削減67%削減



フルスクリーンモード

最後におまけ機能の紹介です。iOSにはフルスクリーンモードという機能があり、Webアプリをまるでネイティブアプリのように表示させることができます。Safariで表示されるロケーションバー・メニューバーの非表示、ステータスバーの色指定、ロック時もJavaSccriptを動かすことができます。
逆に、[戻る][進む][更新]といったナビゲーションをWeb内に入れ込む必要があります。

フルスクリーンモードフルスクリーンモード

フルスクリーンモードをONするには以下の3行を追加するだけです。

<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="apple-touch-startup-image" href="起動時の画像">

以上、スマートフォン版 アメーバピグ新規作成で使用した技術をご紹介しました。アメーバピグその他の機能も現在開発中です。その際の技術も追ってお伝えできたらと思っています!

勉強会の様子はこちらの記事からどうぞ!
>> クリエイター勉強会でのひとこま