LoginSignup
2
2

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-12-07

The end of sprites; the rise of SVG | Optical Cortex
というポストを見て、Compassにインラインデータを埋め込む機能があることを知りました。

これを使えば、これまで温めてきたCompassのSpritingに、SVGのサポートも加えることが出来そうです。

ディレクトリ構成

Compassのconfigで指定した画像フォルダ (ここでは sprites ) に、

sprites/icons_1x
├ icon-facebook.png
├ icon-twitter.png
└ icon-github.png

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

sprites の隣に svg を作って、

svg/icons_svg
├ icon-facebook.svg
├ icon-twitter.svg
└ icon-github.svg

というように配置します。

mixin

前回、Compassを使ったSpriting最適化 [Retina編] で書いたmixinをベースに、SVGのサポートを加えます。

@import "compass/utilities/sprites";

// Mixin
$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, $svg: 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;
    }
  }

  // SVGのサポート
  @if $svg == true {
    .svg & {
      background-image: inline-image( '../svg/icons_svg/#{$sprite}.svg', 'image/svg+xml' );
      background-size: image-width( $sprite-image ) image-height( $sprite-image );
      background-position: 0 0;
    }
  }
}

使用例

$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, true );
  }
}
<i class="icons-icon-facebook"></i>
<i class="icons-icon-twitter"></i>
<i class="icons-icon-github"></i>

生成されるCSSはこのようになります。(アイコン一つ分掲載)
SVGのデータがインラインに埋め込まれます。

.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; } }
  .svg .icons-icon-facebook {
    background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOTYiIGhlaWdodD0iOTYiIHZpZXdCb3g9IjAgMCA5NiA5NiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+aWNvbi1mYWNlYm9vazwvdGl0bGU+PHBhdGggZD0iTTY4IDIySDI2Yy0xLjY0IDAtMyAxLjM2LTMgM3Y0MmMwIDEuNjQgMS4zNiAzIDMgM2gyMi42NjRWNTEuMzQ0aC02VjQ0LjQzaDZ2LTUuOTc3YzAtNS40NiAzLjMyOC05LjExNyA5LjkxNC05LjExNyAyLjkwNiAwIDQuOTIyLjMyOCA0LjkyMi4zMjh2Ni4yMzRINTljLTEuOTkyIDAtMyAxLjEyNS0zIDMuMDk0djUuNDM4aDcuMDA4TDYyIDUxLjM0NGgtNlY3MGgxMmMxLjY0IDAgMy0xLjM2IDMtM1YyNWMwLTEuNjQtMS4zNi0zLTMtM3oiIGZpbGw9IiMwMDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==');
    background-size: 48px auto;
    background-position: 0 0; }

SVGデータの圧縮

GruntでCompassを実行する際にSVGの圧縮プロセスを手前に挟むと良いでしょう。

sindresorhus/grunt-svgmin

※ Gruntのワークフロー一式は近日アップ予定です。

その他の考察

こちらで、icon-fontとSVGの比較や、data-uriによる埋め込み、sprite画像の生成について論じられています。
(以下適当訳)

  • icon-fontになっているのが一番楽に管理でき、単色での着色も簡単だが、位置合わせは手間がかかる。
  • SVGは複数色の着色や位置合わせが簡単だけど、素材作成に手間がかかる。
  • パフォーマンス面ではdata-uriよりspriteを利用する方が優れている。
  • サイズの大きなSVG SpriteはiOSでのレンダリングにバグあり? (960x560で描画されない)
  • PNGの方がSVGよりもレンダリングが速い。
  • spriteの自動生成をGruntで行う場合、セットアップにはかなり手間がかかる。

まとめ

素材の書き出しフローの検討 の時点から考えていましたが、

SVGをdata-uriで埋め込み、PNGでfallbackする

というのが、現時点では最もシンプルなコーディング方法である、と判断しました。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2