從淘寶適配布局談移動端適配


轉自:http://www.w3cfuns.com/notes/23659/5e3cd2904a56f5e6b86c4d49e90e0f34.html

一、        首先我們先來看看淘寶不同分辨率下的適配頁面

從淘寶適配布局談移動端適配

                          

可以看出來,淘寶在不同的分辨率下,頁面的尺寸和模塊間的間距會發生變化,這是因為淘寶采用了rem,這篇文章會簡單介紹淘寶的布局思路以及具體做法,不過在此之前我們先了解一些移動端的知識,以為更好的理解淘寶布局的方案,下面我們來看一些移動端的知識



二、了解一些移動端的知識
viewport的<meta>標簽用法

其主要用來告訴瀏覽器如何規范的渲染Web頁面,而你則需要告訴它視窗有多大

移動端開發中,通常我們都會采用<meta name="viewport"   content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">來設置viewport,那么viewport是什么樣的原理控制頁面適配呢?

所以在講淘寶的具體做法之前,我們先來深入了解viewport



viewport是什么?

通俗來講,移動端的viewport就是我們所能看到的手機端瀏覽器的可視窗口大小,但viewport又不僅僅局限於可視窗口的大小,一般情況下,它是比默認窗口大小要大的,這是因為考慮到移動設備的分辨率相對於桌面電腦來說都比較小,所以為了能在移動端正常顯示為桌面瀏覽器而設計的網頁,移動端的瀏覽器都會默認把自己的默認的viewport設為980px到1024px不等,但其后果就是會出現橫向滾動條,因為移動端瀏覽器可視區域的大小是比默認的viewport寬度要小的。



不同的設備對1px有不一樣的定義

在css中我們一般使用px作為單位,在桌面瀏覽器中css的1個像素往往都是對應着電腦屏幕的1個物理像素,這可能會造成我們的一個錯覺,那就是css中的像素就是設備的物理像素。但實際情況卻並非如此,css中的像素只是一個抽象的單位,在不同的設備或不同的環境中,css中的1px所代表的設備物理像素是不同的。在為桌面瀏覽器設計的網頁中,我們無需對這個津津計較,但在移動設備上,必須弄明白這點。在早先的移動設備中,屏幕像素密度都比較低,如iphone3,它的分辨率為320x480,在iphone3上,一個css像素確實是等於一個屏幕物理像素的。后來隨着技術的發展,移動設備的屏幕像素密度越來越高,從iphone4開始,蘋果公司便推出了所謂的Retina屏,分辨率提高了一倍,變成640x960,但屏幕尺寸卻沒變化,這就意味着同樣大小的屏幕上,像素卻多了一倍,這時,一個css像素是等於兩個物理像素的。

在移動端瀏覽器中以及某些桌面瀏覽器中,window對象有一個devicePixelRatio屬性,它的官方的定義為:設備物理像素和設備獨立像素的比例,也就是 devicePixelRatio = 物理像素 / 獨立像素。css中的px就可以看做是設備的獨立像素,所以通過devicePixelRatio,我們可以知道該設備上一個css像素代表多少個物理像素。例如,在Retina屏的iphone上,devicePixelRatio的值為2,也就是說1個css像素相當於2個物理像素

       

以iphone6為例:

       

設備寬高為375×667,可以理解為設備獨立像素(或css像素)。

       

dpr為2,根據上面的計算公式,其物理像素就應該×2,為750×1334。

       

用一張圖來表現,就是這樣:

從淘寶適配布局談移動端適配


           



關於三個viewport的理論

ppk大神對於移動設備上的viewport有着非常多的研究(第一篇第二篇第三篇),有興趣的同學可以去看一下

ppk認為,移動設備上有三個viewport。包括layout viewport、visual viewprt、ideal viewport

layout viewport: 首先,移動設備上的瀏覽器認為自己必須能讓所有的網站都正常顯示,即使是那些不是為移動設備設計的網站。但如果以瀏覽器的可視區域作為viewport的話,因為移動設備的屏幕都不是很寬,所以那些為桌面瀏覽器設計的網站放到移動設備上顯示時,必然會因為移動設備的viewport太窄,而擠作一團,甚至布局什么的都會亂掉。也許有人會問,現在不是有很多手機分辨率都非常大嗎,比如768x1024,或者1080x1920這樣,那這樣的手機用來顯示為桌面瀏覽器設計的網站是沒問題的吧?前面我們已經說了,css中的1px並不是代表屏幕上的1px,你分辨率越大,css中1px代表的物理像素就會越多,devicePixelRatio的值也越大,這很好理解,因為你分辨率增大了,但屏幕尺寸並沒有變大多少,必須讓css中的1px代表更多的物理像素,才能讓1px的東西在屏幕上的大小與那些低分辨率的設備差不多,不然就會因為太小而看不清。所以在1080x1920這樣的設備上,在默認情況下,也許你只要把一個div的寬度設為300多px(視devicePixelRatio的值而定),就是滿屏的寬度了。回到正題上來,如果把移動設備上瀏覽器的可視區域設為viewport的話,某些網站就會因為viewport太窄而顯示錯亂,所以這些瀏覽器就決定默認情況下把viewport設為一個較寬的值,比如980px,這樣的話即使是那些為桌面設計的網站也能在移動瀏覽器上正常顯示了。ppk把這個瀏覽器默認的viewport叫做 layout viewport。這個layout viewport的寬度可以通過document.documentElement.clientWidth 來獲取。

然而,layout viewport 的寬度是大於瀏覽器可視區域的寬度的,所以我們還需要一個viewport來代表 瀏覽器可視區域的大小,ppk把這個viewport叫做 visual viewport。visual viewport的寬度可以通過window.innerWidth 來獲取

如下所示便是layout viewport 和visual viewport的區別,簡單明了吧

從淘寶適配布局談移動端適配



現在我們已經有兩個viewport了:layout viewport 和 visual viewport。但瀏覽器覺得還不夠,因為現在越來越多的網站都會為移動設備進行單獨的設計,所以必須還要有一個能完美適配移動設備的viewport。所謂的完美適配指的是,首先不需要用戶縮放和橫向滾動條就能正常的查看網站的所有內容;第二,顯示的文字的大小是合適,比如一段14px大小的文字,不會因為在一個高密度像素的屏幕里顯示得太小而無法看清,理想的情況是這段14px的文字無論是在何種密度屏幕,何種分辨率下,顯示出來的大小都是差不多的。當然,不只是文字,其他元素像圖片什么的也是這個道理。ppk把這個viewport叫做 ideal viewport,也就是第三個viewport——移動設備的理想viewport。

ideal viewport並沒有一個固定的尺寸,不同的設備擁有有不同的ideal viewport。所有的iphone的ideal viewport寬度都是320px,無論它的屏幕寬度是320還是640,也就是說,在iphone中,css中的320px就代表iphone屏幕的寬度。

從淘寶適配布局談移動端適配

 

但是安卓設備就比較復雜了,有320px的,有360px的,有384px的等等,關於不同的設備ideal viewport的寬度都為多少,可以到http://viewportsizes.com去查看一下,里面收集了眾多設備的理想寬度。

     

再總結一下:ppk把移動設備上的viewport分為layout viewport、visual viewport和ideal viewport三類,其中的ideal viewport是最適合移動設備的viewport,ideal viewport的寬度等於移動設備的屏幕寬度,只要在css中把某一元素的寬度設為ideal viewport的寬度(單位用px),那么這個元素的寬度就是設備屏幕的寬度了,也就是寬度為100%的效果。ideal viewport 的意義在於,無論在何種分辨率的屏幕下,那些針對ideal viewport 而設計的網站,不需要用戶手動縮放,也不需要出現橫向滾動條,都可以完美的呈現給用戶。


利用meta標簽對viewport進行控制
       

移動設備默認的viewport是layout viewport,也就是那個比屏幕要寬的viewport,但在進行移動設備網站的開發時,我們需要的是ideal viewport。那么怎么才能得到ideal viewport呢?這就該輪到meta標簽出場了。

       

在文章一開始我們就說,進行移動端開發時,我們一般都會加上這么一句:

       

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1,user-scalable=no">

       

該meta標簽的作用是讓當前viewport的寬度等於設備的寬度,同時不允許用戶手動縮放。也許允不允許用戶縮放不同的網站有不同的要求,但讓viewport的寬度等於設備的寬度,這個應該是大家都想要的效果,如果你不這樣的設定的話,那就會使用那個比屏幕寬的默認viewport,也就是說會出現橫向滾動條。

       

這個name為viewport的meta標簽到底有哪些東西呢,又都有什么作用呢?

meta viewport 標簽首先是由蘋果公司在其safari瀏覽器中引入的,目的就是解決移動設備的viewport問題。后來安卓以及各大瀏覽器廠商也都紛紛效仿,引入對meta viewport的支持,事實也證明這個東西還是非常有用的。

       

在蘋果的規范中,meta viewport 有6個屬性(暫且把content中的那些東西稱為一個個屬性和值),如下:

 

width 設置layout viewport  的寬度,為一個正整數,或字符串"device-width"
initial-scale 設置頁面的初始縮放值,為一個數字,可以帶小數
minimum-scale 允許用戶的最小縮放值,為一個數字,可以帶小數
maximum-scale 允許用戶的最大縮放值,為一個數字,可以帶小數
height 設置layout viewport  的高度,這個屬性對我們並不重要,很少使用
user-scalable 是否允許用戶進行縮放,值為"no"或"yes", no 代表不允許,yes代表允許

 

把當前的viewport寬度設置為 ideal viewport 的寬度
       

要得到ideal viewport就必須把默認的layout viewport的寬度設為移動設備的屏幕寬度。因為meta viewport中的width能控制layout viewport的寬度,所以我們只需要把width設為width-device這個特殊的值就行了

<meta name="viewport" content="width=device-width">

       

通過width=device-width,所有瀏覽器都能把當前的viewport寬度變成ideal viewport的寬度

這樣的代碼看起來確實簡單明了,不管你懂不懂viewport,都可以用這句進行移動端開發,可是很少有人知道

<meta name="viewport" content="initial-scale=1">

這句代碼能達到和

<meta name="viewport" content="width=device-width">

一模一樣的效果,也可以把當前的的viewport變為 ideal viewpor。覺得不太信的,你可以試試,不過這說明了什么呢?

 

       

從理論上來講,這句代碼的作用只是不對當前的頁面進行縮放,也就是頁面本該是多大就是多大。那為什么會有 width=device-width 的效果呢?

       

要想清楚這件事情,首先你得弄明白這個縮放是相對於什么來縮放的,因為這里的縮放值是1,也就是沒縮放,但卻達到了 ideal viewport 的效果,所以,那答案就只有一個了,縮放是相對於 ideal viewport來進行縮放的,當對ideal viewport進行100%的縮放,也就是縮放值為1的時候,不就得到了 ideal viewport嘛

 

但如果width 和 initial-scale=1同時出現,並且還出現了沖突呢?比如:

<meta name="viewport" content="width=400, initial-scale=1">

width=400表示把當前viewport的寬度設為400px,initial-scale=1則表示把當前viewport的寬度設為ideal viewport的寬度,那么瀏覽器到底該服從哪個命令呢?是書寫順序在后面的那個嗎?不是。當遇到這種情況時,瀏覽器會取它們兩個中較大的那個值。例如,當width=400,ideal viewport的寬度為320時,取的是400;當width=400, ideal viewport的寬度為480時,取的是ideal viewport的寬度。

最后,總結一下,要把當前的viewport寬度設為ideal viewport的寬度,既可以設置 width=device-width,也可以設置 initial-scale=1,但這兩者各有一個小缺陷,就是iphone、ipad以及IE 會橫豎屏不分,通通以豎屏的ideal viewport寬度為准。所以,最完美的寫法應該是,兩者都寫上去,這樣就 initial-scale=1 解決了 iphone、ipad的毛病,width=device-width則解決了IE的毛病:

<meta name="viewport" content="width=device-width, initial-scale=1">

三、淘寶的布局方案解析

有了上邊的viewport的知識了解后,我們來剖析淘寶的viewport。淘寶觸屏版布局的前提就是viewport的scale根據devicePixelRatio動態設置:

Galaxy S5:

從淘寶適配布局談移動端適配
從淘寶適配布局談移動端適配

 

iphone 5:

從淘寶適配布局談移動端適配
從淘寶適配布局談移動端適配

 

iphone 6 plus:

從淘寶適配布局談移動端適配
從淘寶適配布局談移動端適配

 

上圖都是明晃晃的證據啊。我截取了dpr分別為1,2,3時的縮放比,不一樣吧

這么做目的當然是為了保證頁面的大小與設計稿保持一致了,比如設計稿如果是750的橫向分辨率,那么實際頁面的device-width,以iphone6來說,也等於750,這樣的話設計稿上標注的尺寸只要除以某一個值就能夠轉換為rem了。

從淘寶適配布局談移動端適配

 

通過js設置viewport的方法如下:

 
1
2
 
 
 
var scale devicePixelRatio;  
document.querySelector('meta[name="viewport"]').setAttribute('content','initial-scale=' scale ',maximum-scale=' scale ', minimum-scale=' scale ', user-scalable=no');  
 
 

 

淘寶布局的第二個要點,就是html元素的font-size的計算公式,font-size = deviceWidth / 10:

 

 
1
2
3
4
5
6
7
 
 
 
//flexible義<html>font-size
var width docEl.getBoundingClientRect().width;  
if (width dpr 540{  
     width 540 dpr;
}
var rem width 10;
docEl.style.fontSize rem 'px';
 
 

 

從淘寶適配布局談移動端適配

從淘寶適配布局談移動端適配

從淘寶適配布局談移動端適配

 

注:整個網頁在設備內顯示時的頁面寬度就會等於設備邏輯像素大小,也就是device-width。這個device-width的計算公式為:設備的物理分辨率/(devicePixelRatio * scale),在scale為1的情況下,device-width = 設備的物理分辨率/devicePixelRatio ,物理像素=邏輯像素* devicePixelRatio*scale

接下來要解決的問題是,元素的尺寸該如何計算,比如說設計稿上某一個元素的寬為150px,換算成rem應該怎么算呢?這個值等於設計稿標注尺寸/該設計稿對應的html的font-size。拿淘寶來說的,他們用的設計稿是750的,所以html的font-size就是75,如果某個元素是150px的寬,換算成rem就是150 / 75 = 2rem。

總結下淘寶的這些做法:

 

(1)動態設置viewport的scale



 
1
2
 
 
 
var scale devicePixelRatio;  
document.querySelector('meta[name="viewport"]').setAttribute('content','initial-scale=' scale ', maximum-scale=' scale ', minimum-scale=' scale ', user-scalable=no');  
 
 

 

(2)動態設置html的font-size

 

(3)布局的時候,各元素的css尺寸=設計稿標注尺寸/設計稿橫向分辨率/10

 

(4)font-size可能需要額外的媒介查詢,並且font-size不使用rem

 

這些都是淘寶的布局方案,只是講了一些布局思路,接下來我們具體了解flexible庫以及看看它是怎么實現這些思路的

四. 淘寶移動端自適應方案—lib.flexible庫解析

lib.flexible庫是淘寶用來解決移動端頁面終端適配的

這是github上flexible庫的源碼,需要就去clone吧 https://github.com/amfe/lib-flexible

它的主要js文件有三個,包括flexiblecss.js、flexible.js、makegrid.js

flexible.js—布局的核心js

flexiblecss.js—注入統一的css樣式,比如去掉所有元素的內外邊距,去掉默認邊框等等

makegrid.js—柵格系統

怎么用lib.flexible庫? 引入flexible_css.js,flexible.js文件

<script src="build/flexible_css.debug.js"></script>

<script src="build/flexible.debug.js"></script>

 

更簡單方便的,你可以直接使用阿里CDN:

<script src="http://g.tbcdn.cn/mtb/lib-flexible/{{version}}/??flexible_css.js,flexible.js"></script>

PS:{{version}}換成相應的版本號,如{{0.3.2}}

建議對於js做內聯處理,在所有資源加載之前執行這個js。執行這個js后,會在(也就是document.documentElement)上增加一個data-dpr屬性和font-size樣式。之后頁面中的元素,都可以用rem單位來設置。html上的font-size就是rem的基准像素。JS會根據不同的設備添加不同的data-dpr值,比如說2或者3,同時會給html加上對應的font-size的值,比如說75px。如此一來,頁面中的元素,都可以通過rem單位來設置。他們會根據html元素的font-size值做相應的計算,從而實現屏幕的適配效果。 除此之外,在引入lib-flexible需要執行的JS之前,可以手動設置meta來控制dpr值,如:
<meta name="flexible" content="initial-dpr=2" />

 

其中initial-dpr會把dpr強制設置為給定的值。如果手動設置了dpr之后,不管設備是多少的dpr,都會強制認為其dpr是你設置的值。在此不建議手動強制設置dpr,因為在Flexible中,只對iOS設備進行dpr的判斷,對於Android系列,始終認為其dpr為1。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
 
 
     if (!dpr && !scale{  
        var isAndroid win.navigator.appVersion.match(/android/gi);
        var isIPhone win.navigator.appVersion.match(/iphone/gi);
        var devicePixelRatio win.devicePixelRatio;
        if (isIPhone{
            // iOS於2和3用2用1
            if (devicePixelRatio >= && (!dpr || dpr >= 3)) {                
                dpr 3;
            else if (devicePixelRatio >= && (!dpr || dpr >= 2)){
                dpr 2;
            else {
                dpr 1;
            }
        else {
            // 使用1
            dpr 1;
        }
        scale dpr;
     }
 
 


flexible的實質

flexible實際上就是能過JS來動態改寫meta標簽,代碼類似這樣:

 
1
2
3
4
5
6
7
8
9
10
11
 
 
 
var metaEl doc.createElement('meta');  
var scale isRetina 0.5:1;  
metaEl.setAttribute('name''viewport');  
metaEl.setAttribute('content''initial-scale=' scale ', maximum-scale=' scale ', minimum-scale=' scale ', user-scalable=no');  
if (docEl.firstElementChild{  
  document.documentElement.firstElementChild.appendChild(metaEl);
else {
     var wrap doc.createElement('div');
     wrap.appendChild(metaEl);
     documen.write(wrap.innerHTML);
}
 
 

 

事實上他做了這幾樣事情:

•動態改寫標簽

•給元素添加data-dpr屬性,並且動態改寫data-dpr的值

•給元素添加font-size屬性,並且動態改寫font-size的值



把視覺稿中的px轉換成rem

目前Flexible會將視覺稿分成100份,而每一份被稱為一個單位a。同時1rem單位被認定為10a。針對我們這份視覺稿可以計算出:

1a = 7.5px

1rem = 75px

 

那么我們的視覺稿就分成了10a,也就是整個寬度為10rem,對應的font-size為75px;

這樣一來,對於視覺稿上的元素尺寸換算,只需要原始的px值除以rem基准值即可。例如一個div尺寸為220px*100px,則其轉化為rem的尺寸為2.9333rem * 1.33333rem。

推薦CSSREM——px轉化rem小工具

在實際開發中,如果每一次計算px轉換rem,或許會覺得非常麻煩,或許直接影響大家平時的開發效率。這里有一個px轉換rem的小工具——CSSREM;

CSSREM是一個CSS的px值轉rem值的Sublime Text3自動完成插件。我已經安裝使用體驗,只需要輸入正常的px值,會自動換算成相應的rem值;如下圖所示:

從淘寶適配布局談移動端適配

 

查看CSSREM如何安裝,請參考:https://github.com/flashlizi/cssrem

文本字號應該用rem嗎?

顯然,我們在iPhone3G和iPhone4的Retina屏下面,希望看到的文本字號是相同的。也就是說,我們不希望文本在Retina屏幕下變小,另外,我們希望在大屏手機上看到更多文本,以及,現在絕大多數的字體文件都自帶一些點陣尺寸,通常是16px和24px,所以我們不希望出現13px和15px這樣的奇葩尺寸。

如此一來, rem並不適合用到段落文本上。所以在Flexible整個適配方案中,考慮文本還是使用px作為單位。只不過使用[data-dpr]屬性來區分不同dpr下的文本字號大小。

 
1
2
3
4
5
6
7
8
9
10
11
 
 
 
div {  
     width: 1rem; 
     height: 0.4rem;
     font-size: 12px; // 上dpr1的fontSize
}
[ data-dpr="2"] div {
     font-size: 24px;
}
[ data-dpr="3"] div {
     font-size: 36px;
}
 
 

 

總結下吧,字體慎用rem,誤差太大了,因為不能滿足任何屏幕下字體大小相同,所以建議標題類用rem,要求字體大小相同的部分還是用px

柵格系統—makegrid.js

柵格系統用於實現移動端列表型的需求,比如淘寶首頁的分類模塊:

從淘寶適配布局談移動端適配

 

首先引入makegrid.js

<script src="build/makegrid.js"></script>

 

使用方法

lib.flexible.makeGrid(params)

• [Object params]

-designWidth - 設計稿寬度

 

- designUnit - 設計稿最小單位a(以px為單位)

-columnCount - 柵格列數

-columnXUnit - 柵格列寬(以a為單位)

-gutterXUnit - 柵格間距(以a為單位)

 

-edgeXUnit - 頁面左右邊距(以a為單位)

-className - 柵格樣式的名稱(可省略,默認為grid)

通過傳入視覺的柵格規范定義,可以輸出對應的css樣式。 lib.flexible.makeGridMode(modeName) 方案還預置了幾個默認的柵格規范,分別是750-12,750-6,640-12,640-6。

 
1
2
3
4
5
6
7
8
9
10
 
 
 
var gridMode {  
     '750-12'{     designWidth:750,designUnit:6,columnCount:12,columnXUnit:7,gutterXUnit:3,edgeXUnit:4
     },
     '750-6'designWidth:750,designUnit:6,columnCount:6,columnXUnit:17,gutterXUnit:3,edgeXUnit:4
    },
    '640-12'designWidth:640,designUnit:4,columnCount:12,columnXUnit:11,gutterXUnit:2,edgeXUnit:3
    },
    '640-6'designWidth:640,designUnit:4,columnCount:6,columnXUnit:24,gutterXUnit:2,edgeXUnit:3
    }
}
 
 

 

利用meta輸出柵格樣式

<meta content="designWidth=750, desginUnit=6, columnCount=12, columnXUnit=7, gutterXUnit=3, edgeXUnit=4" name="grid" />

 

<meta content="modeName=750-12" name="grid" />


柵格代碼舉例

 
1
2
3
4
5
6
 
 
 
<meta content="modeName=640-12" name="grid" />  
<div class="grid">  
    <div class="col-4"></div>
    <div class="col-4"></div>
    <div class="col-4"></div>
</div> 
 
 

 

這是我用柵欄系統做的類似於淘寶首頁的分類模塊demo,不用像單純用css實現那么麻煩,不用display:inline-block或者float,只是簡單的應用類grid和col-n,簡單的根據自己的需求調節間距,這大大便利了我們做列表型的需求,最重要的是不用擔心在移動端的適配問題

從淘寶適配布局談移動端適配

 

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
 
 
<meta content="modeName=640-12" name="grid" />  
<style>  
    .gridmargin-top: 1rem ;background-color: #ccc;padding-top: 0.6rem;}
    .grid > div {text-align: center;font-size:0.4rem;}
    .pic{width:2rem;height:2rem;margin-bottom: 0.4rem;}
    .pic img{width:1.4rem;height:1.4rem;}
    .pic p{width:2rem;height:0.6rem;position:relative;top:2px;color:#666;}
</style>  
<div class="grid">  
     <div class="col-3">
     <div class="pic">
        <img src="images/icon1.png" alt="">
        <p></p>
     </div>
     <div class="pic">
        <img src="images/icon1.png" alt="">
        <p></p>
     </div>
     </div>
     <div class="col-3">...</div>
     <div class="col-3">...</div>
     <div class="col-3">...</div>
</div>  
 
 


最后大致看一下flexible.js里的主要源碼,更加清晰前邊的觀點:

flexible.js—布局的核心js,里邊主要包含下邊幾點來實現適配布局

1)設置像素比dpr和scale

有兩種模式:一種是自適應,一種是手動配置dpr

適應模式:根據已有的meta標簽來設置dpr和scale

手動配置:<meta name="flexible" content="initial-dpr=2,maximum-dpr=3" />

2)如果沒有設置縮放比,根據蘋果用戶或者安卓用戶設置縮放比。iOS下,對於2和3的屏,用2倍的方案,其余的用1倍方案,安卓的均采用1。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
 
 
var isAndroid win.navigator.appVersion.match(/android/gi);  
var isIPhone win.navigator.appVersion.match(/iphone/gi);  
var devicePixelRatio win.devicePixelRatio;  
if (isIPhone{  
      // iOS於2和3用2用1
       if (devicePixelRatio >= && (!dpr || dpr >= 3)) {                
           dpr 3;
       else if (devicePixelRatio >= && (!dpr || dpr >= 2)){
            dpr 2;
      else {
             dpr 1;
      }
   else {
        // 使用1
         dpr 1;
  }
 
 

 

3)前邊談到淘寶布局方案的時候,說到淘寶觸屏版布局的前提就是viewport的scale根據devicePixelRatio動態設置

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
 
 
//為html加data-dpr
docEl.setAttribute('data-dpr'dpr);  
//有meta[name="viewport"加meta簽 
if (!metaEl{  
    metaEl doc.createElement('meta');
    metaEl.setAttribute('name''viewport');
    metaEl.setAttribute('content''initial-scale=' scale ', maximum-scale=' scale ', minimum-scale=' scale ', user-scalable=no');
    if (docEl.firstElementChild{
      docEl.firstElementChild.appendChild(metaEl);
    else {
       var wrap doc.createElement('div');
       wrap.appendChild(metaEl);
       doc.write(wrap.innerHTML);
    }
}
 
 

 

4)為html標簽添加data-dpr屬性

document.documentElement.setAttribute('data-dpr', dpr);

5)刷新頁面的rem基准值 (API---lib.flexible.refreshRem())

 
1
2
3
4
5
6
7
8
9
10
11
12
 
 
 
//據dpr置rem
function refreshRem(){  
  //getBoundingClientRect().width
    var width docEl.getBoundingClientRect().width;
    // width / dpr > 540
    if (width dpr 540{  
       width 540 dpr;
    }
    var rem width 10;
    docEl.style.fontSize rem 'px';
    flexible.rem win.rem rem;
}
 
 

 

6)什么時候執行refreshRem()呢?

第一種當窗口大小發生變化,也就是觸發resize事件的時候;

 
1
2
3
4
 
 
 
win.addEventListener('resize'function({  
     clearTimeout(tid);
     tid setTimeout(refreshRem300);
}false);
 
 

 

第二種是當重新載入頁面時,判斷是否是緩存,如果是緩存,執行refreshRem()

 
1
2
3
4
5
6
 
 
 
win.addEventListener('pageshow'function(e{  
    if (e.persisted{
      clearTimeout(tid);
       tid setTimeout(refreshRem300);
    }
}false);
 
 

 

7)rem轉化px (API---lib.flexible.rem2px([Number|String digital]))

 
1
2
3
4
5
6
7
8
 
 
 
flexible.rem2px function(d{  
    //義var rem = width / 10;
    var val parseFloat(dthis.rem;
    if (typeof === 'string' && d.match(/rem$/)) {
       val += 'px';
    }
    return val;
}
 
 

 

rem轉化px計算公式=d*(width/10)

 

8)px轉化rem (API---lib.flexible.px2rem([Number|String digital]))

 
1
2
3
4
5
6
7
 
 
 
flexible.px2rem function(d{  
    var val parseFloat(dthis.rem;
    if (typeof === 'string' && d.match(/px$/)) {
       val += 'rem';
    }
    return val;
}
 
 

 

px轉化rem計算公式=d/(width/10)


再一次最后,附上自己遇到的一些關於css布局適配問題:

1.盒子,圖片等寬度設置首選百分比,次而選擇rem,高度可以是固定值

2.字體可以不用rem,誤差太大了,且不能滿足任何屏幕下字體大小相同,所以建議標題類用rem,要求字體大小相同的部分還是用px;

 

3.遇到內容排列顯示的布局,建議放棄float,可以直接使用display:inline-block。

4.慎用position屬性;absolute會脫離文檔流,relative則不會

5.如何解決盒子邊框溢出?當你把元素寬度設為 width:100%時,有時可能會遇到元素的寬度超出了屏幕,這時可對元素加box-sizing:border-box屬性,用來指定盒子大小包含邊框和內邊距

6.去除button在ios上的默認樣式

-webkit-appearance: none; border-radius: 0;

 

7.不想讓按鈕touch時有藍色的邊框

outline:none;

8.去除webkit的滾動條

element::-webkit-scrollbar{  

     

display: none;

}

9.遇到過一個問題就是,當手機端點擊input彈出鍵盤,整個視窗的高度就會變為減去鍵盤的高度,頁面底部樣式會亂,當時解決方法是用js獲取整個頁面高度賦值給body,等於說在不同的設備下寫死不同的body高度值,底部就不會亂了

$("body").css("height",parseInt($(".wrap").height())+parseInt($(".icon-main").height()));

10.如果想改變 placeholder里的文字,需要用c偽類

::-webkit-input-placeholder{

   

color:#ccc

}





希望這些大家有幫助。后續會寫篇具體怎么應用到項目中~~~~~

未插入正文的圖片或附件
從淘寶適配布局談移動端適配
從淘寶適配布局談移動端適配
從淘寶適配布局談移動端適配


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM