移動端適配之雪碧圖(sprite)背景圖片定位

爲了減小網絡請求個數量,提升網站的訪問速度,咱們通常都會把一些小的圖片合併成一張sprite圖,而後根據background-position來進行定位。在web端因爲是固定的大小與left 、top,因此定位起來會比較準確、簡單。可是在移動端就不同了,各類手機的屏幕大小不同,很難作到使用sprite圖而後根據background-position來定位。因此廣泛的作法都是使用單張圖片,而後使用background-size: cover|100%|contain來控制背景圖的大小。其實這樣會簡單得多,可是呢,若是圖片太多,網速很差的狀況下加載速度就慘不忍睹了。因此,根據以前的移動端適配之rem找到了解決方案。若是沒有看過以前的文章,仍是建議去看一下。css

仍是以視覺稿爲 640px爲例,這是視覺稿的一部分:html

根據這個視覺稿,我切出來合併的sprite圖張這樣:git

這是640px視覺稿切出來的圖,若是隻是適配640px的屏幕,直接使用px定位徹底沒有問題,可是考慮到其餘的屏幕,因此咱們會使用rem來等比例縮放背景圖。是的,把原尺寸轉換爲rem就能夠了。代碼以下:github

html代碼結構web

 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 代碼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的這麼一篇文章
其中比較關鍵的是:url

 

屬性值爲百分比時,將以圖片的 中心點 爲基準計算其相對位置,而使用px像素值時將以圖片的 左上角(0 0)爲基準。若是是10% 20%的這個值,那麼就以圖片的10% 20%的座標點,放置在容器的10% 20%的位置。那這樣理解的話,就是說明,若是是用百分比來做 background-position 的屬性值的話,那麼背景圖片相對於容器的中心點是隨時都在改變的。spa

 加了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%;移動的步驟相似以下:

一、背景圖片sprite圖的中心點會改變成圖片 10% 20% 這個點 即50*10% 50*20% 也就是(5px, 10px)(至關於把sprite圖先移動(-5px -10px),也就是把sprite圖的中心點移動端元素的左上角(0 0)處);

二、而後以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 }

以上方式方案能夠完美解決適配定位問題,還能解放生產力。

相關文章
相關標籤/搜索