一、概述

  在传统的居中布局时,我们常用background-position这个属性来进行雪碧图的定位,在减少数据量的同时,保证准确定位。在移动端使用越来越重的现在,以往的传统定位,已经无法达到目的,那么是否有合适的解决方案呢?答案是有的,让我们先来了解background的两个属性:

    background-position:背景图片相对容器原点的起始位置。详解可以查看另一篇博客:background-position 详解

    background-size: 规定背景图的尺寸;

      语法:background-size: width height;

      取值:auto | length percentage | cover | contain
                auto: 自适应;
                length:确定的宽高;
                cover:把背景图像扩展至足够大,以使背景图像完全覆盖背景区域;
                contain:把图像图像扩展至最大尺寸,以使其宽度和高度完全适应内容区域;
                百分比:以父元素的百分比来设置背景图像的宽度和高度。
  
  预备知识已经ready,接下来如何解决问题。
  

  来看以下四种场景:
        场景1、非响应式下的雪碧图,且子图尺寸相同
        场景2、响应式下的雪碧图,且子图尺寸相同
        场景3、非响应式下的雪碧图,且子图尺寸不同
        场景4、响应式下的雪碧图,且子图尺寸不同
  

二、子图尺寸相同

  该场景下,由于子图的尺寸相同,完全可以使用%来减少人为计算。使用%需要用到换算公式,由background-position 详解的结论,可知:
background-position: a% b%; =》 background-position: x y;
其中:containerWidth为容器宽,containerHeight为容器高,bgWidth为雪碧图宽,bgHeight为雪碧图宽,
则存在(公式1):
  x = (containerWidth - bgWidth) * a%
  y = (containerHeight - bgHeight) * b%
  示例如下: 

    
     图2.1  原图[654 vs 436 即 218 * 3 vs 218 * 2]
 
        想要的结果:选择第一排,第二张图
    
      图2.2   预期结果
 

  2.1、场景1:传统布局

    传统布局下,容器尺寸与子图的尺寸相同,由公式1可推出以下结论:

由于子图尺寸相同,得出(公式2):
  bgWidth = xTotal * containerWidth;
  bgHeight = yTotal * containerHeight;
其中xTotal为雪碧图横向的子图数量,yTotal为雪碧图纵向的子图数量。 由公式1、公式2可推导出(公式3):
  a% = x / (containerWidth - bgWidth) 
= x / (containerWidth - xTotal * containerWidth)
= x / (1 - xTotal) * containerWidth   b% = y / (containerHeight - bgHeight)
= y / (containerHeight - yTotal * containerHeight)
= y / (1 - yTotal) * containerHeight 定位时,背景图的起始点,时常在某个子图的起始点上,所以可以推导出(公式4):
  a% = x / (1 - xTotal) * containerWidth
    = n * containerWidth / (1 - xTotal) * containerWidth
    = n / (1 - xTotal)   b% = y / (1 - yTotal) * containerHeight
    = m * containerHeight / (1 - yTotal) * containerHeight
= m / (1 - yTotal)
  其中,m、n一定是一个小于等于0的数。   需要得到预期结果,使用公式4,
  起始位置:x=-1 * containerWidth,y = 0 * containerHeight;
     so: n=-1,m=0;
  子图数:xTotal = 3; yTotal = 2; 要得到第二张图的显示定位应该为:      
  a% = n / (1 - xTotal) = -1 / (1 - 3) = 50%
  b% = m / (1 - yTotal) = 0 / 1 - 2 = 0%
    以下代码得到预期结果:

width: 218px;
height: 218px;
background-position: 50% 0;
background-repeat: no-repeat;

  2.2、场景2:响应式布局下

    回顾公式1:   

      x = (containerWidth - bgWidth) * a%       

      y = (containerHeight - bgHeight) * b%

    响应式情景下,containerWidth会缩放,而此时bgWidth的值不会变化,使得公式2无法得到。
    解决该问题的关键是,使得bgWidth的大小,随着containerWidth的变化而变化。
    再回过头看看background-size这个属性,它可以使得背景图根据容器的变化而变化,且它的百分比属性可以以父元素的百分比来设置背景图像的宽度和高度,从而达到父容器与背景图的一个对应关系。

    如果需要获得公式2,那么需要将背景图按照怎样的方式变化呢?

    当 background-size: 100% auto;时,得到的结果:

    

        图2.3  100%

    由此可看出,当xpos为100%时,背景图缩放到父容器相同大小。

    当xpos为300%时,背景图缩放到父容器的3倍大,此时背景图与父容器的关系同场景一相同,从而可以应用公式2,此时的xTotal既代表子图横向的数量,也表示背景图横向的收缩比。

    由此当是如下代码,亦可得到预期的第二张图:

width: 118px;
height: 118px;
background-size: 300% auto;
background-position: 50% 0;
background-repeat: no-repeat;

  总结:在响应式下,且子图尺寸相同时,将background-size 的缩放比设置成与子图数量相同,再通过background-position可实现轻松定位。x,y任意方向设置缩放比,另一方向可使用auto值,实现背景图的等比例缩放。此例中,虽然子图的形状为正方形,但实际操作中,不要求。矩形一样可以按照同样的公式实现,因为纵轴和横轴的计算都是分开的,相互没有影响。

三、子图尺寸不同

  在子图尺寸不同的情况下,通常我们不会使用百分比定位,而是选择具体值定位。  示例:

    

    图3.1 不规则雪碧图

  取到白色遮罩覆盖的花环:

       

        图3.2 目标子图

  3.1、场景3:传统布局下的定位

    代码如下:    

border: 1px solid red;
width: 282px;
height: 301px;
background-position: -369px -394px;
background-repeat: no-repeat;

    直接使用具体值定位,较为简单,容器盒子的尺寸与目标子图的尺寸相同,定位位置为容器盒子在背景图中的偏移位置,结果与预期相符。

  3.2、场景4:响应式下的定位

    回到场景1,其中有三个定位的关键因素:

      a、盒子尺寸;

      b、盒子相对背景图的偏移位置;

      c、背景图尺寸(决定目标子图尺寸、从而决定盒子尺寸);

    在响应式下,通常盒子的尺寸会跟随屏幕的伸缩而变化,如何使得最初的定位,不会因为盒子尺寸的变化而发生改变呢?

    回到示例图3.1,想象一下如果我们将背景图、容器盒子、定位位置三者一起进行伸缩,那么会怎么样呢?定位仍然在目标子图,不会发生变化。

  在变化过程中,只要缺少一个因素,就会发生错位。因此解决问题的关键是:三个因素,等比例伸缩。

    我们看下赋值:

      盒子伸缩:width: newWidth; height: newHeight;  

      偏移伸缩:background-position: newX newY;

      背景图尺寸: background-size: newWidth/auto auto/newHeight;

    关于几个新值的计算:是一个换算过程,方法有多种,可以按照具体项目的换算方法进行。我使用的是hotcss的方法,只需要给出原尺寸,便可轻松实现转换,这里不再展开,有兴趣的同学,可以上github了解:hotcss

               

        图3.3 响应式下的定位

    调试器中给出的代码是hotcss编译之后的结果,源码如下(px2rem为hotcss的一个转换函数):    

.test {
margin: px2rem(100);
border: 1px solid red;
width: px2rem(282);
height: px2rem(301);
background-position: px2rem(-369) px2rem(-394);
background-size: px2rem(1024) auto;
background-image: url($imgpath + "temp/flower-3-new.jpg");
background-repeat: no-repeat
}

  总结:雪碧图的四种情况在本文中都给出了解决方案,场景1、2给出了子图尺寸相同时的定位,其中使用到了%,大大减少了计算。%的使用,让我们不再关注原来的尺寸,这个换算的过程映射到了基于一种相对比例关系(子图数量)进行的计算。场景3、4解决了子图不同的情况,这时,需要我们拿到三组关键值:原背景图大小、原容器大小、原相对位移,再利用关键值实现伸缩后的映射,从而实现定位。

 

响应式下的雪碧图解决方案 - 活用background-size / background-position的更多相关文章

  1. Vue-cli3.0下的雪碧图插件webpack-spritesmith配置方法

    在前端项目中,为了减少对图片的请求次数,一般而言需要进行雪碧图的配置.即将多张小图标合并成一张图片,这样页面中的小图标都在一张图片上,只需请求一张图片,就可以通过CSS设置各个小图标的显示,利于节省带 ...

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

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

  3. Vue-cli在webpack内使用雪碧图(响应式)

    先执行install cnpm install webpack-spritesmith 文件位置 build\webpack.dev.conf.js 添加内容: const SpritesmithPl ...

  4. CSS Sprite雪碧图应用

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

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

    为了减少网络请求个数量,提高网站的访问速度,我们一般都会把一些小的图片合并成一张sprite图,然后根据background-position来进行定位.在web端由于是固定的大小与left .top ...

  6. 前端优化:css雪碧图实践应用详解

    一 为什么需要使用雪碧图 二CSS雪碧图原理及应用 前端是接近用户体验的一个项目组成部分,合适的优化能够大大减少网页响应时间,合理的资源加载自然成为了工作中的要务,现在就结合实例讲解到底什么是css雪 ...

  7. shoeBox超实用的雪碧图(Sprite)图制作工具-使用

    从前端优化说起 浏览器载入单张图片的速度基本取决于图片的大小,但是载入多张图片的速度却和另一个要素息息相关-网络请求数,在图片大小和一致的情况下,图片张数越少其请求数越少其载入速度也就越快.所以在使用 ...

  8. 用FSM一键制作逐帧动画雪碧图 Vue2 + webpack

    因为工作需要要将五六十张逐帧图拼成雪碧图,网上想找到一件制作工具半天没有找到,就自己用canvas写了一个. 写成之后就再没有什么机会使用了,因此希望有人使用的时候如果遇到bug了能及时反馈给我. 最 ...

  9. 原创:CSS3技术-雪碧图自适应缩放与精灵动画方案

    花了一个礼拜完成了慕课网定制的七夕主题效果,其中有一个没实现好的功能,就是雪碧图的自适应缩放 ps: 以下实现都是基于移动端的处理 原图如下: 人物是采用的是雪碧图,通过坐标绝对数据取值 问题很明显, ...

随机推荐

  1. tar.gz 解压

    tar -xzvf .tar.gz tar [-cxtzjvfpPN] 文件与目录 .... 参数: -c :建立一个压缩文件的参数指令(create 的意思): -x :解开一个压缩文件的参数指令! ...

  2. Flex 布局里 input 宽度最小 150px 的问题, 浏览器 BUG?

    今天在使用 flex 布局时, 发现当 flex 布局容器比小(小于 150px )时,里面的 input[text] 的宽度会比容器宽: <style> #main { width:12 ...

  3. 杭州.Net 相关大公司,希望对大家有帮助

    本人目前大四,还在实习.北京工作辞职后,打算回杭州看看.发现杭州的大公司相对北京好少啊,招.Net相关的公司就更少了... (我认为刚毕业生还是去大公司比较靠谱,一方面也是实力的体现)大学生,而且之前 ...

  4. PHP set_error_handler()函数的使用

    我们写程序,难免会有问题(是经常会遇到问题 ),而PHP遇到错误时,就会给出出错脚本的位置.行数和原因.有很多人说,这并没有什么大不了.确实,在调试程序阶段,这确实是没啥的,而且我认为给出错误路径是必 ...

  5. CodeForces1142/1143题解

    题面 传送门(1143) 传送门(1142) \(1143A\) 咕咕 n=read(); fp(i,1,n)a[i]=read(),++cnt[a[i]]; fp(i,1,n)if(++c[a[i] ...

  6. jzoj5813

    tj:可以知道,隨意構造一個數列x,且x的第i位被n整除的方案是(約數個數)^2m,因為所有數可以隨便選,只要這個數能被n整除即可,方案為約數個數 設一個合法數列a的f值為x,則x小於n^m 假設所有 ...

  7. RecyclerView的通用适配器

    本来这一个主题应该早就写了,只是项目多,属于自己的时间不多,所以现在才开动!! 前一段时间写了一篇文章,是关于ListView,GriView万能适配器,没有看过的同学,可以先看看那篇文章,然后在来学 ...

  8. Python Socket 编程示例 Echo Server

    简评:我们已经从「Python Socket 编程概览」了解了 socket API 的概述以及客户端和服务器的通信方式,接下来让我们创建第一个客户端和服务器,我们将从一个简单的实现开始,服务器将简单 ...

  9. 读取Properties文件的六种方法

    1.使用java.util.Properties类的load()方法 示例: InputStream in = new BufferedInputStream(new FileInputStream( ...

  10. sele nium 模块

    python3 web测试模块selenium   阅读目录 1.selenium安装配置 2.Selenium的基本使用 (1)声明浏览器对象 (2)定位元素 (3)元素对象(element) (4 ...