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

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

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

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

html代码结构

 <div class="test-sprites">
<ul class="f-cb">
<li class="icon1"></li>
<li class="icon2"></li>
<li class="icon3"></li>
<li class="icon4"></li>
<li class="icon5"></li>
<li class="icon6"></li>
</ul>
</div>

sass 代码

 .test-sprites{
margin-top: 30px; ul{
padding:;
margin:;
} li{
width: 0.48rem;
height: 0.7rem;
overflow: hidden;
border: 1px solid #ccc;
margin-left: 0.3rem;
float: left;
background:transparent url('http://nos.netease.com/edu-image/9BC0742AEB1A0B756EFC71B9DF77E452.png') 0 -0.02rem no-repeat;
background-size: 10.72rem 4.42rem;
} .icon2{
width: 0.74rem;
height: 0.64rem;
background-position: -1.88rem -0.05rem;
} .icon3{
width: 0.71rem;
height: 0.74rem;
background-position: -3.91rem -0.02rem;
} .icon4{
width: 0.72rem;
height: 0.73rem;
background-position: -5.91rem -0.03rem;
} .icon5{
width: 0.73rem;
height: 0.73rem;
background-position: -7.92rem -0.01rem;
} .icon6{
width: 0.67rem;
height: 0.57rem;
background-position: -9.96rem -0.08rem;
}
}

我们平常使用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图的右下角。如图

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

 <style type="text/css">
.box{
width: 400px;
height: 400px;
border: 1px solid #ccc;
margin: 100px auto;
background: url(../images/200-1.jpg) no-repeat;
background-position: 100% 100%;
}
</style>
<div class="box"> </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%;代码及效果如下:

 <style type="text/css">
.box{
width: 100px;
height: 100px;
border: 1px solid #ccc;
margin: 100px auto;
background: url(../images/200-1.jpg) no-repeat;
background-position: 100% 100%;
}
</style>
<div class="box">
</div>

            100*100效果图

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

  

                150*300效果图

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

 //$spriteWidth 雪碧图的宽度px
//$spriteHeight 雪碧图的高度px
//$iconWidth 需要显示icon的宽度px
//$iconHeight 需要显示icon的高度px
//$iconX icon的原始x坐标
//$iconY icon的原始y坐标
//
@mixin bgPosition($spriteWidth, $spriteHeight, $iconWidth, $iconHeight, $iconX, $iconY){ background-position: (($iconX / ($spriteWidth - $iconWidth)) * 100% ($iconY / ($spriteHeight - $iconHeight)) * 100%);
} //使用的方式
.test-sprites{
margin-top: 30px; ul{
padding: 0;
margin: 0;
} li{
width: 0.48rem;
height: 0.7rem;
overflow: hidden;
box-sizing: border-box;
margin-left: 0.3rem;
float: left;
background:transparent url('http://nos.netease.com/edu-image/9BC0742AEB1A0B756EFC71B9DF77E452.png') 0 -0.02rem no-repeat;
background-size: 10.72rem 4.42rem;
} .icon2{
width: 0.74rem;
height: 0.64rem;
@include bgPosition(1072, 442, 74, 64, 188, 5);
} .icon3{
width: 0.71rem;
height: 0.74rem;
@include bgPosition(1072, 442, 71, 74, 391, 2);
} .icon4{
width: 0.72rem;
height: 0.73rem;
@include bgPosition(1072, 442, 72, 73, 591, 3);
}
.icon5{
width: 0.73rem;
height: 0.73rem;
@include bgPosition(1072, 442, 73, 73, 792, 1);
}
.icon6{
width: 0.67rem;
height: 0.57rem;
@include bgPosition(1072, 442, 67, 57, 996, 8);
}
}

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

                                    原始sprite图 1072*442

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

 //同一张sprite图,横图
@mixin bgPositionSameSprite($iconWidth, $iconHeight, $iconX, $iconY){ $spriteWidth :;
$spriteHeight :; @include bgPosition($spriteWidth, $spriteHeight, $iconWidth, $iconHeight, $iconX, $iconY);
} //同一张sprite图、竖图
@mixin bgPositionSameSprite-tow($iconWidth, $iconHeight, $iconX, $iconY){ $spriteWidth :;
$spriteHeight :; @include bgPosition($spriteWidth, $spriteHeight, $iconWidth, $iconHeight, $iconX, $iconY);
}

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

                        

                           原始分享图片 220*220    

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

 //同一张sprite图并且每个icon的大小相同
@mixin bgPositionSameSpriteAndWidth($iconX, $iconY){ $spriteWidth :;
$spriteHeight :;
$iconWidth :;
$iconHeight :; @include bgPosition($spriteWidth, $spriteHeight, $iconWidth, $iconHeight, $iconX, $iconY);
}
//使用
i{
padding-top: 100%;
width: 100%;
display: block;
background: url(http://nos.netease.com/edu-image/3A65D313376F13CE75CE01C2593BD1CE.png) 0 0 no-repeat;
background-size: 2.2rem 2.2rem;
} .i-sina{
@include bgPositionSameSpriteAndWidth(10, 10);
} .i-qzone{
@include bgPositionSameSpriteAndWidth(80, 10);
} .i-qq{
@include bgPositionSameSpriteAndWidth(150, 10);
} .i-douban{
@include bgPositionSameSpriteAndWidth(10, 80);
} .i-yixin{
@include bgPositionSameSpriteAndWidth(80, 80);
} .i-renren{
@include bgPositionSameSpriteAndWidth(150, 80);
}

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

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

  1. 移动端雪碧图sprite的实现

    移动端适配的时候,通常是用rem作为长宽单位,因此,在不同的设备下,元素的实际宽高(px)是不一样的,如果是单张图片作为为背景图片的时候,最为方便,只要设置背景图片的属性background-size ...

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

    先分享一下地址:http://alloyteam.github.io/gopng/ 使用的方法也很简单,将需要的小图标拖进去,全部拖进去后再调位置(每拖一个进去都会帮你排列好,但是没有间隔,所以全部拖 ...

  3. FIS 雪碧图sprite合并

    1 安装fis(必须先安装node和npm):npm install -g fis3 2 构建项目发布到根目录下的output:fis3 release -d ./output 项目根目录:FIS3 ...

  4. 关于css雪碧图sprite

    天气转凉了,又开始贪恋暖暖的被窝了. 早上不想起床的时候在被窝里看了有关于雪碧图的视频. 1.使用场景 V导航条,登录框img标签多次载入,性能低 X大图banner按需加载,如果做成雪碧图一次加载就 ...

  5. CSS——精灵图与背景图片定位

    精灵图产生背景: 1.网页上的每张图像都需要向服务器发送一次请求才能展现给用户.2.网页上的图像过多时,服务器就会频繁地接受和发送请求,大大降低页面的加载速度.为了有效地减少服务器接受和发送请求的次数 ...

  6. CSS Sprite雪碧图应用

    在写网页过程中,会遇到这种需要使用多个小图标: 如上图中的「女装」文字左边的图标.容易想到的解决方法是为每张图片加入<img>标签,但这样做会增加HTTP请求数量,影响网站加载速度.比这更 ...

  7. CSS Sprite雪碧图的应用

    CSS雪碧图,即CSS Sprite,也有人叫它CSS精灵图,是一种图像拼合技术.该方法是将多个小图标和背景图像合并到一张图片上,然后利用CSS的背景定位来显示需要显示的图片部分. 雪碧图的使用场景 ...

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

    × 目录 [1]定义 [2]应用场景 [3]合并[4]实现[5]维护 前面的话 前面已经介绍过,描述性图片最终要合并为雪碧图.本文是photoshop巧用系列第五篇——雪碧图 定义 css雪碧图(sp ...

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

    雪碧图(sprite)是减少请求次数的有效手段,其原理是把多张图片进行合成,使用时通过css进行定位. 1.先看一下雪碧图 没有使用雪碧图时图标是这样一个个的单独文件: 合成雪碧图后是这样拼在一起的一 ...

随机推荐

  1. mysql备份参数--master-data和--dump-slave的介绍

    [mysql@db2 ~]$ mysqldump -A --master-data=2 > master2.sql[mysql@db2 ~]$ mysqldump -A --master-dat ...

  2. 查看sql语句加锁信息

    问题: 最近使用quartz集群,总是报deadlock问题,所以需要查看一下执行的sql导致的加锁冲突. 步骤: 1.在要测试的库中创建指定表innodb_lock_monitor create t ...

  3. 02 Go 1.2 Release Notes

    Go 1.2 Release Notes Introduction to Go 1.2 Changes to the language Use of nil Three-index slices Ch ...

  4. 04 Effective Go 高效的go语言 重点内容

    Effective Go  高效的go语言 Introduction 介绍 Examples 例子 Formatting 格式 Commentary 评论 Names 名字 Package names ...

  5. Scrapy官网程序执行示例

    Windows 10家庭中文版本,Python 3.6.4,Scrapy 1.5.0, Scrapy已经安装很久了,前面也看了不少Scrapy的资料,自己尝试使其抓取微博的数据时,居然连登录页面(首页 ...

  6. java基础60 JavaScript字符串转换成数字(网页知识)

    1.字符串转换成数字 <!doctype html> <html> <head> <meta charset="utf-8"> &l ...

  7. JSP和Servlet那些事儿系列--HTTPS

    原文:http://qingkangxu.iteye.com/blog/1614053 <JSP和Servlet那些事儿 >系列文章旨在阐述Servlet(Struts和Spring的MV ...

  8. 洛谷P1120 小木棍(升级版)

    传送门啦 一道经典的搜索剪枝题,不废话,步入正题. 分析: 一.输入时手动过滤不合法的情况 二.很明显我们要枚举把哪些棍子拼接成原来的长棍,而原始长度(原来的长棍的长度)都相等,因此我们可以在 $ d ...

  9. TIAGo ROS模拟教程2 - 自主机器人导航

    TIAGo ROS Simulation Tutorial 2 – Autonomous robot navigation TIAGo ROS模拟教程2 - 自主机器人导航 发表于 12月 23,20 ...

  10. IdentityServer4揭秘---登录

    IdentityServer4默认提供了的登录地址是Account/Index 同意页面是Consent/Index 这里我们可以通过IdentittyServer4的用户交互自定义配置设置 在Con ...