WebアプリケーションをiPhoneに対応させるための技術メモ
はじめに
iPhone 3G DevWikiという開発情報サイトに基本的な情報がまとまっています。まず最初にこちらに目を通してください。
本エントリでは、新規にiPhone対応のWebアプリケーションを作るというより、既存のWebアプリケーションをいかにしてiPhoneに対応させるかを中心にして話を進めます。
どう対応するか
既存のWebアプリケーションをiPhone対応させるには、大きく分けて二つの方法があります。
- 既存のHTML生成コードを利用する
- スクラッチでiPhone専用のHTML生成コードを書く
(1)の方法では、JSPなどのHTML生成コードをそのまま利用しますが、iPhone Safariからリクエストされた場合にのみ、追加でiPhone専用のCSSをロードします。不必要なヘッダやナビゲーションは、CSSで適宜display:noneを指定することで非表示にします。必要ならHTML生成コードにも手を加えますが、その際、UserAgentを見てiPhone Safariかどうか判別して処理を分岐させます。この方法は実装の工数を最小限にできるというメリットがありますが、生成されるHTMLが巨大な場合や高負荷のJavaScriptが評価される場合は、高い確率でパフォーマンスの問題が持ち上がることになります。
(2)の方法では、新規でiPhone専用のHTML生成コードを書きます。既存のHTML生成コードを汚すことなく対応できるためソースコードの可読性や保守性が向上します。さらに刷新されたスリムなHTMLになるのでパフォーマンスの問題も最小限に抑えられます。言うまでもありませんが、この方法のデメリットは工数の肥大化です。実装の工数が膨らむのは当然ですが、(1)の方法と比べてメンテナンスやテストの工数も膨らみます。というのも、(1)の方法では、同じコードベースを利用しているので、機能追加やバグ修正、テストなどの結果はある程度自動的に反映されます。一方、(2)の方法では、元のコードベースに機能追加やバグ修正が入るたびに、iPhone専用のHTML生成コードも修正しなければなりません。
どちらが優れた選択かは一概には言えません。以下を参考にして選択してください。
(1)を選ぶ理由:
- (ある程度)工数を抑えられる
- 実装
- 機能追加
- バグ修正
- テスト
- すばやい対応が必要
(2)を選ぶ理由:
- パフォーマンス
- 分業
- 既存のHTML生成コードが小さいかシンプル
- よりiPhoneに特化
ビューポートの決定
どう対応するか決定したら、つづいてビューポートについて考えなければなりません。ビューポートとは、iPhone Safariの画面表示に関するメタタグで、画面サイズやズームの可不可を指定します。詳しいビューポートに関する解説は上記のWikiを参考してください。
まず考えなければならないのが、ズームが可能かどうかです。一般的にはズームが必要なユーザーインターフェースは劣っていると言えるのですが、前節で(1)の方法を選択している場合はその限りではありません。PCに最適化されたページというのは何らかの方法でうまく表示しない限りどうしてもはみ出てしまうのです。そうした時に応急処置的にズームを可能にしてしまうのはありかもしれません。
また画面サイズに関しても考える必要があります。ズームが不可能で、普通のiPhoneアプリケーションと同様の使い勝手を目指すのなら、幅320pxぐらいで固定するのがベストです。ただ、ズームが可能な場合や、画像のサムネイルなど巨大なビューポートが必要な場合は、その限りではありません。
どちらにしても初めに決定したビューポートを後から変更するのは大変なので慎重に決定してください。
ページ遷移の方法
PCとiPhoneのブラウザで大きく異なるのは画面サイズです。前節で(1)の方法を選択した場合は特にそうなのですが、表示する内容をうまく縮小したり不要な要素を削ったりしなければ、ほとんどのページはiPhoneで表示するのに最適なサイズには収まりません。そこで1ページを複数のページに分割する方法が有効になりますが、その際、どのようにページ遷移させるかが問題になります。おそらく一般的な方法は以下の二つでしょう。
- 通常のページ遷移(単純リンク)
- JavaScriptによる疑似ページ遷移
(1)の方法では遷移先のページのURLをaタグなどでリンクすることでページ遷移を実現します。この方法は非常に簡単ですが、次のデメリットが伴います。
- HTTPの通信が発生(パフォーマンス問題)
- ページの状態が失われる
(2)の方法では、JavaScriptで要素の位置を変更することにより、擬似的なページ遷移を実現をします。この方法は(1)の方法のデメリットが解消されますが、次の新たなデメリットが伴います。
- ブラウザの「戻る」で戻れない(専用のインターフェースが必要)
- コードの複雑化
UiUIKitというライブラリを使えば、(1)の方法に基づいたiPhone風のページを簡単に作成できます。
UiUIKit: http://code.google.com/p/iphone-universal/
また、iUIというライブラリを使えば、(2)の方法に基づいたiPhone風のページを簡単に作成できます。
iUI: http://code.google.com/p/iui/
ただ、この二つを同時に実現するのは現状では独自に対応するしかないようです(*)。
(*) jQTouchなら可能かも… http://www.jqtouch.com/
例えばWebアプリケーションでよくあるのは、トップページから商品一覧のページに遷移するのにはaタグを使って、商品一覧のページで各商品の詳細を閲覧するのには疑似ページ遷移を使いたい、というケースだと思いますが、現状ではこのようなケースに簡単に対応する方法はないようです。
もし、ちゃんとした疑似ページ遷移(*)を使いたいなら、独自に簡単に実装してしまうのをお勧めします。僕もそうしました。ページのdisplayスタイルを変更するコードとナビゲーションスタックさえ実装すれば、結構簡単にそれっぽく動かすことができます。ちなみにページ遷移をアニメーションさせるのはお勧めしません。JavaScriptでやってもCSS Transformを使っても、現状では滑らかにアニメーションされないからです。カクカクするぐらいならdisplayスタイルで表示/非表示を切り替えるほうが素直で、ユーザーにとっても良いでしょう。
(*) iUIは動的にページ遷移を生成することができません
スクロールの対応
iPhone Safariの仕様を注意深く調べれば分かりますが、iPhone Safariではインナーフレームなどの内部要素を一本指でスクロールすることができません。ここで内部要素といっているのは、ページの大きさに関係なく、要素の内部でスクロールを可能にしている要素です。以下に例を示します。
<div style="height: 100px; overflow: scroll"> <p style="height: 300px"> スクロール可能な長い文章… </p> </div>
一般的なブラウザではこのdiv要素に対してスクロールを発行できますが、iPhoen Safariではdiv要素に対するスクロールとは見做されずページ自体のスクロールと見做されます。一応、このような要素でも、二本指でタッチすることでスクロールすることができますが、ほとんどのユーザーはこの方法を知らないと思ったほうが良いでしょう。
このようなケースには現状では以下のように対応するしかありません。
- heightスタイルやoverflowスタイルを取り除いてページの高さに反映させる
- 疑似ページ遷移を使う
- touchイベントを処理する
可能な限り(1)と(2)の方法で対応してください。どうしても内部要素のスクロールが必要な場合には(3)の方法をとってください。その場合はtouchイベントを処理するJavaScriptコードを自分で書く必要があります。(3)に対応するために僕が作った簡単なライブラリを本エントリに添付しておきます。このライブラリを使えば上記の例も対応できます。
<div id="container" style="height: 100px; overflow: scroll"> <p style="height: 300px"> スクロール可能な長い文章… </p> </div> <script type="text/javascript"> Touch.scrollable(document.getElementById('container')); </script>
その他の問題
基本的に上記したことを考慮しておけば案外簡単にちゃんとしたiPhone対応サイトを作ることができます。CSSやLocal StorageなどのWebKit拡張をフルに活用すればさらに効率的に作ることができるでしょう。
本エントリの締め括りとして、僕がはまったiPhone Safari特有の問題を紹介しておきます。
1. offsetWidth, offsetHeightが取得できない問題 iPhone Safariではdisplay:noneな要素のoffsetWidth, offsetHeightが正しく取得できません。一度、display:blockなどに変更してoffsetWidth, offsetHeightを取得した後に、display:noneに戻すなどの対応が必要ですが、prototype.jsを使っているならElement.getDimensions()がその問題を吸収してくれます。
2. onclickの問題 onclick="return false"という字面があるaタグをクリックすると、なぜかはよくわかりませんが、hrefで指定されたページに遷移してしまいます。この問題に対応するために、aタグのhrefにjavascript:void(0)と書くか、onclick="return false"ではなくonclick="return !!false"と書く必要があります。
ちょっと後味が悪いですが参考になれば幸いです。
- Category(s)
- javascript
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/matsuyama/iphone-webapp-memo/tbping
UiUIKitはライセンスに注意
これは GNU Affero GPL (AGPLv3) というライセンスのソフトウェアです。
http://ja.wikipedia.org/wiki/Affero_General_Public_License
このライセンスは、Webアプリケーションのユーザーに対しても
完全なソースコードを提供可能にしておくことを要求するものなので、
ビジネスとして使用する場合は注意が必要でしょう。