使用sass与compass合并雪碧图(一)
Author:zhoulujun@live.cn Date:
雪碧图就是很多张小图片合并成一张大图片,以减少HTTP请求,从而提升加载速度。有很多软件可以合并雪碧图,但通常不太容易维护,使用compass生成雪碧图应该算是非常方便的方法了,可以轻松的生成雪碧图,而且易维护。
安装sass与compass
安装sass可以参考这里。
安装完sass以后,使用下面命令安装compass:
> gem install compass
配置环境
进入项目目录,使用下面命令初始化项目:
> compass init
该命令会在当前目录中生成一些文件:
- sass
-- ie.scss
-- print.scss
-- screen.scss
- stylesheets
-- ie.sss
-- print.sss
-- screen.sss
config.rb
其中sass与stylesheets文件夹中的文件基本上没什么用。config.rb配置文件中的内容一般不需要改动,也可以根据需要修改。
合并图片
在当前目录下创建一个images
的文件夹放置所有图片,然后在images
文件夹中创建一个icons
文件夹放置需要合并的图片。在sass文件夹中创建一个icons.scss
文件,在文件中写入:
@import "icons/*.png";
@include all-icons-sprites;
然后,命令行执行compass compile
命令,合并图片工作就已完成。images
文件夹中多了一张icons-*******.png
的图片。在stylesheets
文件夹中会生成一个icons.css
的文件:
.icons-sprite, .icons-car-icon, .icons-card-icon, .icons-hand-icon, .icons-light, .icons-pan, .icons-title, .icons-watch-icon, .icons-wheel, .icons-wheel1 {
background-image: url('/images/icons-sd6ae4306cd.png');
background-repeat: no-repeat;
}
.icons-car-icon {
background-position: 0 0;
}
.icons-card-icon {
background-position: 0 -124px;
}
.....
自定义类名
可以看到上面生成的css文件中的类名都是自动生成的,在实际应用中通常并不会使用上面的默认类名,这时需要自定义类名:
@import "icons/*.png";
.car-icon {
@include icons-sprite(car-icon);
}
注意:@include icons-sprite(car-icon)
不要写成@include icons-sprites(car-icon)
,否则会有意想不到的结果。@include all-icons-sprites
这句可以去掉,就不会生成默认的类名了。上面输出的结果为:
.icons-sprite, .car-icon {
background-image: url('/images/icons-sd6ae4306cd.png');
background-repeat: no-repeat;
}
.car-icon {
background-position: 0 0;
}
雪碧地图(Sprite maps)
可以使用雪碧地图取代上面的@import
,如下:
$icons: sprite-map("icons/*.png", $spacing: 8px, $layout: horizontal);
.car-icon {
background-image: sprite-url($icons);
width: image-width(sprite-file($icons, car-icon));
height: image-height(sprite-file($icons, car-icon));
background-position: sprite-position($icons, car-icon);
background-repeat: no-repeat;
}
结果:
.car-icon {
background-image: url('/images/icons-s6844bf5750.png');
width: 242px;
height: 116px;
background-position: 0 0;
background-repeat: no-repeat;
}
上面使用了很多compass内置的方法:
sprite-url($icons); //获取合并后雪碧图的url;
sprite-file($icons, $name); //获取目标icon;
image-width(); //获取图片宽度;
image-height(); //获取图片高度;
sprite-position($icons, $name); //获取图片坐标
设置图片尺寸
之前生成的css文件中并没有设置图片的尺寸,一般情况下是需要设置的。可以通过下面的设置设置图片尺寸:
$icons-sprite-dimensions: true;
输出结果:
.car-icon {
background-position: 0 0;
height: 116px;
width: 242px;
}
上面的设置会为每张图图片添加尺寸,也可以指定为某张图片添加尺寸:
.car-icon {
@include icons-sprite(car-icon);
width: icons-sprite-width(car-icon);
height: icons-sprite-height(car-icon);
}
布局方式
布局方式就是生成的雪碧图中小图片的排列方式。compass提供了四中排列方法:vertical、horizontal、diagonal和smart。默认排列方式是vertical。
使用方法就是在icons.scss
文件中加上:
$icons-layout: "vertical";
其他方式用法一样。
下面是四种布局生成的图片:
设置间距
通常,我们会在图片与图片之间设置一定的间距,添加一下代码:
$icons-spacing: 8px;
上面为图片之间设置了8px
的间距。
总结:
上面简单介绍了使用compass制作雪碧图。在使用生成的css文件时会有一个问题:在PC端我们可以直接使用生成的css文件,但在移动端并不能直接使用,因为移动端需要缩放图片以适应不同分辨率的屏幕。然而生成的css文件的宽高都是使用绝对单位px
的,这样在移动端并不适用。由于篇幅原因,我会在下一篇介绍在移动端怎样使用compass生成的雪碧图。
上文介绍了怎样使用compass
合并雪碧图,生成的icons.css
文件中单位是px
,PC端可以直接在html文件中使用,但在移动端,我们需要根据不同分辨率的屏幕,来缩放图片大小,显然使用px
单位肯定是不行的。所以需要做一下单位转换的工作。
移动端使用rem
作为单位是最合适不过了。并不是使用了rem
就可以,还需要做一些准备工作。我们都知道rem
是基于html
标签的font-size
的,所以需要使用js动态的计算html
的font-size
。这里我使用淘宝的lib-flexible
。
在上一篇文章中,有讲过雪碧地图(Sprite maps),如下面:
$icons: sprite-map("icons/*.png", $spacing: 8px, $layout: smart);
.icon {
width: image-width(sprite-file($icons, card-icon));
height: image-height(sprite-file($icons, card-icon));
background-image: sprite-url($icons);
}
生成css:
.icon {
width: 77px;
height: 64px;
background-image: url('/images/icons-s37f950be3b.png');
}
现在,需要把px
转换成rem
。我们不可能在icons.css
中转换,应该在icons.scss
文件中转换。
在icons.scss
声明一个转换函数px2rem
,:
@function px2rem ($px) {
@return $px / 64px * 1rem;
}
这里的64
是因为视觉稿是640px
的,如果是750px
的就是75
。可以看一下lib-flexible
的说明。
加上转换函数的icons.scss
文件是这样的:
$icons: sprite-map("icons/*.png", $spacing: 8px, $layout: smart);
@function px2rem ($px) {
@return $px / 64px * 1rem;
}
.icon {
width: px2rem(image-width(sprite-file($icons, card-icon)));
height: px2rem(image-height(sprite-file($icons, card-icon)));
background-image: sprite-url($icons);;
}
生成的css
如下:
.icon {
width: 1.20313rem;
height: 1rem;
background-image: url('/images/icons-s37f950be3b.png');
}
好了,第一步转换工作就完成了。我们都知道,使用雪碧图,肯定要使用background-position
属性,它的单位也是px
,也需要转换,所以需要在icons.scss
加上:
$icons: sprite-map("icons/*.png", $spacing: 8px, $layout: smart);
@function px2rem ($px) {
@return $px / 64px * 1rem;
}
.icon {
width: px2rem(image-width(sprite-file($icons, card-icon)));
height: px2rem(image-height(sprite-file($icons, card-icon)));
background-image: sprite-url($icons);
background-position: px2rem(sprite-position($icons, car-icon));
}
意思就是:background-position
的值为-250px 0
,并不能简单的使用px2rem
函数,那该怎么办?我们先来判断一下传递给函数的参数的类型:
@function px2rem ($px) {
@warn type-of($px);
@return $px / 64px * 1rem;
}
再次编译(可以使用compass watch
进行监听文件的修改),命令行提示如下图:
从图中可以知道:$width
、$height
的类型是number
,而$pos
类型是list
。知道了什么类型就可以对症下药了,修改函数如下:
@function px2rem ($px) {
@if (type-of($px) == "number") {
@return $px / 64px * 1rem;
}
@if (type-of($px) == "list") {
@return nth($px, 1) / 64px *1rem nth($px, 2) / 64px * 1rem;
}
}
nth
方法可以取出list
中的每一项进行运算,输出css如下:
.icon {
width: 1.20313rem;
height: 1rem;
background-image: url('/images/icons-s37f950be3b.png');
background-position: -1.46875rem -1.40625rem;
}
这边又会有个问题:background-position
的值有可能是0 0
、0 100px
或者100px 0
,而0
是没有单位的,这样转换的时候会报错,继续对px2rem
函数进行改造,如下:
@function px2rem ($px) {
@if (type-of($px) == "number") {
@return $px / 64px * 1rem;
}
@if (type-of($px) == "list") {
@if (nth($px, 1) == 0 and nth($px, 2) != 0) {
@return 0 nth($px, 2) / 64px * 1rem;
} @else if (nth($px, 1) == 0 and nth($px, 2) == 0) {
@return 0 0;
} @else if (nth($px, 1) != 0 and nth($px, 2) == 0) {
@return nth($px, 1) / 64px * 1rem 0;
} @else {
@return nth($px, 1) / 64px *1rem nth($px, 2) / 64px * 1rem;
}
}
}
上面对各种为0
的情况进行了判断,避免了错误。
下面还需要对background-size
属性进行转换。在PC端如果图片不要缩放的话,其实不需要该属性,但在移动端一般是需要的。在移动端,可能很多人不知道该怎么用background-size
属性,到底是设置整个雪碧图的大小,还是设置单个sprite的的大小呢?其实是设置整个雪碧图的大小。
好像compass
没有内置的方法获得雪碧图的大小,没关系,我们可以等到雪碧图生成的时候,再去查看雪碧图的大小。可以先用两个变量保存雪碧图的宽高,初始化为0
:
$bigWidth: 0;
$bigHeight: 0;
等雪碧图生成后,查看图片大小,再修改,如:
$bigWidth: 242px;
$bigHeight: 270px;
这时icons.scss
文件内容如下:
$icons: sprite-map("icons/*.png", $spacing: 8px, $layout: smart);
$bigWidth: 242px;
$bigHeight: 270px;
@function px2rem ($px) {
@if (type-of($px) == "number") {
@return $px / 64px * 1rem;
}
@if (type-of($px) == "list") {
@if (nth($px, 1) == 0 and nth($px, 2) != 0) {
@return 0 nth($px, 2) / 64px * 1rem;
} @else if (nth($px, 1) == 0 and nth($px, 2) == 0) {
@return 0 0;
} @else if (nth($px, 1) != 0 and nth($px, 2) == 0) {
@return nth($px, 1) / 64px * 1rem 0;
} @else {
@return nth($px, 1) / 64px *1rem nth($px, 2) / 64px * 1rem;
}
}
}
.icon {
width: px2rem(image-width(sprite-file($icons, card-icon)));
height: px2rem(image-height(sprite-file($icons, card-icon)));
background-image: sprite-url($icons);
background-position: px2rem(sprite-position($icons, card-icon));
background-size: px2rem(($bigWidth, $bigHeight));
background-repeat: no-repeat;
}
生成css
如下:
.icon {
width: 1.20313rem;
height: 1rem;
background-image: url('/images/icons-s37f950be3b.png');
background-position: -1.46875rem -1.40625rem;
background-size: 3.78125rem 4.21875rem;
background-repeat: no-repeat;
}
到这里,应该可以说是很完美了,但还有改进的空间。我们需要自定义很多类,如:
.icon1 {
width: px2rem(image-width(sprite-file($icons, card-icon)));
height: px2rem(image-height(sprite-file($icons, card-icon)));
background-image: sprite-url($icons);
background-position: px2rem(sprite-position($icons, card-icon));
background-size: px2rem(($bigWidth, $bigHeight));
background-repeat: no-repeat;
}
.icon2 {
width: px2rem(image-width(sprite-file($icons, watch-icon)));
height: px2rem(image-height(sprite-file($icons, watch-icon)));
background-image: sprite-url($icons);
background-position: px2rem(sprite-position($icons, watch-icon));
background-size: px2rem(($bigWidth, $bigHeight));
background-repeat: no-repeat;
}
......
上面的每个类中的属性都是一样的,为什么不使用一个mixin
,把相同的属性都放进这个mixin
中,然后在每个类中引入就可以了。下面来定义一个mixin
:
@mixin sprite-info ($icons, $name) {
width: px2rem(image-width(sprite-file($icons, $name)));
height: px2rem(image-height(sprite-file($icons, $name)));
background-image: sprite-url($icons);
background-position: px2rem(sprite-position($icons, $name));
background-size: px2rem(($bigWidth, $bigHeight));
background-repeat: no-repeat;
}
使用这个mixin
:
.card {
@include sprite-info($icons, card-icon);
}
.watch {
@include sprite-info($icons, watch-icon);
}
生成css如下:
.card {
width: 1.20313rem;
height: 1rem;
background-image: url('/images/icons-s37f950be3b.png');
background-position: -1.46875rem -1.40625rem;
background-size: 3.78125rem 4.21875rem;
background-repeat: no-repeat;
}
.watch {
width: 1.3125rem;
height: 1.40625rem;
background-image: url('/images/icons-s37f950be3b.png');
background-position: 0 0;
background-size: 3.78125rem 4.21875rem;
background-repeat: no-repeat;
}
现在可以说是非常完美了。下面贴出icons.scss
文件中最终的代码:
$icons: sprite-map("icons/*.png", $spacing: 8px, $layout: smart);
$bigWidth: 242px;
$bigHeight: 270px;
@function px2rem ($px) {
@if (type-of($px) == "number") {
@return $px / 64px * 1rem;
}
@if (type-of($px) == "list") {
@if (nth($px, 1) == 0 and nth($px, 2) != 0) {
@return 0 nth($px, 2) / 64px * 1rem;
} @else if (nth($px, 1) == 0 and nth($px, 2) == 0) {
@return 0 0;
} @else if (nth($px, 1) != 0 and nth($px, 2) == 0) {
@return nth($px, 1) / 64px * 1rem 0;
} @else {
@return nth($px, 1) / 64px *1rem nth($px, 2) / 64px * 1rem;
}
}
}
@mixin sprite-info ($icons, $name) {
width: px2rem(image-width(sprite-file($icons, $name)));
height: px2rem(image-height(sprite-file($icons, $name)));
background-image: sprite-url($icons);
background-position: px2rem(sprite-position($icons, $name));
background-size: px2rem(($bigWidth, $bigHeight));
background-repeat: no-repeat;
}
.card {
@include sprite-info($icons, card-icon);
}
.watch {
@include sprite-info($icons, watch-icon);
}
生成的icons.css
代码如下:
.card {
width: 1.20313rem;
height: 1rem;
background-image: url('/images/icons-s37f950be3b.png');
background-position: -1.46875rem -1.40625rem;
background-size: 3.78125rem 4.21875rem;
background-repeat: no-repeat;
}
.watch {
width: 1.3125rem;
height: 1.40625rem;
background-image: url('/images/icons-s37f950be3b.png');
background-position: 0 0;
background-size: 3.78125rem 4.21875rem;
background-repeat: no-repeat;
}
转载本站文章《使用sass与compass合并雪碧图(一)》,
请注明出处:https://www.zhoulujun.cn/html/webfront/style/sass/2016_0307_7681.html