義援金の受付

東日本大震災の
復興支援へのご寄付
をお願い致します。

2. ウェブアプリの画面対応


概略

  • ビューポートのメタデータ、CSS、および JavaScript を使ってウェブページをさまざまな画面に対応させることができます。
  • このテクニックは Android 2.0 以上かつ、デフォルトの Android ブラウザと WebView でレンダリングされるウェブページで動作します。

このドキュメントの内容

  1. ビューポートメタデータの使用
    1. ビューポートサイズの定義
    2. ビューポートスケールの定義
    3. ビューポートの対象密度の定義
  2. CSS を使ったデバイス密度の対応
  3. JavaScript を使ったデバイス密度の対応

Android 用のウェブアプリケーションを開発したりモバイルデバイス用の再設計する場合は、さまざまな種類の画面でのウェブページの外観に細心の注意を払うが必要があります。Android はさまざまなタイプの画面のデバイスで利用できることから、Android デバイスでのウェブページの見せ方に影響を及ぼすいくつかの要因に対して十分な配慮が必要になります。

注意: このドキュメントので説明する仕様は Android 2.0 以上で、Android のブラウザアプリケーション ( Android プラットフォームにデフォルトで提供されている ) と、WebView ( ウェブページを表示するためのフレームワークのビューウィジェット ) によりサポートされます。Android で動作するサードパーティーのウェブブラウザは、ビューポートサイズや画面密度の制御に対し、これらの仕様をサポートしていない可能性があります。

ウェブページを Android デバイス対応にするには、以下の 2 つの基本事項を把握しておく必要があります。

ビューポートのサイズとウェブページのスケール
Android ブラウザがウェブページをロードするときは、デフォルトの振る舞いの "オーバービューモード" でページをロードしますが、これはウェブページをズームアウトした外観を提供します。ビューポートのデフォルトの寸法またはビューポートの初期スケールを定義して、ウェブページに対するこの振る舞いを上書きすることができます。ユーザがズームインやズームアウトできる範囲を完全に制御することもできます。ユーザはブラウザの設定でオーバービューモードを無効にすることもできることから、ページがオーバービューモードで表示されることを前提とすることはできません。その代わりビューポートのサイズをカスタマイズし、かつ ( または ) ページを適切にスケーリングします。

しかしながら、ページが WebView でレンダリングされていると、そのページは最大のズームでロードされます ( "オーバービューモード"  ではありません ) 。つまり、ズームアウトされているのではなく、このページに対してデフォルトのサイズで表示されます ( これはユーザがオーバービューモードを無効にした場合のページでも同じようになります ) 。


デバイスの画面密度
Android 搭載のデバイスの画面密度 ( 1 インチあたりのピクセル数 ) はウェブページが表示される解像度とサイズに影響を及ぼします (  低、中、高の 3 つの画面カテゴリがあります ) 。Android ブラウザと WebView はウェブページをスケーリングし、さまざまな画面密度でも埋め合わせを行うので、 すべてのデバイスで中密度の画面と同じ見た目のサイズでウェブベージが表示されます。グラフィックスがウェブデザインの重要な要素であるなら、イメージのスケーリングが不適切な結果 ( ぼやけたりピクセルがそのまま大きくなる ) になってしまうことから、異なる密度で起こるスケーリングに細心の注意を払うべきです。

すべての画面密度でベストな視覚的表現ができるようにするには、ウェブページで対応する画面密度に関するビューポートのメタデータを提供し、異なる画面密度用の代替グラフィックスを提供する ( CSS や JavaScript を使ってさまざまな画面に適用することができる ) ことによりスケーリングの発生を制御する必要があります。

このドキュメントのここから先では、これらの効果をいかに発揮するのか、またマルチ画面タイプでいかにうまくデザインするかという点について説明していきます。


ビューポートメタデータの使用

ビューポートとは、ウェブページが描画される領域のことです。ビューポートの見える領域が画面のサイズと一致していても、ビューポートにはウェブページで利用できるピクセル数を決定した独自の寸法を持っています。つまり、ウェブページに利用できるピクセル数は、そのウェブページが画面の領域を超えないうちにビューポートの寸法により定義され、デバイスの画面の寸法により定義されるものではありません。例えば、デバイスの画面が 480 ピクセルだとしても、ビューポートは 800 ピクセルの幅にできるので、800 ピクセルの幅でデザインされたウェブページは画面上に完全に見えるようになります。

"viewport" プロパティを HTML の <meta> タグで使用することにより ( これはドキュメントの<head> に置く必要があります ) 、ウェブページ用のビューポートのプロパティを定義することができます。<meta> タグの content 属性にビューポートのプロパティを複合的に定義することができます。例えば、ビューポートの高さと幅、ページの初期のスケール、および対応する画面の密度を定義することができます。content 属性にあるビューポートのプロパティはそれぞれカンマで分割する必要があります。

例として、以下の HTML ドキュメントのスニペットだと、ビューポートの幅がデバイスの幅とまったく同じで、ズームは使用できなくなるはずです。

<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, user-scalable=no" />
</head>

この例ではビューポートのプロパティは 2 つだけです。以下の構文はビューポートでサポートされるすべてのプロパティと、それぞれで受け付ける一般的な値です。

<meta name="viewport"
content="
height = [pixel_value | device-height] ,
width = [pixel_value | device-width ] ,
initial-scale = float_value ,
minimum-scale = float_value ,
maximum-scale = float_value ,
user-scalable = [yes | no] ,
target-densitydpi = [dpi_value | device-dpi |
high-dpi | medium-dpi | low-dpi]
" />

この後のセクションでは、それぞれのビューポートのプロパティと、受け付ける値について厳密に解説します。

図 1. Android ブラウザでの 320 ピクセル幅のイメージを持つウェブページ、ビューポートをのメタデータ設定なし ( デフォルトで "オーバービューモード"  有効、ビューポート 800 ピクセル幅 )

図 2. ウェブページのビューポートが width=400 で "オーバービューモード" 有効 ( ウェブページのイメージは 320 ピクセル幅 )

ビューポートサイズの定義

ビューポートの heightwidth プロパティにより、ビューポートのサイズ ( 画面からはみ出る前の利用可能なピクセル数 ) が指定できます。

上の概略で述べたように、Android のブラウザはデフォルトで "オーバービューモード" でページをロードし ( 但しユーザにより無効にされていない場合 ) 、このモードは最小のビューポートの幅を 800 ピクセルにセットします。よって、ウェブページのサイズを  320 ピクセルにした場合は、図 1 のように、表示できる画面の範囲よりもページが小さくなります ( 800 ピクセル幅の描画可能エリアをシミュレートしているという理由により、たとえ物理画面が 320 ピクセルであったとしても ) 。この影響を避けるには、ウェブページ用にデザインした幅に合うようにビューポートの width を明示的に定義します。

例えば、ウェブページが明示的に 320 ピクセルでデザインされている場合は、ビューポートの幅を以下のサイズで設定したいと思うのではないでしょうか。

<meta name="viewport" content="width=320" />

この場合ウェブページの幅とビューポートの幅が同じなので、ウェブページは画面サイズにぴったり収まります。

注意: width の値が 10,000 より大きい、または 320 より小さい ( または同じ ) 場合は、デバイスの幅と同じ値 ( 上記で説明した ) になってしまいます。高さの値が 10,000 より大きい、または 200 より小さい場合は無視されます。

このプロパティによりウェブページのサイズがどのような影響を受けるのかをデモするために、図 2 に 320 ピクセル幅のイメージを含むウェブページを表示していますが、このビューポートの幅は 400 にセットされています。

注意: ビューポートの幅をウェブページの幅と同じに設定し、デバイスの画面の幅がその寸法と一致していない場合、たとえデバイスの密度が高密度または低密度の画面だとしても、ウェブページは画面にぴったり収まりますが、これは Android ブラウザと WebView がデフォルトで中密度画面のサイズと判断しているからです ( 図 2 の hdpi と mdpi のデバイスを比較した様子で分かると思います ) 。画面の密度についてはさらに ビューポートの対象密度の定義 で解説しています。

自動的なサイズ化

ビューポートの寸法をピクセルの即値で指定するのと別の方法として、ビューポートのサイズをデバイスの画面の寸法に常に一致させるように設定することができますが、そうするにはビューポートのプロパティの heightwidth をそれぞれ device-heightdevice-width の値で定義します。これは流動的な幅 ( 固定していない幅 ) のウェブアプリケーションを開発していながら、あたかも固定しているかのように見せたいときに適しています。以下はその例です。

<meta name="viewport" content="width=device-width" />

これにより図 3 にあるように、現在の画面の幅が何であってもビューポートの幅が画面の幅と一致することになります。現在のデバイスが 対象の密度、つまり中密度と合っていないときに、他の密度を指定しなければ、イメージは画面にぴったりと合うようにスケーリングされることになります。その結果、図 3 の高密度のデバイスに表示されるイメージは中密度画面の画面の幅と一致するように拡大されます。

図 3. ビューポートが width=device-width または initial-scale=1.0 のウェブページ

注意: ウェブページを対象の密度にスケーリングするのではなく、すべてのデバイスに対して device-widthdevice-height を物理的な画面ピクセルに合わせたい場合、target-densitydpi プロパティの値を device-dpi にして含める必要があります。ビューポート密度の定義 のセクションでこのことを詳しく説明します。そうでなければ、単純に device-height and device-width を使ってビューポートのサイズをすべてのデバイスの画面に合うように定義しますが、それによりさまざまな密度に対して調整を行うためにイメージでのスケーリングが発生します。

ビューポートスケールの定義

ビューポートのスケールにはウェブページに適用するズームレベルを定義します。以下の方法でビューポートのプロパティにウェブページのスケールの指定が可能です。

initial-scale
ページの初期スケールです。この値はウェブページサイズに対する乗数を示す float 値で、画面サイズへの相対値になります。例えば、初期スケールを "1.0" にセットした場合、ウェブページは 対象の密度 の 1 対 1 の解像度に合わせるようにして表示されます。"2.0" にセットした場合は、ページが 2 倍に拡大され ( ズームインされ ) ます。

デフォルトの初期スケールは、ビューポートサイズのウェブページにぴったり合うように計算されます。デフォルトのビューポートは幅は 800 ピクセルなので、デバイスの画面解像度は 800 ピクセル幅より小さくなり、初期スケールはデフォルトで画面で 800 ピクセル幅のページに合うように、1.0 より幾分小さくなります。

minimum-scale
ページで許可する最小のスケールです。この値はウェブページサイズに対する最小の乗数を示す float 値で、画面サイズへの相対値になります。例えば、これを "1.0" にセットした場合は、対象の密度 と 1 対 1 が最小のサイズになることから、ページはズームアウトされなくなります。

maximum-scale
ページで許可する最大のスケールです。この値はウェブページサイズに対する最大の乗数を示す float 値で、画面サイズへの相対値になります。例えば、これを "2.0" にセットした場合は、ページを対象サイズの 2 倍より大きくズームインすることはできません。

user-scalable
ユーザによりページのスケールを変更できるのかどうかの指定です ( ズームインとズームアウト ) 。スケールを許可する場合は yes 、許可しない場合は no をセットします。デフォルトは yes です。これを no にセットした場合はスケーリングができないことから minimum-scalemaximum-scale が無視されます。

すべてのスケール値は 0.01 から 10 の範囲内でなければなりません。

以下はその例です。

<meta name="viewport" content="initial-scale=1.0" />

このメタデータにより初期スケールがビューポートの対象密度に対してフルサイズにセットされます。

ビューポートの対象密度の定義

デバイスの画面密度は画面の解像度に基づいていて、1 インチあたりのドットの数 ( dpi ) により定義されます。Android でサポートする密度のカテゴリには、低 ( ldpi ) 、中 ( mdpi ) 、高 ( hdpi ) の 3 つがあります。低密度の画面は 1 インチあたりの利用できるピクセル数がより少ないのに対して、高密度の画面は 1 インチあたりのピクセル数はより多くなります ( 中密度の画面と比べて ) 。Android ブラウザと WebView はデフォルトで中密度を対象にしています。

図 4. ビューポートが width=device-width かつ target-densitydpi=device-dpi のウェブページ

対象とするデフォルトは中密度なので、低密度または高密度のデバイスを持つユーザには Android ブラウザと  WebView のウェブページはスケールされて ( ページを効率的にズームして ) 表示されることにより、中密度の画面と認識した外観と合ったサイズで表示されます。もっと具体的に言うと、Android ブラウザと WebView は、高密度画面でおよそ 1.5 倍のスケーリングが ( その画面のピクセルがより小さいため ) 、低密度画面でおよそ 0.75 倍のスケーリングが適用されます ( その画面のピクセルがより大きいため ) 。

このデフォルトのスケーリングにより、同じ物理サイズのウェブページを高密度と中密度の両方で表示すると、図 1、2、および 3 のようになるということを例に挙げました ( 高密度のデバイスはデフォルトのスケール係数が実際のピクセル解像度よりも 1.5 倍でウェブページを表示しますが、これは対象の密度に合わせるためです ) 。これによりイメージにおいて好ましくない不自然な結果をもたらしてしまうことがあります。例えば、中密度と高密度で同じサイズのイメージを表示したとしても、高密度ではそのイメージが 320 ピクセル幅でデザインされたのに 480 ピクセルで描画されることにより、イメージはよりぼやけて表示されてしまいます。

ウェブページに対する対象の画面密度は、ビューポートプロパティの target-densitydpi を使って変更することができます。これには以下の値が受け入れられます。

  • device-dpi - 対象の dpi に本来の dpi を使用する。デフォルトのスケーリングは発生しない。
  • high-dpi - 対象の dpi に hdpi を使用する。中密度と低密度画面はそれに見合った大きさに縮小される。
  • medium-dpi - 対象の dpi に mdpi を使用する。高密度画面は拡大され、低密度画面は縮小される。これがデフォルトの対象密度。
  • low-dpi - 対象の dpi に ldpi を使用する。中密度と高密度画面はそれに見合った大きさに拡大される。
  • <value> - 対象の dpi に dpi の値を使用する。値は 70 から 400 の範囲内でなければならない。

例えば Android ブラウザや WebView に異なる画面密度に対してウェブページのスケーリングをさせないようにするためにするには、target-densitydpi のビューポートプロパティに device-dpi をセットします。こうすることでページがスケーリングされなくなります。その代わり、現在の画面の密度に合ったサイズで表示されます。この場合は、ビューポートの幅もデバイスの幅に合わせる必要もあり、それによりウェブページは自然に画面のサイズにぴったり合うようになります。以下はその例です。

<meta name="viewport" content="target-densitydpi=device-dpi, width=device-width" />

図 4 では、これらのビューポートの設定を使って表示したものです。高密度のデバイスは、その物理ピクセルが中密度デバイスのそれよりも小さいため、ページが小さく表示され、それによりスケーリングが起こらず、320 ピクセル幅のイメージは両方の画面で 320 ピクセルそのもので描画されます ( これは画面密度を基にウェブページをカスタマイズし、異なる密度用にそれぞれのイメージを提供したい場合にビューポートを定義する手法で、それには CSS や JavaScript を使います ) 。


CSS を使ったデバイス密度の対応

Android ブラウザと WebView は、特定の画面密度に対してスタイルを作成できるようにするための -webkit-device-pixel-ratio の CSS メディア仕様をサポートしています。この機能に適用すべき値は "0.75"、"1"、"1.5" のいずれかで、それぞれ低密度、中密度、高密度の画面のデバイスに対するスタイルを指定します。

例えば、以下のように各密度に対するスタイルシートを分けて作成することができます。

<link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio: 1.5)" href="hdpi.css" />
<link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio: 1.0)" href="mdpi.css" />
<link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio: 0.75)" href="ldpi.css" />

図 5.  -webkit-device-pixel-ratio メディア仕様を使って特定の画面密度を対象としたウェブページ。hdpi デバイスでは、CSS で適用された別のイメージが表示されていることに注目

または、スタイルシートで異なるスタイルを指定できます。

#header {
background:url(medium-density-image.png);
}

@media screen and (-webkit-device-pixel-ratio: 1.5) {
// CSS for high-density screens
#header {
background:url(high-density-image.png);
}
}

@media screen and (-webkit-device-pixel-ratio: 0.75) {
// CSS for low-density screens
#header {
background:url(low-density-image.png);
}
}

注意: #header のデフォルトのスタイルは、Android の 2.0 未満のバージョンが動作しているデバイスをサポートするために中密度用にデザインされたイメージを適用してください。2.0 未満のバージョンは -webkit-device-pixel-ratio メディア仕様をサポートしていません。

画面の密度による調整を期待するスタイルのタイプは、ビューポートのプロパティの定義の方法により変わってきます。ウェブページをサポートする密度それぞれに対して調整する完全にカスタマイズされたスタイルを提供するには、ビューポートの幅とデバイスの密度が合うようにビューポートのプロパティを設定する必要があります。つまり以下のようにします。

<meta name="viewport" content="target-densitydpi=device-dpi, width=device-width" />

この方法により、Android ブラウザと WebView はウェブページをスケーリングしなくなり、ビューポートの幅は画面の幅にきっちり合うようになります。それぞれについて、ビューポートのプロバティにより表示された結果を 図 4 に示しています。しかしながら、-webkit-device-pixel-ratio メディア仕様を使っていくつかのカスタマイズした CSS を追加することにより、さまざまなスタイルを適用することができます。その例として、これらのビューポートのプロパティと高密度画面用の高解像度のイメージを追加した CSS を持つウェブページを 図 5 に示します。


JavaScript を使ったデバイス密度の対応

Android ブラウザと WebView は、今のデバイスの密度を問い合わせることができる DOM のプロパティをサポートしており、それは window.devicePixelRatio DOM プロパティです。このプロパティの値は現在のデバイスに使われているスケーリング係数を特定します。たとえば、window.devicePixelRatio の値が "1.0" の場合、デバイスは中密度のデバイスとで、デフォルトでスケーリングなしが適用されているとみなされます。この値が "1.5" の場合、デバイスは高密度で、ページはデフォルトで 1.5 倍にスケーリングされると見なされます。この値が "0.75" の場合、デバイスは低密度で、ページはデフォルトで 0.75 倍にスケーリングされるとみなされます。もちろん、Android ブラウザと WebView は対象とするウェブページを基本としてスケーリングを適用します。このことは ビューポートの対象密度の定義 で説明しましたが、対象となるデフォルトは中密度ですが、異なる画面密度でもウェブページがスケーリングされるように対象を変更することが可能です。

これは JavaScript を使ってデバイスの密度を問い合わせできることを示す例です。

if (window.devicePixelRatio == 1.5) {
alert("This is a high-density screen");
} else if (window.devicePixelRation == 0.75) {
alert("This is a low-density screen");
}