注目の記事

コーダー必見、SCSS・Compassで開発効率アップ|Retina Display対応CSS Sprite編

2013.02.04

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

特に寒い今日この頃ですが読者の皆様は元気にお過ごしでしょうか?

2月のリア充イベントといえばバレンタインですね(企業戦略)。バレンタイン用のチョコを販売するお店も増えてきました。
弊社は秋葉原という立地ですが意外なことに既婚者が多いので「リア充爆発しろ」と嘆く男性は少数のようです。

ちなみにビターチョコが好きです。

本題

今回は少し前に執筆した「コーダー必見、SCSS・Compassで開発効率アップ|便利なCSS Sprite実装編」を発展させてSCSS・CompassでRetina Displayに対応する方法を紹介します。

事前に必要な知識

この記事では、以下の事前知識が必要になります。
記事中でも解説を挟みますが、詳しくは解説で案内しているページを参考にしてください。

  • SCSS/Compass
  • CSS Sprite
  • Media Queries

1,サンプルをキャプチャしてみた

サンプルを作ってみました。
今回はiPhoneを対象にし、2倍の解像度に対応してみました。

非対応の低解像度版

低解像度汚い・・・。見るに堪えない画像ですね(画像をクリックすると実物が開きます)。

ノーマル

Retina対応の高解像度版

綺麗に表示されています。

Retina対応

サンプルコード

サンプルファイルをgithub「cutandslice_me_sample」にアップロードしてあります。

2,Media Queriesについておさらい

Retina Displayの対応にはMedia Queriesを利用します。
まだ覚えていない方は先に知っておいてください。

W3C Media Queries

@media宣言を使い、メディアタイプやデバイスの画面サイズ、向き、などに合ったスタイルの指定が可能になるCSS3の仕様です。

@media screen and (max-width: 320px)
{
	.class
  	{
  		background: #ccc;
	}
}

device-pixel-ratio、resolution、dppxについて

device-pixel-ratioとは

device-pixel-ratioはデバイスのピクセル密度を表す値です。

@media screen and (-webkit-min-device-pixel-ratio: 2)
{
	.class
	{
		background-image: url(icon-2x.png);
	}
}

調べていて知ったのですが、どうやらdevice-pixel-ratioは標準ではなくwebkitの独自拡張とのこと。
とても参考になったYakuraさんの記事から抜粋。

device-pixel-ratioはもともとWebKitの拡張だったもの。それをMozillaとOperaも取り入れたのだけど、ベンダー接頭辞の面倒さに加えてmin-/max-のつき方、値の書き方がばらばらというカオスになっていた。どちらも各々のパーサに都合のよい、もしくは「適切」だと考えた構文を実装した結果なのだろうけど、センスよい感じではない。

さらばmozとoのdevice-pixel-ratio

ということで、本来はresolutionがW3Cの標準です。

resolutionとdppx

resolutionはdevice-pixel-ratioと同様にピクセル密度を表します。
dppxはresolutionに値を指定するときの単位であり、dot per pixelを表します

W3C Media Queries resolutionW3C CSS Values and Units Module Level 3 dppx

@media (-webkit-min-device-pixel-ratio: 2),
       (min-resolution: 2dppx)
{
	.class
	{
		background-image: url(icon-2x.png);
	}
}

3,CSS Spriteの原理とRetina Display対応の原理

CSS Spriteの原理

簡単に言うと画像をくっつけてCSSのbackgroud-positionで表示を制御するテクニックです。
画像を1つにすることでHTTPリクエストの削減につながりるのでWebサイト高速化手法の1つになっています。

CSS Spriteの原理(Retina Display対応の場合)

Retina Display対応のCSS Spriteも基本的な原理は通常の解像度のCSS Spriteと変わりません。

Retina Displayに対応したCSS Spriteの原理

Retina Display対応のポイント

  • viewportを指定しwidthをdevice-widthにする
  • 2倍の解像度の画像を作る(解像度については、対象となるデバイスに合わせて複数用意する場合もあります)
  • Media Queriesを使い、device-pixel-ratio:2(resolution:2dppx)以上の場合に2倍の解像度の画像を指定
  • 通常の解像度の場合に合わせた1/2(device-pixel-ratioまたはresolutionによる)のbackground-sizeを指定する

4,準備

こちらの「コーダー必見、SCSS・Compassで開発効率アップ|便利なCSS Sprite実装編」を理解している前提で話しを進めますので、まだこちらを読んでいない方はこちらを試してから以降の手順を試してください。

作業の流れ

主な流れはこんな感じです。

  1. ディレクトリの作成
  2. SCSS用設定ファイルの作成
  3. 画像の用意
  4. SCSSの記述
  5. 保存してコンパイル

ファイル構成

  • SCSS/
  • CSS/(output)
  • images/
    • btns/
      • 2x/(Retina Display用の倍の解像度の画像)
      • normal/(通常の解像度の画像)
  • config.rb
  • index.html

画像の準備

画像は通常の解像度と倍の解像度を用意します。
画像の作成には「Cut&Slice me」や「PNG EXPRESS」を利用すると作りやすいかもしれません。
Cut&Slice meはこのブログでも解説「【実案件で使える?】Photoshop CS6のプラグイン「Cut&Slice me」を使ってみる」を書いたので参考にどうぞ。

以下のように通常と倍の解像度の画像を必要な分だけ用意します。

設定ファイル

http_pathは必要に応じて変更したり消してください。
設定ファイルについてはこちら「【Webデザイナ-・コーダー向け】すぐに使えるSCSS入門|設定ファイルを知っておこう – 番外編」を参考にしてください。

http_path = 'http://nonakaryuichi.github.com/cutandslice_me_sample/'
sass_dir = 'scss'
css_dir = 'css'
images_dir = 'images'
output_style = :nested
line_comments = false

SCSS/Compassを利用したCSS Sprite

一応CSS Spriteについておさらいしておきましょう。
詳しくはこちら「コーダー必見、SCSS・Compassで開発効率アップ|便利なCSS Sprite実装編」をどうぞ。

サンプル

.btn
{
	$btns: sprite-map("btns/normal/*.png", $spacing: 20px, $layout: horizontal);
	
	a
	{
		display:       block;
                overflow:     hidden;
                width:          90px;
                height:         90px;
                
                background : $btns no-repeat;
	}
	
	&.home
	{
		a
                {
                    background-position:
                        sprite-position( $btns, btn_home_normal );
                }

                a:hover
                {
                    background-position:
                        sprite-position( $btns, btn_home_hover );
                }

                a:active
                {
                    background-position:
                        sprite-position( $btns, btn_home_pressed );
                }
                a:target
                {
                    background-position:
                        sprite-position( $btns, btn_home_selected );
                }
	}
}

5,Retina Displayに対応したCSS Spriteを実装する

Retina Displayに対応するには、Media Queriesを利用します。

注意点

自動化するためのちょっとした注意点があるので気をつけましょう。

  • 画像を保存するディレクトリを分ける
  • ファイル名を同じにする
  • 画像の配置が同じか確認する
  • 画像間のスペースは倍の値にする
  • 画像名に@2xを使わない(コンパイルエラーの原因になる)

全体のSCSS

まずは全体像を見てみてください。

.btn
{
	$btns: sprite-map("btns/normal/*.png", $spacing: 20px, $layout: horizontal);
	$btns-retina: sprite-map("btns/2x/*.png", $spacing: 40px, $layout: horizontal);
	
	a
	{
		display:       block;
                overflow:     hidden;
                width:          90px;
                height:         90px;
                
                background : $btns no-repeat;
                
                //retina
                @media (-webkit-min-device-pixel-ratio: 2),
                (min-resolution: 2dppx)
                {
                        background : $btns-retina no-repeat;
                        @include background-size(image-width(sprite-path($btns)) image-height(sprite-path($btns)));
                }
	}
	
	&.home
	{
		a
                {
                    background-position:
                        sprite-position( $btns, btn_home_normal );
                }

                a:hover
                {
                    background-position:
                        sprite-position( $btns, btn_home_hover );
                }

                a:active
                {
                    background-position:
                        sprite-position( $btns, btn_home_pressed );
                }
                a:target
                {
                    background-position:
                        sprite-position( $btns, btn_home_selected );
                }
	}
}

スプライトマップを変数に保存

sprite-mapを使いCSS Spriteを定義します。
引数には対象となる画像、倍のスペース、レイアウトをを指定します。

それらを通常のSpriteは$btnsに、Retina用は$btns-retinaに保存します。

$btns: sprite-map("btns/normal/*.png", $spacing: 20px, $layout: horizontal);
$btns-retina: sprite-map("btns/2x/*.png", $spacing: 40px, $layout: horizontal);

Media Queriesでpixel-ratioが2以上の時に背景画像を指定

Retina用に設定したスプライトマップを背景画像に設定します。

@media (-webkit-min-device-pixel-ratio: 2),
(min-resolution: 2dppx)
{
	background : $btns-retina no-repeat;
}

通常時に合わせたbackground-sizeの指定

sprite-path($btns)でマージされた画像のURIを取得します。
それからimage-width(), image-height()を使い、幅と高さを取得します。

ここでは通常の解像度のSprite用画像から基準となる幅と高さを取得していますが、Retina用のSprite画像を1/2にして値を取得するのも良いかもしれません。

@include background-size(image-width(sprite-path($btns)) image-height(sprite-path($btns)));

通常時と同じ座標指定でbackground-positionを指定

background-sizeを指定すると、background-imageで指定している画像が倍のサイズだとしても、background-sizeで指定したサイズとして処理されます。
なので、通常の解像度と同じ座標指定で良いことになります。

座標が同じということはRetina Display用に別のbackground-positionを指定する必要はありません。

a
{
	background-position:
        	sprite-position( $btns, btn_home_normal );
}

コンパイル

保存してコンパイルを実行して問題なくコンパイルされるか確認してみてください。

まとめ

長い解説記事なってしまいましたが、うまくコンパイルできたでしょうか?
sprite-file()で取得する方法とsprite-path()を使う方法があるのですが、個人的にsprite-pathでやる方法好きだったのでこちらを紹介しました。

Androidの特殊な解像度の場合、たぶん計算がかなり面倒だと思いますが、Sass, Compassに処理を任せて自動化することはできると思います。
Mixinsを作ったら紹介したいと思います。

参考サイト