viewportを固定したときAndroid端末で右側に空白ができるバグを回避する方法
前田 大地

昨年、viewportを320pxに固定する案件のコーディングがありました。自分で設計する案件では、viewportを固定することがないので、なかなか貴重な体験でした。
……で、どうやら、Android端末ではviewportを固定したときバグがあるようです。
バグに気づいたとき、ネットで一生懸命調べても情報がぜんぜんないのでとっても困りました。同様のバグ報告の記事も皆無!これだけネットが普及してるご時世に、なぜ!……で、紆余曲折を経てなんとか解決に至りましたが、同様の現象に悩まされている方のために、記事にすることに決めました。
……そして半年後、ようやく記事を書いたので公開します。
どんなバグ?

固定したviewportの値よりもAndroid端末の幅が大きいとき、一見すると正常に表示されているように見えるのですが、右側に謎の余白ができて横スクロールが発生していました。そして、それに伴ってなんか色々と不具合が出ました。
例えば、幅360pxのAndroid端末でviewportを320pxに固定されたページを表示すると、右側に謎の余白が40px相当分発生して、横スクロールできちゃうようなイメージです。
複数の実機で同様の症状が確認できたので、Android全体の問題かと。ちなみに、iPhoneだと問題ありません。
解決方法
この記事に救われました。もう更新されていないブログですが、著者の方には心から感謝します。
http://d.hatena.ne.jp/festiva1300/20121122/p1
まずはviewportを指定するmetaタグにidを振って、
<meta name="viewport" content="width=320" id="viewport">
UAとかでAndroid判定(省略)して、Androidだったら以下を実行。
<script>
var width = 320; // 固定viewportの値
var defaultDpi = 160;
document.getElementById("viewport").remove();
var densityDpi = (defaultDpi * width * window.devicePixelRatio / screen.width) | 0;
var meta = document.createElement('meta');
meta.setAttribute('name', 'viewport');
meta.setAttribute('content', 'width=device-width, target-densitydpi=' + densityDpi);
document.getElementsByTagName('head')[0].appendChild(meta);
</script>
これで正常に表示されるようになりました。
Android端末のときだけ、widthのかわりにtarget-densitydpiを使って解像度を固定するイメージですね。JavaScriptでviewportを動的に書き換えています。
感想
これだけ調べて情報がほとんど無いってことは、viewport固定してるサイトで、横スクロールに気付かないでそのままになっているケースとか多いんだろなー。ちゃんと実機で確認しましょうね。