こんばんは。LatLongLabの河合(@inuro)です。
ようやくiPadが日本でも発売されましたね。入手された方もたくさんいらっしゃることかと思います。
ヤフーではこのiPad国内発売にタイミングを合わせ、Yahoo!ラボで「yubichiz」というiPad専用の地図Webアプリを公開しました。
Yahoo!ラボ - yubichiz(ゆびちず)
詳しい機能はリンク先ページを見ていただくとして、
- 地図に書かれた文字(大塚家具、とか紀伊國屋書店、とか)をタップするだけでその店舗の詳細情報が表示されます
- 地図を指でなぞるだけで、なぞったラインの距離を測定できます
- 同様に地図を指でなぞるだけで、道沿いのお店を検索できます
といった特徴があります。
またyubichizは、App Storeからダウンロードするいわゆる「アプリ」ではなく、HTML5を用いてiPadのSafari上で動作するWebアプリとなっています。
今日はyubichizを作る上でいろいろと試行錯誤した内容について、少しご紹介させていただきます。
なぜWebアプリか
そもそも、なぜyubichizをWebアプリで作ろうとしたかといえば、
- 開発サイクルが速い
- リリースサイクルが速い
- 挑戦的である
の3点が挙げられます。
開発サイクルが速い、はWebアプリ全般に言える特徴で、コードを更新すれば即座にブラウザから挙動を確認しフィードバックをもらえます。
アプリケーションやサービスの開発においては、フィードバックサイクルのオーバーヘッドや機能不全が開発コストの大半を占めます。 今回、短い期間で設計・実装のみならずブラッシュアップを行いリリースするためにはWebアプリでなくては困難でした。
また同様にリリースサイクルも、App Storeへの登録・審査・掲載・ユーザによるDLを経るネイティブアプリより遥かに速いことは大きな利点です。
最後に挑戦的であるということですが、これはもう単純に「アプリだと普通だよね」「アプリじゃなくHTMLでどこまでできるんだろうね」「HTMLでアプリみたいだったらいかすよね」というノリと勢いです。制限の中で何ができるのかを模索するのは楽しいですよね。
iPadでのUIデザインで気を付けるべきこと
さてiPadでWebアプリを作ろうと考えた場合、特にUIのデザインでは気を付けるべき点が幾つかあります。
- iPadは大きいiPhoneではない
- 固定サイズ、固定環境
- ステップ数はできるだけ少なく
iPadは大きいiPhoneではない
「iPadなんて大きいiPhoneだろ?」はユーザの視点からはそういう捉え方もありますが、開発者の視点からは明らかに間違いです。
人間の手のサイズ、眼の解像能力が一定である以上、デバイスの大きさの違いは最も本質的な違いです。 電話の設計が耳から口までの距離に拘束されるのと同じです。
iPadの場合は、画面が広いためインタフェースを配置する余地が充分にあります。後述のステップ数の話とも関連しますが、iPhoneではスペースの制限上メニュー→機能選択→さらにオプション、と多段にならざるを得ない操作も、iPadであれば1タップで呼び出せるボタンとして配置することが可能になります。
yubichizではなるべく多くの機能に1タップでアクセスできるように、ボタンをフラットに配置しています。
試しにyubichizをiPhoneで表示すると、以下のようにボタン類がまったく収まりません。iPhone向けとは根本的に異なるUI設計が必要です。
また、マルチタッチのインタフェースはiPhoneでも同様ですが、3.5インチのスクリーンサイズでは実際にはオペレーションのメインはシングルタッチになります。多くの指や両手で操作しようと思っても、指が邪魔で画面が見えません(なおこれがマウスなどの間接ポインティングデバイスと直接ポインティングインタフェースであるタッチの大きな違いのひとつです)。
iPadであれば、左手でモードを指定しながら右手で操作する、といったインタフェースが有効に機能するでしょう。yubichizには「なぞって測定」機能がありますが、これもモード切り替えではなく
- 定規アイコンを左手で押しながら、右手で地図をなぞればその間だけスクロールではなく測定を行う
という操作にすれば、再びモードをスクロールに戻す、という1ステップを省略することができます。
いずれyubichizにも実際に実装したいと思っています。
固定サイズ、固定環境
Webサービスの開発者は、ブラウザウィンドウの大きさが可変である・ブラウザの実装が様々である、という状況にすっかり慣れていると思います。「あのブラウザさえ無ければ」と呟いたことがある方も少なくないと思います。
iPadでの開発は、iPadのSafariだけを対象にすれば良く、またmetaタグを
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=no">
と記述すれば、ビューのサイズもほぼ固定で考えることができます。よって、Safariの実装をフルに生かした仕様で、ブラウザ側のリサイズによるレイアウト崩れなどを気にすること無くインタフェースをデザインすることができます。
例えばyubichizでは、機能を切り替えると左上にこのような帯が斜めに表示され、選択された機能をアナウンスします。
この処理は、CSSで以下のように指定して実現しています。
div#titlewindow{
background-color: #fff;
-webkit-box-shadow: rgba(0,0,0,.2) 1px 2px 4px;
color: rgba(0,0,0,0.7);
text-shadow: rgba(0,0,0,0.3) 0px -1px 1px;
text-align:left;
padding:0.2em 0.5em;
padding-left:64px;
position:absolute;
width:480px;
height:64px;
top:0px;
left:-48px;
z-index:2;
opacity: .7;
-webkit-transform: rotateZ(-15deg);
}
このCSSは、iPadで期待通りに表示されることしかテストしていません。実際Firefoxなどでは斜めになりませんし(-webkit-transformしか指定していないので当然ですが)、透過の具合やフォントもブラウザによって微妙に異なりますが、iPadで良ければそれで良し、としています。
また、帯が表示される位置・サイズも iPadの画面サイズで地図の邪魔にならず、かつなるべく大きく見えるように 最適化されています。
このように、1つの環境での最適化に集中すれば良いというのは、開発サイクルの高速化にも非常に大きな効果があります。
ステップ数はできるだけ少なく
これはiPadに限った話ではなくiPhone、ひいてはタッチインタフェースのプラットフォーム全般に言えることですが、マウスなどで操作するPCよりも 操作の1ステップの重みが遥かに重い です。少しステップ数が多いだけでストレスを強く感じるのは、例えばiPhoneのTwitterクライアントを使い比べた方などは経験されているのではないでしょうか。
タッチはマウスよりも直感的で、狙うとか外すといった要素がほとんどありません。
例えば「ボタンを押す」という操作は1ステップに見えますが、 マウスであれば「カーソルをボタンの位置に正確に動かす」というステップが暗黙の内に含まれています。 しかも大抵は1ストロークで狙った位置に動かせるわけではなく、ミスや微調整がそこに加わります。ところがタッチであれば、狙ったボタンを一発で押すことができます。
つまり動作自体にミスがほとんど介在しないため、マウスより圧倒的に操作のリズムが速くなります。それだけにステップが増えたり、1つのステップに時間が掛かったりすると大きなストレスを感じます。タッチインタフェースのプラットフォームにおいては、 ステップ数の多寡がユーザ体験の良否に直結します。
yubichizでは前述のように機能をなるべくフラットにボタンとして展開し、少ないステップ数でシナリオを実現するように心がけています。
「なぞって測定」も、地図の上で距離を測る最もシンプルな方法は何か、を考えた結果生まれた機能です。
また「ジャンル検索」機能がありますが、これもよく使う検索を2ステップで実行できるようにしてあります。ただ「よく使う検索」は当然ユーザによって異なるので、検索するジャンルを設定できるように改良する予定です。
よりアプリらしい体験のために
iPhone OS(4からはiOSですね)のホーム画面は、1ステップ、遅くとも2・3ステップで主要なアプリにアクセスできるようになっています。
余談ですがこのアプリアクセスへのコストが著しく低いからこそ、iPhoneのアプリはPCのアプリとは異なり単機能アプリが多く、またそれが受け入れられてもいると言えます。
一方Webアプリは、Safariを起動しブックマークボタンをタップしブックマークを選択し(場合によってはスクロールしたりフォルダを追ったり)、と遥かにステップ数は多くなります。ネイティブアプリと同等の体験を提供するためには、Web Clipという仕組みを利用します。
Web Clipに対応するためには
Web ClipはWebページをネイティブアプリの様にユーザに見せることができる仕組みです。
Safariには閲覧中のページをホーム画面に追加する機能がありますが、Web Clipに対応したWebページをホーム画面に追加すると、そこから起動したWebページはSafariのツールバーが表示されず、まるでネイティブアプリの様にフルスクリーンで表示されます。
Safariでの表示
Web Clipでの表示
Web Clipを有効にするためには、以下のmetaタグを記述します。
<meta name="apple-mobile-web-app-capable" content="yes"/>
詳しくはAppleのSafari Web Content Guideを参照してください。
Safari Web Content Guide: Configuring Web Applications
Web Clip化の功罪
Web Clipには様々な利点があります。
- 画面を広く使える
- 不用意な「戻る」「進む」などでページが切り替わる危険がない
- Safariで走らせるよりもちょっと速い(気がする)
最後はあくまで体感でありまだ検証していないのですが、特にSafariで複数ページを開いていると顕著に感じられます。
反面、欠点もあり、特に悩ましいのが
- 別ページに飛ぶリンクをクリックするとWeb Clipが終了しSafariが立ち上がり、そしてWeb Clipに戻るともういちど最初から起動しなおしになる
というものです。
Safariで閲覧している場合は、別ページを立ち上げてもメモリに余裕がある限りは元のページの状態を維持してくれているのですが、Web Clipになるとそこは一切面倒を見てもらえません。
つまりはネイティブアプリと同様の挙動なのですが、Webアプリは一般に前述の様にブラウザが状態を維持してくれることを前提とした実装になっている場合が多く、タスク切り替えが前提のiPhone OSのWeb Clipで快適なユーザ体験を提供するためには考え方を切り替える必要があります。
アプリケーションキャッシュによる高速起動
まず1つに、HTML5のアプリケーションキャッシュの仕組みを用いてデータをローカルにキャッシュし起動を高速化することが効果的です。
Web Clipは毎回最初から起動しなおしになるので、画像やスクリプトなど固定的なファイルはなるべくネットワークからではなくローカルから高速に読み出したいです。
Offline Application Caching APIs - W3C Working Group Note
詳しくは各種サイトを参考にして頂くとして、簡単に説明すると
- MIMEタイプを「text/cache-manifest」としたマニフェストファイルを用意する
- 上記ファイルに、キャッシュさせたいリソース、させたくないリソースなどを記述する
- htmlタグのmanifestアトリビュートに上記ファイルを指定する
することでアプリケーションキャッシュが有効になり、指定されたリソースをローカルに保持するようになります。
yubichizの例をもう少し具体的に見ると、まずマニフェストファイルは以下のようになっています(内容は分かりやすいように一部変更・省略してあります)。
CACHE MANIFEST
# Cache version 0.988
# change the version to invalidate the cache manifest...
NETWORK:
https://map.yahoo.co.jp/
CACHE:
#scripts
jquery.js
ipad.js
#stylesheets
ipad.css
#images
images/ruler.png
images/scroll.png
images/search.png
#で始まる行はコメントです。
CACHE:のラベルに続くファイルがキャッシュ対象とするファイルです。
ここでは使用しているスクリプト、スタイルシート、画像などを軒並み記述してあります。
逆にNETWORK:のラベルに続くファイルは、必ずネットワークから取得することを指示するファイルになります。
ここでは地図のタイル画像は必ずネットワークから取得するように設定してあります。
このファイルを「cache.manifest」というファイル名で保存し、MIMEタイプを適切に設定した上で、htmlファイル冒頭に以下のように記述します。
<!DOCTYPE html>
<html lang="ja" manifest="cache.manifest">
これで、マニフェストファイルが変更されない限り(あるいは設定→Safariから削除されない限り)、指定されたリソースは全てローカルに保持され、高速に読み出されます。
LocalStorageによる状態のシリアライズ
前述の通り、Web Clipはページの状態を一切保持してくれないので、ネイティブアプリと同様の体験を提供するためには自前で状態のシリアライズとデシリアライズを行う必要があります。
実はyubichizはシリアライズにまだ対応できていません。なるべく早期に対応したいと考えています。
シリアライズのバックエンドとしては、LocalStorageを利用します。LocalStorageは「あたしルートラボ」の記事でもご紹介したように、ドメイン単位でユニークなクライアントサイドのKey-Valueストアです。ページを閉じてもデータを保持することができるので、基本的には終了時に状態をLocalStorageに書き出し、起動時にまたLocalStorageから書き戻す、という実装でシリアライズが実現できます(実はそう上手くはいかないことについては後述します)。
yubichizでは状態として、
- 地図の位置、縮尺
- 検索結果データ
- ビューモード(地図、リスト、グリッド)
- 検索モード(AUTO、場所、店舗)
- 操作モード(地図、測定、なぞり検索)
といった辺りを持ちますので、これらのモデルからLocalStorageに格納できる形でデータを書き出します。LocalStrageはKey-Valueストアで単純な文字列の格納しかできませんので、オブジェクトをJSONで書きだすのが適当です。書き出したデータは、起動時にLocalStorageから読み出してevalし値をコピーします。スケルトンとしてはこんな形になります。
var model = {
id: "uniqueid"
,
serialize : function(){
return jsonize(this);
}
,
deserialize : function(jsonstr){
var data = eval("(" + jsonstr + ")");
for(var key in data){
this[key] = data[key];
}
}
}
//起動時
window.onload = function(){
var storage = window.localStorage;
if(storage){
var jsonstr = storage.getItem(model.id);
model.deserialize(jsonstr);
}
}
//終了時
window.onunload = function(){
var storage = window.localStorage;
if(storage){
var jsonstr = model.serialize();
storage.setItem(model.id, jsonstr);
}
}
ここでjsonizeはそれぞれのオブジェクトで実装すべき適切なJSON化メソッドです。
典型的にはtypeofがfunctionではないメンバーについて、JSONとして書き出すことになると思います。
ただし、ここでひとつ問題があります。
現状(2010年6月10日現在) iPhone OSのSafariではbeforeunloadイベントがサポートされておらず、unloadイベントはサポートされていますがWeb Clip化したページでは呼ばれない、 などアプリの終了をフックすることが実は困難です。
よってモデルの状態が変化するたびに都度シリアライズを行うしかありませんが、地図をスクロールするたびに処理を行っていてはUIの軽快性を損ねかねません。快適なユーザ体験のためにはこの辺りをうまくチューニングする必要があります。
おわりに
iPadの大きな画面を得てiPhone OSはようやくその本来のポテンシャルを発揮できたとも言え、iPadでのWebアプリは上述のように制限や課題も多いものの非常に挑戦的で魅力的な分野だと思います。iPhoneではWebアプリの存在感は残念ながらそれほどありませんでしたが、iPadではぜひWebアプリが盛り上がって欲しいと思います。yubichizおよびこの記事がその一助となれれば幸いです。
こちらの記事のご感想を聞かせください。
- 学びがある
- わかりやすい
- 新しい視点
ご感想ありがとうございました