ウェブサイトのRetina化

/ Text by

iPhone 4からはじまり新しいiPadことiPad 3、そしてもはや確定的とも思われる次期MacBook ProのRetina化。現状でウェブサイトをRetina化する効率的な方法を考えると、 “Retina Images” を使うのが最適解な気がしている。

Retina画像を対応端末に表示させる場合、

<!-- imgタグによる設置 -->
<img src="foo@2x.png" width="100" height="100" alt="bar">
<!-- background-imageによる設置 -->
<style>
    #foo {
        width: 100px;
        height: 100px;
        background: url(bar.png) no-repeat;
    }

    @media only screen and (-webkit-min-device-pixel-ratio: 1.5) {
        #foo {
            background-image: url(bar@2x.png);
            -webkit-background-size: 100px 100px;
        }
    }
</style>

<div id="foo"></div>

とやるのが一般的だと思うのですが、この方法のデメリットは

  1. 面倒くさい。
  2. 面倒くさい。
  3. 面倒くさい。
  4. <img>での設置の場合、2種類の画像ファイルの振り分けをどういうやりかたで行うかいちいち検討が必要。
  5. Media Queriesで分けたRetina用のCSSを必然的に別の場所にまとめて書くことになるので、コードの閲覧性に難が出たり書き損じも生じやすい。
  6. Retina画像(@2x画像)をアップロードし忘れると、Retina端末で画像が表示されなくなる。

と6つほど。「面倒くさい」は3回挙げたいほど面倒。(さらに言えばそもそもRetina画像を作るのが面倒だったりしますがこれは致し方ない。)

で、この面倒を回避する策として最初にたどりついたのが “Retina.js” なのですが、これでも以下に挙げるような不満が残り

  1. 最初に非Retina画像を読み込んだあと非同期でRetina画像の有無をサーバーに確認しにいくため、
    • ページ内に画像が多いと全てのRetina画像が表示されるまでに時間を要する。
    • Retina端末にとっては、読み込む必要のない非Retina画像まで読み込むことで無駄な通信コストが発生する。現状Retina端末がiPhone等のモバイルであることを踏まえるとこの無駄は致命的。
  2. ページ表示時点でのチェックしか行わないため、JavaScriptで後から動的に追加・置換を行った画像は非Retinaのまま。

結果、たいして効率は上がらないのではないかと思う。

Retina Images

そこで “Retina Images” なのですが、最初に結論として言ったとおり現状ではこれがいちばん楽なのかなと。設置方法はリンク先の説明のままですが

  1. retinaimages.phpを設置する。
  2. mod_rewiteを使って全ての画像の参照先がretinaimages.phpに向くよう.htaccessにリダイレクト設定を書く。
    <IfModule mod_rewrite.c>
        RewriteCond %{HTTP_HOST} ^(www\.domain\.com)(:80)? [NC]
        RewriteRule \.(?:jpe?g|gif|png|bmp)$ /retinaimages.php
    </IfModule>
  3. サイトの全ページのヘッダ中、最初のCSSが読み込みこまれるよりも前の場所にcookie確認と生成用のスクリプトを挿入する。
    <script>document.cookie='devicePixelRatio='+((window.devicePixelRatio === undefined) ? 1 : window.devicePixelRatio)+'; path=/';</script>
  4. <body>タグの直後へ指定のスクリプトを挿入する。
    <noscript><style id="devicePixelRatio" media="only screen and (-moz-min-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio: 2)">#devicePixelRatio{background-image:url("retinaimages.php?devicePixelRatio=2")}</style></noscript>

ここまでやれば、あとはCSS中での指定方法は冒頭で書いたものに比べてだいぶシンプルになります。

<!-- imgタグによる設置 -->
<img src="foo.png" width="100" height="100" alt="bar">
<!-- background-imageによる設置 -->
<style>
    #foo {
        width: 100px;
        height: 100px;
        background: url(bar.png) no-repeat;
        -webkit-background-size: 100px 100px;
    }
</style>

<div id="foo"></div>

imgタグによる設置方法では通常解像度の画像を置くのと全く同じソースが使用できるし、background-imageによる設置の場合でも-webkit-background-sizeの指定を追加しておくだけで良い。面倒な@2x画像への振り分けは全部retinaimages.phpがやってくれる。

メリットは言わずもがなHTMLとCSSの記述量が減らせることと、Retina.jsのように画像の無駄な転送が発生しないこと、そして特に嬉しいのはJavaScriptで動的に画像を追加・置換する際にもRetina画像への振り分けを一切考慮しなくて済むようになること。

全ての画像にリダイレクト処理を加えることでレイテンシやサーバへの負荷にどのくらい影響が出るかは未計測で分からないですが、単純なリダイレクト処理だし、実際にやってみても体感的なレベルでは特に遅くなった感じはしない。

ちなみにJavaScriptを切った状態だと非Retina画像が表示されます。

Retina化で誰が幸せになれるのか

Retina対応のMacBook Proが発売される秒読み段階と言われていますが、現状ではRetina対応なのはiOSデバイスをはじめとしたモバイル。そのモバイル端末で、アプリはさておきRetina対応のウェブサイトってどうなんでしょうね。わざわざPCサイトよりもファイル容量の大きな画像を、回線の細いモバイル環境で読み込ませるというドMっぷり。

ただ、Retina端末でRetina非対応のサイトを開いたときの全体的にぼやけた感じはやっぱり気になってしまいますし、プロダクトを扱ったサイトなんかだと肝心の商品画像がぼけてシズル感が一掃されるという哀しい状況になりますので対応せざるを得ないのかなぁとも。iPhoneなどの携帯端末でまじまじとサイトを閲覧することってあまりないのかもしれませんが、リビングなどで体を落ち着かせて使うことの多いタブレットだと特に気になる率アップ。

というわけで、4G (3.5G) のLTE携帯網やら802.11ac Wi-Fi網みたいなより高速なインフラが普及するまでは、過渡期特有の悩みとして誰もあまり幸せでないこの状況としばらくお付き合いしていかないといけなさそうです。ユーザー側も制作側も。