移动端适配之雪碧图(sprite)背景图片定位

为了减少网络请求个数量,提高网站的访问速度,我们一般都会把一些小的图片合并成一张sprite图,然后根据background-position来进行定位。在web端由于是固定的大小与left 、top,所以定位起来会比较准确、简单。但是在移动端就不一样了,各种手机的屏幕大小不一样,很难做到使用sprite图然后根据background-position来定位。所以普遍的做法都是使用单张图片,然后使用background-size: cover|100%|contain来控制背景图的大小。其实这样会简单得多,但是呢,如果图片太多,网速不好的情况下加载速度就惨不忍睹了。所以,根据之前的移动端适配之rem找到了解决方案。如果没有看过之前的文章,还是建议去看一下。

还是以视觉稿为 640px为例,这是视觉稿的一部分:

根据这个视觉稿,我切出来合并的sprite图张这样:

这是640px视觉稿切出来的图,如果只是适配640px的屏幕,直接使用px定位完全没有问题,但是考虑到其他的屏幕,所以我们会使用rem来等比例缩放背景图。是的,把原尺寸转换为rem就可以了。代码如下:

html代码结构

 1 <div class="test-sprites">
 2         <ul class="f-cb">
 3             <li class="icon1"></li>
 4             <li class="icon2"></li>
 5             <li class="icon3"></li>
 6             <li class="icon4"></li>
 7             <li class="icon5"></li>
 8             <li class="icon6"></li>
 9         </ul>
10     </div>

sass 代码

 1 .test-sprites{
 2     margin-top: 30px;
 3
 4     ul{
 5         padding: 0;
 6         margin: 0;
 7     }
 8
 9     li{
10         width: 0.48rem;
11         height: 0.7rem;
12         overflow: hidden;
13         border: 1px solid #ccc;
14         margin-left: 0.3rem;
15         float: left;
16         background:transparent url(‘http://nos.netease.com/edu-image/9BC0742AEB1A0B756EFC71B9DF77E452.png‘) 0 -0.02rem no-repeat;
17         background-size: 10.72rem 4.42rem;
18     }
19
20     .icon2{
21         width: 0.74rem;
22         height: 0.64rem;
23         background-position: -1.88rem -0.05rem;
24     }
25
26     .icon3{
27         width: 0.71rem;
28         height: 0.74rem;
29         background-position: -3.91rem -0.02rem;
30     }
31
32     .icon4{
33         width: 0.72rem;
34         height: 0.73rem;
35         background-position: -5.91rem -0.03rem;
36     }
37
38     .icon5{
39         width: 0.73rem;
40         height: 0.73rem;
41         background-position: -7.92rem -0.01rem;
42     }
43
44     .icon6{
45         width: 0.67rem;
46         height: 0.57rem;
47         background-position: -9.96rem -0.08rem;
48     }
49 }

我们平常使用background-size: 100%|cover|contain只是根据元素的宽高进行缩放的,那只对单张图片有用,因为此时百分比的大小是相对于元素的大小的,也就是说,一个100px*100px的div,使用一张1000px*1000px的sprite图做背景图片的,如果此时你给div加上background-size: 100%|cover|contain的话,那么整张sprite图就会被压缩成100*100的大小,这恐怕不是你想要的吧。

而我们的sprite是要根据它的原始大小来进行缩放的,先把px转化为rem,按照我的习惯是直接除以100px。也就得到类似background-size: 10.72rem 4.42rem;(原始1072px*442px)。这样sprite图就可以根据font-size进行缩放了。而且定位background-position直接使用原始的left-top 值除以100px就可以了,就是那么简单,BB了那么多,见证奇迹的时候到了。那我们直接上效果图:

看,是不是感觉适配得还不错。对的,大体上是可以了,但是呢,认真看看有一些手机里面,总会发现有点缺陷,有些图片少了那么1px,其实如果要求不严格的话这样也就差不多了。但是本着精益求精的原则,我们肯定是需要解决这个问题的。于是在网上查找,功夫不负有心人,找到了林小志_linxz的这么一篇文章
其中比较关键的是:

属性值为百分比时,将以图片的 中心点 为基准计算其相对位置,而使用px像素值时将以图片的 左上角(0 0)为基准。如果是10% 20%的这个值,那么就以图片的10% 20%的坐标点,放置在容器的10% 20%的位置。那这样理解的话,就是说明,如果是用百分比来作 background-position 的属性值的话,那么背景图片相对于容器的中心点是随时都在改变的。

加了background-position: 100% 100%;之后,就是把sprite图的B点移动到A点。如图

按照我的理解,就是把sprite图上的某一个点移动到元素上的某一个点,让这两个点重合。举个例子:我有一个400*400的div,200*200的sprite图,然后我给元素设置了background-position: 100% 100%;那么我们先找出这两个点,元素的(100% 100%)点A就是元素的右下角,sprite图的(100% 100%)点B在sprite图的右下角。如图

,就是这么个情况。代码如下:

 1 <style type="text/css">
 2     .box{
 3         width: 400px;
 4         height: 400px;
 5         border: 1px solid #ccc;
 6         margin: 100px auto;
 7         background: url(../images/200-1.jpg) no-repeat;
 8         background-position: 100% 100%;
 9     }
10 </style>
11 <div class="box">
12
13 </div>

但是这个是在我们知道百分比的情况下的,而我们需要做positon定位的时候需要的正是这个百分比,所以我们应该根据其他的变量把百分比求出来。我们可以把以上的情况转换成跟元素、sprite图、坐标有关的场景,比如类似:

当给元素加background-position: 10% 20%的时候,sprite图会先参考自身移动(-10% -20%)也就是改变自己的中心点,然后再根据元素的宽高来移动(10% 20%),最后sprite图会移动到一个点(X Y)。这个点就是我们需要显示在元素中icon的坐标。根据这个方式,总是可以把sprite图的某个点定位到元素的(0 0)位置。具体操作的demo

那重新梳理一下:
如果使用px来定位的话,那么sprite图是以左上角(0 0) 为中心点的,比如加上background-position:10px 20px;(此时sprite图的中心点在(0 0))那么图片的左边缘跟上边缘会往下移动20px,往右移动10px;我们平常使用的也是这种情况。

但是使用百分比来定位的话,那图片就不是以左上角为中心点了。比如加上background-position:10% 20%;那么背景sprite图片的中心点就会改变成图片 (10% 20%) 这个点了,比如原始sprite图片宽度为50px*50px,原始原始的中心点是(0 0);加了background-position:10% 20%;之后呢,中心点就变成了 (50px*10%  50px*20%) 也就是(5px, 10px)这个点,然后就会根据这个中心点来进行移动,假设元素的大小为200px*200px,根据推理,加了background-position:10% 20%;移动的步骤类似如下:

1、背景图片sprite图的中心点会改变成图片 10% 20% 这个点 即50*10% 50*20% 也就是(5px, 10px)(相当于把sprite图先移动(-5px -10px),也就是把sprite图的中心点移动端元素的左上角(0 0)处);

2、然后以sprite图的(5px 10px)点为中心点移动元素宽高度的10% 元素高度的20%,也就是往右往下移动了 20px 40px;
需要注意的是,这次的移动是以(5px 10px)这个中心点来移动的,就是把这个点先移动到父元素 0 0 的位置,再移动 20px 40px;
所以最终移动的距离是 (-5px+20px -10px+40px) 也就是 向右移动了15px 向下移动了30px 。

根据以上的推理,要想得到定位的百分比值(n m),我们需要 元素的宽高(w h), sprite图的宽高(k g),我们需要显示icon的坐标(x y),我们以向右向下移动端为正,向上向左为负。可以得到计算公式如下:

left: -n* k + n*w = -x
top: -m* g + m*h = -y

根据上面的公式,我们可以得到:

n = -x / (w-k) * 100%
m = -y / (h-g) * 100%

那举个例子:我们有一张200*200的sprite图,需要显示黄色的区块。

当我们的div宽度为 100*100时,可以得出n:100%, m: 100%,所以我们应该给元素加上background-position: 100% 100%;代码及效果如下:

 1 <style type="text/css">
 2  .box{
 3      width: 100px;
 4      height: 100px;
 5      border: 1px solid #ccc;
 6      margin: 100px auto;
 7      background: url(../images/200-1.jpg) no-repeat;
 8      background-position: 100% 100%;
 9  }
10 </style>
11 <div class="box">
12 </div>

            100*100效果图

当div的宽度为 150*300时,可以得出n:200% m: -100%;所以我们应该给元素加上background-position: 200% -100%;效果如下

  

                150*300效果图

经过验证,上面的计算公式的确是可以的,就是那么简单。但是我们也不能用一次就算一次吧,经过以上公式的整理,可以用sass写出一个fucntion 或者mixin,代码如下:

 1 //$spriteWidth 雪碧图的宽度px
 2 //$spriteHeight 雪碧图的高度px
 3 //$iconWidth 需要显示icon的宽度px
 4 //$iconHeight 需要显示icon的高度px
 5 //$iconX icon的原始x坐标
 6 //$iconY icon的原始y坐标
 7 //
 8 @mixin bgPosition($spriteWidth, $spriteHeight, $iconWidth, $iconHeight, $iconX, $iconY){
 9
10     background-position: (($iconX / ($spriteWidth - $iconWidth)) * 100% ($iconY / ($spriteHeight - $iconHeight)) * 100%);
11 }
12
13 //使用的方式
14 .test-sprites{
15     margin-top: 30px;
16
17     ul{
18         padding: 0;
19         margin: 0;
20     }
21
22     li{
23         width: 0.48rem;
24         height: 0.7rem;
25         overflow: hidden;
26         box-sizing: border-box;
27         margin-left: 0.3rem;
28         float: left;
29         background:transparent url(‘http://nos.netease.com/edu-image/9BC0742AEB1A0B756EFC71B9DF77E452.png‘) 0 -0.02rem no-repeat;
30         background-size: 10.72rem 4.42rem;
31     }
32
33     .icon2{
34         width: 0.74rem;
35         height: 0.64rem;
36         @include bgPosition(1072, 442, 74, 64, 188, 5);
37     }
38
39     .icon3{
40         width: 0.71rem;
41         height: 0.74rem;
42         @include bgPosition(1072, 442, 71, 74, 391, 2);
43     }
44
45     .icon4{
46         width: 0.72rem;
47         height: 0.73rem;
48         @include bgPosition(1072, 442, 72, 73, 591, 3);
49     }
50     .icon5{
51         width: 0.73rem;
52         height: 0.73rem;
53         @include bgPosition(1072, 442, 73, 73, 792, 1);
54     }
55     .icon6{
56         width: 0.67rem;
57         height: 0.57rem;
58         @include bgPosition(1072, 442, 67, 57, 996, 8);
59     }
60 }

就是下面这个图片,按照这样的方式,经过实践是没有问题的

                                    原始sprite图 1072*442

但是呢,以上的bgPosition感觉不够简洁,因为每次都要输入sprite图的宽高,那么可以在bgPosition的基础上再拓展一下;

 1 //同一张sprite图,横图
 2 @mixin bgPositionSameSprite($iconWidth, $iconHeight, $iconX, $iconY){
 3
 4     $spriteWidth : 1072;
 5     $spriteHeight : 442;
 6
 7     @include bgPosition($spriteWidth, $spriteHeight, $iconWidth, $iconHeight, $iconX, $iconY);
 8 }
 9
10 //同一张sprite图、竖图
11 @mixin bgPositionSameSprite-tow($iconWidth, $iconHeight, $iconX, $iconY){
12
13     $spriteWidth : 300;
14     $spriteHeight : 1000;
15
16     @include bgPosition($spriteWidth, $spriteHeight, $iconWidth, $iconHeight, $iconX, $iconY);
17 }

这样我们就只要输入四个参数了,那还能不能再简洁点呢,那只能看情况了,如果你的每个icon大小都一样的话,是完全没有问题的,你只需要输入每个icon的坐标就行,比如这样的图

                        

                           原始分享图片 220*220    

然后你就可以写这样的一个方法.

 1 //同一张sprite图并且每个icon的大小相同
 2 @mixin bgPositionSameSpriteAndWidth($iconX, $iconY){
 3
 4     $spriteWidth : 220;
 5     $spriteHeight : 220;
 6     $iconWidth : 61;
 7     $iconHeight : 61;
 8
 9     @include bgPosition($spriteWidth, $spriteHeight, $iconWidth, $iconHeight, $iconX, $iconY);
10 }
11 //使用
12 i{
13     padding-top: 100%;
14     width: 100%;
15     display: block;
16     background: url(http://nos.netease.com/edu-image/3A65D313376F13CE75CE01C2593BD1CE.png) 0 0 no-repeat;
17     background-size: 2.2rem 2.2rem;
18 }
19
20 .i-sina{
21     @include bgPositionSameSpriteAndWidth(10, 10);
22 }
23
24 .i-qzone{
25     @include bgPositionSameSpriteAndWidth(80, 10);
26 }
27
28 .i-qq{
29     @include bgPositionSameSpriteAndWidth(150, 10);
30 }
31
32 .i-douban{
33     @include bgPositionSameSpriteAndWidth(10, 80);
34 }
35
36 .i-yixin{
37     @include bgPositionSameSpriteAndWidth(80, 80);
38 }
39
40 .i-renren{
41     @include bgPositionSameSpriteAndWidth(150, 80);
42 }

以上方式方案可以完美解决适配定位问题,还能解放生产力。

时间: 2024-08-02 10:57:38

移动端适配之雪碧图(sprite)背景图片定位的相关文章

移动端雪碧图sprite的实现

移动端适配的时候,通常是用rem作为长宽单位,因此,在不同的设备下,元素的实际宽高(px)是不一样的,如果是单张图片作为为背景图片的时候,最为方便,只要设置背景图片的属性background-size:contain|conver|100%;都能够将图片盖住整个div. 其次如果用雪碧图的话,那么得将 背景图片的大小和位置改为rem单位.background-position:x.x rem  y.y rem;background-size : xxrem yyrem;此处就是将按照设计稿的px

移动端rem布局雪碧图解决方案 以及分享腾讯团队的在线雪碧图工具

先分享一下地址:http://alloyteam.github.io/gopng/ 使用的方法也很简单,将需要的小图标拖进去,全部拖进去后再调位置(每拖一个进去都会帮你排列好,但是没有间隔,所以全部拖进去后自己调) 然后点击右边绿色的make按钮即可 点击后,上面的选项会高亮,提示你制作好了, 点击PNG选项即可下载制作好的雪碧图, 点击css选项即可查看每个小图标在雪碧图中对应的x和Y位置 对于PC端来说,基本就完成了. 对于移动端采用rem布局的,则需要多一些步骤: 首先将对应的x和y位置转

FIS 雪碧图sprite合并

1 安装fis(必须先安装node和npm):npm install -g fis3 2 构建项目发布到根目录下的output:fis3 release -d ./output 项目根目录:FIS3 配置文件(默认fis-conf.js)所在的目录为项目根目录. 3 sprite的配置文件(fis-config.js)如下: fis.match('::packager', { spriter : fis.plugin('csssprites') }); fis.match('*.css', {

图片替换技术、雪碧图技术、图片透明技术、常用的电商布局方式

###雪碧图技术### !DOCTYPE html>     <html lang="en">     <head>     <meta charset="UTF-8">     <title>sprite雪碧图技术</title>         <style type="text/css">             div{                 widt

前端工程师技能之photoshop巧用系列第五篇——雪碧图

显示目录 目录 [1]定义 [2]应用场景 [3]合并[4]实现[5]维护 前面的话 前面已经介绍过,描述性图片最终要合并为雪碧图.本文是photoshop巧用系列第五篇--雪碧图 定义 css雪碧图(sprite)是一种网页图片应用处理方式,它允许将一个页面涉及到的所有零星图片都包含到一张大图中.使用雪碧图的处理方式可以实现两个优点: [1]减少http请求次数 [2]减少图片大小,提升网页加载速度 (多张图片加载速度小于拼合成的图片的加载速度) 凡事都不完美,实现优点的同时也带来了缺点,即提

使用grunt对css中的background图片自动生成雪碧图

公司研发的系统为B/S架构,用户使用浏览器访问系统时,使用浏览器自带工具查看,对图片的请求数极多,多为小图片. 今天想对这个现状进行改善,网上查到一种雪碧图的方案,其实就是使用工具将数量很多的小图片拼成一张大图片,然后css里都引用这张大图片,并指定显示该图片的某一个区域,但这个方案需要手工作很多处理. 于是就想到能不能用目前比较成熟的grunt对前端样式文件自动进行处理,自动生成雪碧图,自动修改样式文件.一搜索果然找到了方案,下面为Gruntfile.js文件的片断: module.expor

雪碧图(图片拼合技术)

雪碧图 (sprite)是一种图片拼合技术: 使用方法: 1.定视口 width: xx px; height: xx px; 2.插图 background-image: url("图片路径"); 3.移动位置 background-position: x轴坐标 y轴坐标: 优点:将小图标拼合到一张图片里,占用内存少,对开发人员来说就不用麻烦给每个小图标命名,还可以有效地加快网页的加载速度,可以有效增强用户体验: 缺点:需要利用相关图片查看软件找到每个小图标的准确坐标,相对来说比较繁

css中雪碧图(sprite)的使用及制作方法

雪碧图(sprite)是减少请求次数的有效手段,其原理是把多张图片进行合成,使用时通过css进行定位. 1.先看一下雪碧图 没有使用雪碧图时图标是这样一个个的单独文件: 合成雪碧图后是这样拼在一起的一张图:  2.雪碧图的使用 首先确定要使用的图标的位置和大小(可以通过ps测量), 如下的雪碧图大小统一,排列规则 它们的大小均为30px*30px,第一个图标位置为0 0,第二个的位置为30px 0,依次... 样式可以这样写: 1 .box1 li:nth-child(1) { 2 width:

compass与css sprite(雪碧图)

什么是css sprite? css sprite,中文叫雪碧图,也有人喊CSS精灵,就是一种背景拼合的技术,然后通过background-position来显示雪碧图中需要显示的图像. MDN相关链接:https://developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/CSS_Image_Sprites 优点:1.减少页面请求数 2.降低图片占用字节 缺点:1.拼图麻烦 2.后期维护麻烦 为什么使用compass? 最近项目中需要使用到很多小图片,想用