with the flow

WEBプログラマを目指すWEBデザイナーが書き綴る開発日誌のようなもの

Sass(Compass)でRetina用backgroundを同時に書き出すmixinを作った

Retina(に限らず高解像度)用の画像を背景画像として書き出すとき、
今までは全部手作業でやってたんだけども、

  • 高解像度向けの@mediaのベストプラクティスが日々変化(進化)するので、毎回grepして修正するのが面倒。
  • @mediaの記述位置はCSSの末尾にまとめて書いてたが、数が多いとどこに対応してるか、訳が分からなくなってきて保守地獄発生。かといって対応セレクタの直後に書くとなんか見通しが悪くなるのでこれも避けたい。
  • そもそもbackground-image: url("path/to/image/hoge@2x.png);とかbackground-sizeとか毎回書くのが大変。なんでRetinaのためにコード書く量が2倍以上になるのか。。。

→そこでsvgですよ、という話もあるんだけど、IE8以下対応してないし、画像でしか表現できないものもあるわけで。


こんな時、Sassでmixin定義したら上の問題が一気に解決できたので共有。
※Sass(もしくはSCSS,Compass)がどんなものか、どれほど便利かは、優れた解説記事がこちらこちらで見られます。

具体的には、こんなmixinを書きます。

SASS

@mixin bgretina($bgwidth, $bgHeight, $bgCol, $image, $extension, $posX:0, $posY:0, $repeat:no-repeat, $ratio:'@2x') {
	background: $bgCol url($image + '.' + $extension) $posX $posY $repeat;
	@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
		   only screen and (min-resolution: 192dpi) {
				background-image: url($image + $ratio + '.' + $extension);
				@include background-size($bgwidth $bgHeight);
	}
}

使い方はこんな感じ。

SASS

.hoge {
	@include bgretina(50px, 50px, #fff, path/to/image/hoge, png);
}

上のように、1行sass(scss)ファイルに書いてコンパイルすると、CSSには以下が自動的に書き出される!

CSS

.hoge {
	background: #fff url(path/to/image/hoge.png) 0 0 no-repeat;
}
@media only screen and (-webkit-min-device-pixel-ratio: 1.3), only screen and (min-resolution: 192dpi) {
	.hoge {
		backgrond-image: url(path/to/image/hoge@2x.png);
		-webkit-background-size: 50px 50px;
		-moz-background-size: 50px 50px;
		-o-background-size: 50px 50px;
		background-size: 50px 50px;
	}
}

※background-sizeにCompassのmixin使ってるのは、"-webkit-background-size"を書かないとAndroid2.1-2.3でサイズが変更されないから。
あと、caniuseみると、一応-moz-や-o-必要なバージョンがあったみたいなので。
IEいきなり9から対応しているのでprefixいらず。
http://caniuse.com/#search=background-size

background-positionとbackgroun-repeat,画像名の後に付ける"@2x"とかの変更にも対応しています。
引数増えるけど、こんな感じ。

SASS

.hoge {
	@include bgretina(50px, 50px, #fff, path/to/image/hoge, png, 0, 50%, repeat-y, @3x);
}


CSS

.hoge {
	background: #fff url(path/to/image/hoge.png) 0 50% repeat-y;
}
@media only screen and (-webkit-min-device-pixel-ratio: 1.3), only screen and (min-resolution: 192dpi) {
	.hoge {
		backgrond-image: url(path/to/image/hoge@3x.png);
		-webkit-background-size: 50px 50px;
		-moz-background-size: 50px 50px;
		-o-background-size: 50px 50px;
		background-size: 50px 50px;
	}
}

  • @mediaのベストプラクティスが変わったら、mixinだけを書き換えて再コンパイルすれば全ファイル一括書き換えもカンタン。
  • 保守するのはscssファイルだけでいいので、@mediaの位置が離れて見づらいとかの問題も解決!
  • なによりたった1行書くだけで、今まで10行書いてた苦痛から解放される!

本当は引数の$imageと$extensionは、分けずにmixin側で分割したい
(@include bgretina(50px, 50px, #fff, path/to/image/hoge.png);って書きたい)んですが、
文字列操作とかはSass3.3以降でしかサポートされないみたいですね。
安定版としてリリースされたらmixin書き直すかも。。