<meta>タグによるviewport指定の2016年春決定版!jsで上書きするべきケースも紹介

長々書いていますが記事の新規部分は最近の Android 標準ブラウザでも遭遇するバグへの target-densitydpi=medium-dpi での対策だけです。

はじめに

気が付けば <head> 内にはズラズラといろいろなことを書くようになりました。

<meta> タグの viewport にどんな指定をすればよいのか?自分でも怪しかったのでここしばらくで根を詰めて調べてみました。

モバイルブラウザのデフォルトの拡大縮小機能を生かす場合と切る場合、この2通りについてそれぞれ指定法を紹介します。

また残念ながら viewport を js で上書きするべきケースも併せて紹介します。

拡大縮小を禁止する
Web アプリケーションなどでタッチ操作を完全に制御している。
Web 文書でもアクセシビリティに手当てがされているので拡大縮小を禁止する。例えば“AAA”などの昔ながらの文字サイズ変更ボタンがある。
拡大縮小を許可する
一般的な Web 文書用。

拡大縮小を禁止する

考慮することの少ない拡大縮小を禁止するケースから紹介していきます。

js が切られている場合に配慮する

Web 文書の場合でも文字サイズを切り替える手段を提供していれば拡大縮小を禁止することができます。

しかし js によって手段を提供している場合 js が切られているケースに対処が必要です。そこではじめに拡大縮小が可能な <meta> タグを指定した上で js でそれを上書きします。

<meta name="viewport" content="width=device-width,target-densitydpi=medium-dpi,initial-scale=1,minimum-scale=1,shrink-to-fit=no">
<script>
document.write('<meta name="viewport" content="width=device-width,target-densitydpi=medium-dpi,minimum-scale=1,maximum-scale=1.0,shrink-to-fit=no">');
</script>

onload 後の viewport の書き換えが可能なのは一部の環境みたいです。そのようなわけで必ず <head> 内の js で上書きします。

ちなみに以上の反対で <noscript> 内に書いた <meta> で指定を上書きする手も考えられますが、これは不正な html となってしまいます。

fotnSize ベースのレイアウト

レイアウトを fontSize ベースで行っていれば、Web 文書への文字の拡大縮小ボタンの設置はとても容易になります。

このテクニックの基本的なコンセプトは、全てのインターフェース要素のサイズ設定単位に、活字の相対的なサイズを表す単位である「em」を利用することにあります。(中略)

font-sizeはCSSにおいて子要素に継承されるプロパティであるため、emを使ってサイズを設定した任意の要素について、その親要素のfont-sizeを変更することにより子要素のサイズを変更することが可能となります。

拡大縮小を許可する

<meta name="viewport" content="width=device-width,target-densitydpi=medium-dpi,initial-scale=1,minimum-scale=1,shrink-to-fit=no"/>

width=device-width を指定

副作用の出る環境もあるため指定され無い場合もある。副作用の出る環境に対しては js で <meta> を上書きして対策する。

target-densitydpi=medium-dpi を追加

次の記事には medium-dpi が target-densitydpi のデフォルト値とある。

しかし target-densitydpi=medium-dpi を明示した場合と無い場合で Android 2.3.5 の標準ブラウザで挙動が変わった。指定しない場合縦向きから横向きにした際に画面がズームインする。

medium-dpi 中解像度。160dpiまで。属性を指定しなければ、通常はこれが適用される。

好みにで high-dpi を指定してもよいが、デフォルトの文字サイズがかなり小さくなってしまった。

また先にの記事にも言及があるように target-densitydpi=device-dpi には深刻なバグがあるため決して指定しない。

Android 4 以降の標準ブラウザで viewport 指定を無視して初期表示が拡大縮小する

Android 4 以降の標準ブラウザでは、要素を画面外にスライドさせたときにページ制作者が意図せずに画面が縮小されてすべての画面範囲が再び画面に収まる挙動があった。この症状は次の対策を行ったところ解消した。

  1. target-densitydpi=medium-dpi を指定する
  2. ユーザーが気にならない程度にはじめに一度だけ 10px 画面をスライドさせて 0 位置に戻す(症状は2度目以降のスライドでは起こらなかったことから発見する、アニメーション用に指定した css プロパティが関係する模様)

上で言及している原因の推測と対策に納得がいかなかったところ、次の記事の対策が筋がいいように思う(未確認、2016-10-05 追記)。

一昨年の年末、Android4.0.4とかを対応していた際に、 user-scalableを指定すると一部Androidで初期表示がおかしくなるという現象に出くわしたので、 それ以降user-scalableは動的にJSで動的に設定するという方針だったのですが、 最近のAndroidでは不要な処理なのかもしれません。

shrink-to-fit=no を追加

iOS9.0限定の不具合に対策するために追加する。詳しくは次の記事などで。

iOS9のSafariでは、初期の画面倍率を無視してページ全体を表示するよう縮小して表示しているようです。

iOS5以下に対してjavascriptで対策すること

iOS5 以下に対して拡大縮小を一切禁止にする。width=device-width を指定しなければよい、とする記事もあるが、iOS3 & 4 では改善を確認できない。

iOS5以下で、以下のようなviewport指定をしているとき、縦向き(ポートレート)から横向き(ランドスケープ)にすると、1.5倍拡大される(というより320pxのviewportを保つ)仕様があります。

これも、拡大・縮小を禁止(maximum-scale=1.0,minimum-scale=1.0)にすることで解決できます。

Android 2.x以下に対してjavascriptで対策すること

Android 2.x 以下に対して拡大縮小を禁止しないと画面にズーム用のボタンが出現して邪魔だ、という理由で…

IE Mobile 10に対してjavascriptで対策すること

css 内の @viewport 指定の上書きを行う。この問題は手元の IE Mobile 11 では確認していません。また @-ms-viewport を使っていなければ不要のようです。

[1] Windows Phone 8 の古いバージョンにある IE モバイル 10 は、 device-width のところに不具合がある。 @-ms-viewport を使ったとき、物理的なピクセルによる画面幅ではなく、CSS ピクセルとして評価してしまう。

ほか

拡大縮小を禁止すると position:fixed が使えるようになる、とか click イベントの発生が早くなるとか。

先々は CSS 側に @viewport 指定で書いていく。@viewport - CSS | MDN

お好みで minimal-ui。(iOS7.1 だけ)

onload 後の viewport の変更を反映してくれるダイナミック viewport が Opera 10(?だったかな, Windows Mobile 6.5 IS12)で可能。