Edited at

Compassを使ったSpriting最適化 [Retina編]

More than 3 years have passed since last update.

前回、CompassのSpriteが進化していたで、今まで知らなかったCompassのSpriting関連の関数をキャッチアップしましたが、今どきの実用面ではRetinaディスプレイのサポートをする必要があります。

そこでこのようにコーディングします。


ディレクトリ構成

Compassのconfigで指定した画像フォルダに、

icons_1x

├ icon-facebook.png
├ icon-twitter.png
└ icon-github.png

icons_2x
├ icon-facebook.png
├ icon-twitter.png
└ icon-github.png

という風に1x画像、2x画像を分けて入れる。


mixinの定義

@import "compass";

@import "compass/utilities/sprites";

// スプライト画像の読み込み
$icons_1x-sprites: sprite-map( 'icons_1x/*.png', $spacing: 2px );
$icons_2x-sprites: sprite-map( 'icons_2x/*.png', $spacing: 4px );

@mixin get-icons-sprite( $sprite, $retina: false ) {
$map-url: sprite-url( $icons_1x-sprites );
$sprite-position: sprite-position( $icons_1x-sprites, $sprite );
background: $map-url $sprite-position no-repeat;

$sprite-image: sprite-file( $icons_1x-sprites, $sprite );
width: image-width( $sprite-image );
height: image-height( $sprite-image );

@if $retina == true {
@include media-retina {
background-image: sprite-url( $icons_2x-sprites );
background-size: image-width( sprite-path( $icons_1x-sprites ) ) auto;
}
}
}


使用例

$icon-names: (

'icon-facebook'
'icon-twitter'
'icon-github'
);

@each $icon-name in $icon-names {
.icons-#{ $icon-name } {
display: inline-block;
@include get-icons-sprite( #{ $icon-name }, true );
}
}

<i class="icons-icon-facebook"></i>

<i class="icons-icon-twitter"></i>
<i class="icons-icon-github"></i>

生成されたCSSは以下。

.icons-icon-facebook {

display: inline-block;
background: url('../../assets/images/icons_1x-s3241a4cef7.png') 0 0 no-repeat;
width: 48px;
height: 48px; }
@media only screen and (min-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3 / 2), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 1.5) {
.icons-icon-facebook {
background-image: url('../../assets/images/icons_2x-sda4f458d0f.png');
background-size: 48px auto; } }

.icons-icon-twitter {
display: inline-block;
background: url('../../assets/images/icons_1x-s3241a4cef7.png') 0 -100px no-repeat;
width: 48px;
height: 48px; }
@media only screen and (min-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3 / 2), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 1.5) {
.icons-icon-twitter {
background-image: url('../../assets/images/icons_2x-sda4f458d0f.png');
background-size: 48px auto; } }

.icons-icon-github {
display: inline-block;
background: url('../../assets/images/icons_1x-s3241a4cef7.png') 0 -50px no-repeat;
width: 48px;
height: 48px; }
@media only screen and (min-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3 / 2), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 1.5) {
.icons-icon-github {
background-image: url('../../assets/images/icons_2x-sda4f458d0f.png');
background-size: 48px auto; } }


import を使う場合

mixinを定義する際に、最初の2行で、 sprite-map という関数をコールして、見えない変数がCompassによって自動的に定義されるのを避けましたが、Compassのimport機能を使って、

$icons_1x-spacing: 2px;

@import "icons_1x/*.png";
// → $icons_1x-sprites が定義される

$icons_2x-spacing: 4px;
@import "icons_2x/*.png";
// → $icons_2x-sprites が定義される

という書き方をしても、同じ結果が得られます。


Retinaディスプレイの条件分岐

Retinaディスプレイを分岐するmixin で紹介したmixin「media-retina」を利用していますが、 Modernizr などを使っても良いでしょう。

@mixin media-retina() {

@media only screen and (min-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 1.5) {
@content;
}
}


参考