在網上搜了一下,很多面試都會被問到移動端適配方法的問題,最近看了一些文章,這裏總結一下。
首先,談一下目前爲止出現的一些關於移動端適配的技術方案:
(1)通過媒體查詢的方式即CSS3的meida queries
(2)以天貓首頁爲代表的 flex 彈性佈局
(3)以淘寶首頁爲代表的 rem+viewport縮放
(4)rem 方式
1.Media Queries
meida queries
的方式可以說是我早期採用的佈局方式,它主要是通過查詢設備的寬度來執行不同的 css
代碼,最終達到界面的配置。核心語法是:
@media screen and (max-width: 600px) { /*當屏幕尺寸小於600px時,應用下面的CSS樣式*/
/*你的css代碼*/
}
優點
media query
可以做到設備像素比的判斷,方法簡單,成本低,特別是對移動和PC維護同一套代碼的時候。目前像Bootstrap
等框架使用這種方式佈局- 圖片便於修改,只需修改css文件
- 調整屏幕寬度的時候不用刷新頁面即可響應式展示
缺點
- 代碼量比較大,維護不方便
- 爲了兼顧大屏幕或高清設備,會造成其他設備資源浪費,特別是加載圖片資源
- 爲了兼顧移動端和PC端各自響應式的展示效果,難免會損失各自特有的交互方式
2.Flex彈性佈局
以天貓的實現方式進行說明:
它的viewport
是固定的:<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
高度定死,寬度自適應,元素都採用px
做單位。
隨着屏幕寬度變化,頁面也會跟着變化,效果就和PC頁面的流體佈局差不多,在哪個寬度需要調整的時候使用響應式佈局調調就行(比如網易新聞),這樣就實現了『適配』。
3.rem + viewport 縮放
這也是淘寶使用的方案,根據屏幕寬度設定
rem
值,需要適配的元素都使用 rem
爲單位,不需要適配的元素還是使用 px
爲單位。(1em = 16px)
PS:rem
rem是CSS3新增的一個相對單位(root em,根em),這個單位引起了廣泛關注。這個單位與em有什麼區別呢?
區別在於使用rem爲元素設定字體大小時,仍然是相對大小,但相對的只是HTML根元素。這個單位可謂集相對大小和絕對
大小的優點於一身,通過它既可以做到只修改根元素就成比例地調整所有字體大小,又可以避免字體大小逐層複合的連鎖
反應。目前,除了IE8及更早版本外,所有瀏覽器均已支持rem。對於不支持它的瀏覽器,應對方法也很簡單,就是多寫一
個絕對單位的聲明。這些瀏覽器會忽略用rem設定的字體大小。比如:p{font-size:14px;font-size:0.875rem;}
(推薦一個單位轉換的工具:http://pxtoem.com/)
實現原理
根據rem
將頁面放大dpr
倍, 然後viewport
設置爲1/dpr
.
如iphone6 plus的dpr爲3, 則頁面整體放大3倍, 1px(css單位)在plus下默認爲3px(物理像素)
然後viewport
設置爲1/3, 這樣頁面整體縮回原始大小. 從而實現高清。
這樣整個網頁在設備內顯示時的頁面寬度就會等於設備邏輯像素大小,也就是device-width
。
這個device-width
的計算公式爲:設備的物理分辨率/(devicePixelRatio * scale)
,
在scale爲1的情況下,device-width = 設備的物理分辨率/devicePixelRatio
。
4、rem實現
比如說“魅族”移動端的實現方式,
viewport
也是固定的: <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
。
通過以下代碼來控制rem
基準值(設計稿以720px寬度量取實際尺寸)
!function (d) {
var c = d.document;
var a = c.documentElement;
var b = d.devicePixelRatio;
var f;
function e() {
var h = a.getBoundingClientRect().width, g;
if (b === 1) {
h = 720
}
if(h>720) h = 720;//設置基準值的極限值
g = h / 7.2;
a.style.fontSize = g + "px"
}
if (b > 2) {
b = 3
} else {
if (b > 1) {
b = 2
} else {
b = 1
}
}
a.setAttribute("data-dpr", b);
d.addEventListener("resize", function () {
clearTimeout(f);
f = setTimeout(e, 200)
}, false);
e()
}(window);
css
通過sass
預編譯,設置量取的px
值轉化rem
的變量$px: (1/100)+rem;
1像素邊框高清
1.淘寶實現方式
上面說到的淘寶的實現方式即rem
+viewport
縮放來實現。
transform:
scale(0.5)
CSS
代碼:
div{
width: 1px;
height: 100%;
display: block;
border-left: 1px solid #e5e5e5;
-webkit-transform: scale(.5);
transform: scaleX(.5);
}
缺點:
圓角無法實現,實現4條邊框比較麻煩,並且只能單獨實現,如果嵌套,會對包含的效果產生不想要的效果,所以此方案配合:after和before獨立使用較多。
box-shadow
實現方法:
利用CSS對陰影處理的方式實現0.5px的效果。
-webkit-box-shadow:0 1px 1px -1px rgba(0, 0, 0, 0.5);
優點:
基本所有場景都能滿足,包含圓角的button,單條,多條線。
缺點:
顏色不好處理, 黑色 rgba(0,0,0,1)
最深的情況了。有陰影出現,不好用。
大量使用box-shadow
可能會導致性能瓶頸。
四條邊框實現效果不理想。
2.圖片實現
使用 background-image
實現1px有兩種方式: 漸變 linear-gradient
或直接使用圖片(base64
)。
漸變 linear-gradient
(50%有顏色,50%透明)
單條線:
div{
height: 1px;
background-image:-webkit-linear-gradient(top,transparent 50%,#000 50%);
background-position: top left;
background-repeat: no-repeat;
background-size: 100% 1px;
}
多線條:
div{
background-image: -webkit-linear-gradient(top,transparent 50%,#000 50%),
-webkit-linear-gradient(bottom, transparent 50%, #000 50%),
-webkit-linear-gradient(left, transparent 50%, #000 50%),
-webkit-linear-gradient(right, transparent 50%, #000 50%);
background-size: 100% 1px,100% 1px,1px 100%,1px 100%;
background-repeat: no-repeat;
background-position: top left, bottom left, left top, right top;
優點:
可以設置單條,多條邊框
可以設置顏色
缺點:
大量使用漸變可能導致性能瓶頸
代碼量大
多背景圖片有兼容性問題