用 Compass 分分钟地做图片精灵

992 阅读3分钟
原文链接: www.jianshu.com

对于页面仔来说,做图片精灵是一件枯燥无聊又废时的事。然后不甘于现状的人们发明了些做图片精灵的工具。我觉得用 Compass 来做图片精灵是最快速简单的。

先来说说我们不用工具的情况下,做图片精灵的流程。

  1. 创建一张背景是透明的图片。将一系列图标放到该图片中。图标间会留一些间距。裁切掉透明的空白部分。
  2. 查看图标的大小,以及在图片精灵中的位置,写类似这样的 CSS
.icon{
  display: inline-block;
  background-image: url(图片精灵路径);
  background-repeat: no-repeat;
}

.icon--facebook{
  width: 图标宽度;
  height: 图标高度;
  background-position: 图标在图片精灵中的位置;
}

.icon--flickr{
  width: 图标宽度;
  height: 图标高度;
  background-position: 图标在图片精灵中的位置;
}

以后,新增或删除图标后,需要手动修改图片精灵图片。为了使修改后的图片精灵的图像质量比较高,一般都会保存一份 psd 格式的图片精灵。修改都是在 psd 上改,然后导出。

如果用 Compass ,只需写如下几行代码
1 创建图片精灵图片。可以用 sprite-map($glob, [配置1,] [配置2,][ ...]) 来实现。如:

$sprites: sprite-map('icons/*.png', $spacing: 10px, $layout: 'vertical');

上面代码的意思是:将 config.rb 中配置的 images_dir 路径下的 icons/ 文件夹下所有的 png 图片做成图片精灵,图标垂直放置,图标之间的垂直间距为 10px。

2 获取图标精灵的路径,获取图标的大小,以及在图片精灵中的位置。Compass中也提供了一系列的方法获取这些值。

@import "compass/utilities/sprites";

$sprites: sprite-map('icons/*.png', $spacing: 10px, $layout: 'vertical');

.icon{
  display: inline-block;
  background-image: sprite-url($sprites);
  background-repeat: no-repeat;
}

.icon--facebook{
  $iconPath: sprite-file($sprites, 图标文件名称(不包含文件拓展名)); // 图标文件的路径
  width: image-width($iconPath);
  height: image-height($iconPath);
  background-position: 0 nth(sprite-position($sprites, $图标文件名称), 2);// 因为是垂直放的
}

.icon--flickr{
  $iconPath: sprite-file($sprites, 图标文件名称(不包含文件拓展名)); // 图标文件的路径
  width: image-width($iconPath);
  height: image-height($iconPath);
  background-position: 0 nth(sprite-position($sprites, $图标文件名称), 2);// 因为是垂直放的
}

以后,新增,删除图标后,只要运行 Compass 的编译命令,都会自动生成新的图片精灵图片。就这么方便 XD~

如果要做响应式的图片精灵怎么办?

解决方案是:图片的宽,高和 background-postion 都要用 rem 做单位,并且设置 bacgroud-size。但 background-position 也用 rem 做单位的话,会有定位不准的 bug, 所幸,background-position 用百分数的话,可以解决这个 bug。具体描述见 完美解决移动端使用 rem 单位时 CSS Sprites 错位问题

最后,写个图片精灵的工具方法。调用我的工具方法,图片精灵就更简单啦,代码如下

@import "sprite"; // 导入定义工具方法的文件

.icon {
    display: inline-block;
    $sprites: creatSprite('icons/*.png');// 将icons下所有png图片生成图片精灵。
    &--facebook {// 非响应式图标
        @include icon('facebook', $sprites);
    }
    &--facebook-rem{ // 响应式图标
        @include icon('facebook', $sprites, true);
    }
    &--flickr {
        @include icon('flickr', $sprites);
    }
    &--flickr-rem{
        @include icon('flickr', $sprites, true);
    }
}

工具代码

@import "compass/utilities/sprites";

// 将 px 转化成 rem
@function pxToRem($pxVal) {
  $pxVal : $pxVal / ($pxVal * 0 + 1);// 去单位
  @if  $pxVal == 0{
    @return 0;
  } @else {
    @return $pxVal/64 * 1rem;
  }
}

// 生成图片精灵
@function creatSprite($globImgPath, $spacing: 10px){
  @return  sprite-map($globImgPath, $spacing: $spacing, $layout: vertical);
}

@mixin icon($name, $sprites, $isRem: false) {
    $iconPath: sprite-file($sprites, $name); // 图标文件的路径
    $iconWidth: image-width($iconPath);
    $iconHeight: image-height($iconPath);
    $iconPosXInSprite: 0;// 垂直放的
    $iconPosYInSprite: nth(sprite-position($sprites, $name), 2);
    background-repeat: no-repeat;
    background-image: sprite-url($sprites);
    @if $isRem {
      width: pxToRem($iconWidth);
      height: pxToRem($iconHeight);
      $spriteWidth: sprite-width($sprites);
      $spriteHeight: sprite-height($sprites);
      /*
      * 完美解决移动端使用 rem 单位时 CSS Sprites 错位问题
      * (https://github.com/banricho/webLog/issues/1
      */
      @if $iconPosYInSprite != 0 {
        $iconPosYInSprite: $iconPosYInSprite / ($iconHeight - $spriteHeight) * 100%;
      }
      background-position: $iconPosXInSprite $iconPosYInSprite;
      background-size: pxToRem($spriteWidth) pxToRem($spriteHeight);
    } @else {
      width: $iconWidth;
      height: $iconWidth;
      background-position: $iconPosXInSprite $iconPosYInSprite;
    }
}

完整 Demo 见这里