解像度に依存しないモバイルユーザーインターフェース
2010/08/24 by yuki
この記事は8/23に掲載された「Resolution Independent Mobile UI」を訳したものです
…または… ピクセルはピクセルじゃないんです。
「SASSとCSS3のメリット(the benefits of SASS and CSS3)」(英語、未訳)という記事の中で、解像度に依存しないユーザーインターフェースを実現するためにSencha Touch内で活用しているテクニックについて簡単に解説しました。今回の記事では、読者がUI開発を行う際に役に立つように、そのテクニックについてもう少し詳しく解説してみたいと思います。

概要
この記事はアダプティブなレイアウトや、レスポンスの良いWebデザインについてのものではありません。この記事は、デザイナーにとって比較的新しい関心事となった、「ピクセル密度」に注目したものです。モバイル環境において、画面の解像度は急速に進化しています。その結果PPI(ピクセル数/インチ)がどんどん大きくなっています。
例えば、上の画像をご覧ください。これは同じページを同じブラウザで、ただしiPadとiPhone4で描画したものです。iPhoneに描画されたボタンが小さく見えることに気が付くでしょうか?これはiPadのピクセル密度が132ppiなのに対してiPhone4のRetinaディスプレイが326ppiとなっているからです。ただしiPhone4では解像度を自動的に補正するので実際は163ppi相当と考えることができます。これでもiPadと比べると15%もピクセル密度が高いため、ボタンの実際のサイズは15%小さくなるわけです。
クロスプラットフォームなモバイルアプリケーションをデザインする場合には、主に下記の2つの理由から、このピクセル密度について注意する必要があります:
- ボタンを132ppi(iPadなど)向けにデザインした場合、より高いppiを持つ機器上では小さく表示されてしまい、タップが困難だったり、最悪の場合タップできないほど小さくなる可能性があります。
- 解像度が変わっても、画像やUI部品の表示がギザギザになったり滲んだりしないようにスケールさせる必要があります。
基本的な考え方
このテクニックの基本的なコンセプトは、全てのインターフェース要素のサイズ設定単位に、活字の相対的なサイズを表す単位である「em」を利用することにあります。emについてWikipediaから引用すると:
『この単位は現在使用されているフォントのポイントサイズとの相対的な縦横のサイズを表します(中略)この単位は何か特定の書体に対して定義されているわけではないため、任意のポイントサイズにおいて全てのフォントに対して同じ大きさとなります。つまり16ポイントの書体における1emは必ず16ポイントになるということです。』
font-sizeはCSSにおいて子要素に継承されるプロパティであるため、emを使ってサイズを設定した任意の要素について、その親要素のfont-sizeを変更することにより子要素のサイズを変更することが可能となります。
シンプルな例:ボタン
シンプルなボタンを使って、このコンセプトを実践に移してみましょう。
.button {
display: inline-block;
color: #fff;
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#C1FA3B), color-stop(0.02, #8FCA05), to(#5A7F03));
-webkit-border-radius: .2em;
-webkit-box-shadow: #7EB105 0 0 .03em 0.03em inset, rgba(0, 0, 0, 0.4) 0px 0.1em .2em;
text-shadow: rgba(0,0,0,.2) 0 .05em .02em;
border: .08em solid #374D02;
padding: .2em .6em;
}
上記コードでは、ラウンドコーナー、光沢(-webkit-box-shadowでinsetを指定))、ドロップシャドウ、テキストシャドウ、パディング設定のサイズ指定オプションにおいて「em」を単位として使っています。 background-gradientは唯一emを使っていませんが、これは色の変化の指定にパーセント指定が必要だからです。ただし、この色の変化についてもボタンサイズと相対的なものであるため、これらの値も結果的にはフォントサイズを継承したものとなります。
サイズの異なるボタンを実現するためには、下記のようなクラスを追加するだけです:
.size_2x {
font-size: 200%;
}
.size_8x {
font-size: 800%;
}
HTMLは下記の通り:
<a href="#" class="button">1×</a>
<div class="size_2x">
<a href="#" class="button">2×</a>
</div>
<div class="size_8x">
<a href="#" class="button">8×</a>
</div>
この後のサンプルでもsize_2xとsize_8xクラスを使用していきます。
Webkitベースのブラウザ(ChromeやSafari)でこのサンプルを見る。
注意:文字サイズだけを変える場合
上記方法で唯一困るのは、実際にfont-sizeだけを変更して、他の部分のサイズを変更したくない場合です。こういった場合には、要素の中にラッパーとなるdivやspanを挿入することで解決できます:
<a href="#" class="button"><span class="textsize_2x">2× text</span></a>
画像とマスク
このテクニックは画像にも適用可能です。一般的な画像ファイルに対しては、widthあるいはheightをemあるいはパーセントで指定するだけです(もう片方は縦横比を保つ値に自動的に設定されます)。貼付ける画像は、スケールダウンして様々なサイズに利用可能なように、解像度が高いものである必要があります(必ずスケールダウンして使われるようにする必要があります。スケールアップするとギザギザが発生してしまいます)。
.imgbase {
width: 4em;
}
HTMLは以下の通り:
<img class="imgbase" src="duck.jpg" />
<div class="size_2x">
<img class="imgbase" src="duck.jpg" />
</div>
<div class="size_8x">
<img class="imgbase" src="duck.jpg" />
</div>
画像と同様に、背景画像やマスクに対しても同じサイズ指定が可能です:
li {
background: url(resources/duckbullet.png) 0 .3em no-repeat;
background-size: 1em auto; // widthを1emに設定、heightは自動設定
}
このテクニックのメリットは、異なる機器上であっても画像が同じサイズで表示されることと同時に、高い解像度をサポートする機器上では高めの解像度で表示されるということです。
ただし、注意しないといけないのは、これらの画像は実際には「解像度非依存」ではないということです。解像度に依存しないというコンセプトをビットマップ画像に適用するということがそもそも矛盾しているからです。上の例でも、画像がスケールダウンされることを前提として大きめの画像を用意しました。画像がスケールアップされたらギザギザが表示されることになります。他にも帯域を無駄に使ってしまうという副作用があります。必要なサイズより大きめの画像を転送することで、無駄なデータを常に転送していることになります。
Webkitベースのブラウザ(ChromeやSafari)でこのサンプルを見る。
SVGで解決
SVGはベクター画像のためのW3C仕様(英語)であり、WebKitでは既に実装されています(一部のバージョンでは未実装)。SVGはベクターデータであるため、画像の品質を損なうことなく無限にスケールさせることが可能です。アイコン、ロゴ、その他の(ビットマップを使わない)UI要素にとっては最適のオプションです。
.logo {
width: 2em;
margin-bottom: 20px;
}
.size_2x {
font-size: 200%;
}
.size_8x {
font-size: 800%;
}
HTMLは下記の通り:
<img class="logo" src="sencha.svg" />
<div class="size_2x">
<img class="logo" src="sencha.svg" />
</div>
<div class="size_8x">
<img class="logo" src="sencha.svg" />
</div>
* 残念ながらAndroidではSVGがまだ実装されていないため、Sencha Touchではこのテクニックは使っていません。
Webkitベースのブラウザ(ChromeやSafari)でこのサンプルを見る。
コミュニティサンプル:ローディングインジケーター
Jordon Dobson氏はこのテクニックを使って作った素晴らしいCSS3ベースのローディングインジケーター公開しています。デモページをチェックしてみてください。インジケーターのサイズを大きくしたり小さくしたりできます(これまで見てきたように、親要素のfont-sizeを変化させているだけです)。
機器ごとにサイズを変える
UI要素やレイアウトの全てをemおよびパーセントで設定できるようにしたら、bodyタグにfont-sizeを適用することによってページ全体のスケールを変更できるようになります(これまでは、設定したい要素の親要素のfont-sizeを設定してきました)。現在、Sencha TouchではJavaScriptで取得できるユーザーエージェント情報を使って機器判別を行った後で、bodyタグに適切なクラスを追加しています。機器に応じたクラスが追加されることで、UIの解像度も最適なものに調整されます:
body {
font-size: 100%; // 一番低いピクセル密度に対応(iPadの132ppi)。
}
body.x-iphone-os.x-phone {
font-size: 114%; // iPhoneの163ppiに対応。
}
body.x-android-os.x-phone {
font-size: 120%; // 多くのAndroidで採用されている180ppiに対応。
}
将来:@mediaクエリー
将来的には、上記の様にJavaScriptを使うのではなく、CSS3のmediaクエリーを使ってCSSだけで機器の解像度を検知し調整するのが理想的な方法です。これを実現するためにCSS3に提案されているresolution属性があるのですが、iOS、Androidのいずれにもまだ実装されていません:
@media screen and (min-resolution: 132dpi) {
body {
font-size: 100%; // 一番低いピクセル密度に対応(iPadの132ppi)。
}
}
@media screen and (min-resolution: 160dpi) {
body {
font-size: 114%;
}
}
@media screen and (min-resolution: 180dpi) {
body {
font-size: 120%;
}
}
// 上記は、まだ、できません
iOSに最近追加されたmediaクエリーのdevice-pixel-ratioは注目に値するかもしれません。 この記事の冒頭でも述べたように、Retinaディスプレイを装備するiPhone 4では、ウェブページのピクセルを自動的に2倍にスケールします。下記のクエリーを使えばRetinaディスプレイの有無を確認できます:
@media screen and (-webkit-min-device-pixel-ratio: 2) {
// Retinaディスプレイに対応したCSS
}
Aral Balkan氏は「How to make your web content look stunning on the iPhone 4’s new Retina display」(英語)の中でこのルールを活用するための方法について素晴らしい考察を提供してくれています。
Webkitベースのブラウザ(ChromeやSafari)でこのサンプルを見る。
結論
機器のピクセル密度が高くなるにつれて(iPadもRetinaディスプレイを搭載するという噂がありますよね?)、解像度に依存しないUI要素を作るための方法も重要性を増してきています。この記事で紹介した、emやパーセントの利用はそのための方法の1つであり、今のところ一番最適な方法だと考えています。ただ、もし他にもっと良い方法が存在したり、あるいはCSS3の仕様変更があるのであれば、ぜひ教えてください。








Posted on November 30th, 2011 at 4:29 am
Simply desire to say your article is as astounding. The clearness for your publish is simply spectacular and that i can think you are a professional in this subject. Fine with your permission let me to snatch your feed to keep up to date with impending post. Thank you a million and please continue the rewarding work.