移動端
特點
移動端下的屏幕存在以下特點:
-
屏幕相比較於PC端要小
-
瀏覽器不像PC端,隨時各種調整大小
原因
移動端由於屏幕整體比PC端小,而且也不能出現拖動瀏覽器來調整大小的情況,所以在移動端上的布局是流式布局最多,其中有些小分支,如固定小版心。
案例
代碼
普通的圖片和容器,寫單位的時候換成 百分比 或者 flex即可。
對於頁面中的某些元素,如字體大小,可以使用 淘寶 flexibile + rem
的解決方案
一、普通的流式布局
<!DOCTYPE html> <head> body { ul { li { <body> </html> |
效果
二、淘寶flexible + rem
flexible 和flex布局沒關系 老婆和老婆餅 也沒有關系
這個解決方案是可以和以上的流式布局搭配使用的,rem的作用是主要是針對字體實現 跟隨屏幕變化而變化
- rem css單位,相對長度,它的值等於根標簽的字體大小
- 淘寶flexible
是手淘團隊出的一個處理移動端rem設置的js庫
把根標簽的字體大小改成了 當前屏幕的十分之一大小
根標簽的字體大小發生改變了,使用了rem單位的元素或者字體大小也跟着改變
手機淘寶的flexible方案,特點:
1.僅針對iphone生成動態viewport,因為目前iphone的dpr只有1,2,3三種,android的dpr很有多種,不具有一致性;
2.字體大小不用rem做縮放處理,仍然使用px單位,設置不同dpr下對應的字體大小;
3.寬度利用rem等比縮放;
4.允許強制定義dpr;
使用時頁面頭部需要引入flexible.js.
流程
flexible代碼
<!DOCTYPE html> (function flexible(window, document) { var docEl = document.documentElement; // 設備像素比
var dpr = window.devicePixelRatio || 1; // 設置body元素字體大小:監聽DOM內容是否加載完畢,完畢后給body設置字體大小 function setBodyFontSize() { if (document.body) { document.body.style.fontSize = 12 * dpr + "px"; } else { document.addEventListener("DOMContentLoaded", setBodyFontSize); } } setBodyFontSize(); // 更改根元素字體大小:設置根元素字體大小為屏幕的十分之一
function setRemUnit() { var rem = docEl.clientWidth / 10; docEl.style.fontSize = rem + "px"; } setRemUnit(); // 監聽屏幕大小:監聽屏幕大小的變化,有變化調用更改根元素字體大小函數
window.addEventListener("resize", setRemUnit); window.addEventListener("pageshow", function (e) { if (e.persisted) { setRemUnit(); } }); if (dpr >= 2) { var fakeBody = document.createElement("body"); var testElement = document.createElement("div"); testElement.style.border = ".5px solid transparent"; fakeBody.appendChild(testElement); docEl.appendChild(fakeBody); if (testElement.offsetHeight === 1) { docEl.classList.add("hairlines"); } docEl.removeChild(fakeBody); })(window, document); </script> <body> </div> setFont();
</html> |
flexible效果
綜合flexible 和 rem
根據以上的特點
-
flexible
把 根標簽字體大小改為 屏幕的十分之一 -
rem
可以根據根標簽的字體大小改變而發生改變
得出以下解決方案
-
假定設計稿的寬度 是
640px
-
根標簽的字體大小為
64px
也就是1 rem = 64px
=>1px=1/64rem
-
原設計稿中的div大小為100px,字體大小為100px
-
將px單位修改為 rem單位
div{ |
5. 將設計稿的寬度也抽象出去
div{ |
完整代碼
<!DOCTYPE html> (function flexible(window, document) { var docEl = document.documentElement; // 設備像素比
var dpr = window.devicePixelRatio || 1; // 設置body元素字體大小:監聽DOM內容是否加載完畢,完畢后給body設置字體大小 function setBodyFontSize() { if (document.body) { document.body.style.fontSize = 12 * dpr + "px"; } else { document.addEventListener("DOMContentLoaded", setBodyFontSize); } } setBodyFontSize(); // 更改根元素字體大小:設置根元素字體大小為屏幕的十分之一
function setRemUnit() { var rem = docEl.clientWidth / 10; docEl.style.fontSize = rem + "px"; } setRemUnit(); // 監聽屏幕大小:監聽屏幕大小的變化,有變化調用更改根元素字體大小函數
window.addEventListener("resize", setRemUnit); window.addEventListener("pageshow", function (e) { if (e.persisted) { setRemUnit(); } }); if (dpr >= 2) { var fakeBody = document.createElement("body"); var testElement = document.createElement("div"); testElement.style.border = ".5px solid transparent"; fakeBody.appendChild(testElement); docEl.appendChild(fakeBody); if (testElement.offsetHeight === 1) { docEl.classList.add("hairlines"); } docEl.removeChild(fakeBody); })(window, document); </script>
div {
width: calc(100rem / 64);
height: calc(100rem / 64);
font-size: calc(100rem / 64);
background-color: aqua;
}
</style> <body> </div> setFont();
</html> |
最終效果
三、小版心
小板心的做法其實也是流式布局中的一種,只不過對最外層容器加了一個最大寬度的設置如
main{ |
參考
四、vw 和 vh
在移動端中,還存在以下單位,也很好用,可以很方便解決問題。
以上單位 在移動端中,或者在小程序中都支持。
設計稿為 375px
,存在一個大小為100px
的div
,字體大小也為100px
。
-
375px = 100 vw
那么1 px = 100vw / 375
-
因此
100px = 100vw * 100 / 375
;
代碼
main { |
詳細介紹
老版常規做法
方案一:Meida Queries媒體查詢
meida queries
主要是通過查詢設備的寬度來執行不同的 css
代碼,最終達到界面的配置。核心語法是:
@media screen and (max-width: 600px) { /*當屏幕尺寸小於600px時,應用下面的CSS樣式*/ |
需要添加meta設置
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> |
width=device-width :表示寬度是設備屏幕的寬度
initial-scale=1.0:表示初始的縮放比例
minimum-scale=1.0:表示最小的縮放比例
maximum-scale=1.0:表示最大的縮放比例
user-scalable=no:表示用戶是否可以調整縮放比例
這個標簽可以保證在移動端設備中,頁面的寬度與屏幕寬度相同。
方案二:px + viewport縮放
以最小的Iphone4/5的寬度(320px)為基准,還原視覺稿。
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0 /> |
然后對不同屏幕分辨率的手機進行簡單粗暴的等比例縮放設置。 例如:iphone8(375px)initial-scale = 375 / 320 = 1.18
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.18 /> |
initial-scale越來越大,頁面內容也就被拉伸也越厲害,導致頁面內容會變得模糊,這個方法已經被摒棄了。
高度定死,寬度自適應,元素都采用px
做單位。
隨着屏幕寬度變化,頁面也會跟着變化,效果就和PC頁面的流體布局差不多,在哪個寬度需要調整的時候使用響應式布局調調就行(比如網易新聞),這樣就實現了『適配』
方案三:響應式布局
響應式的概念分為兩大類
-
一種是后端響應式
-
一種是前端響應式
后端響應式
后台服務器根據前端瀏覽器的User-Agent
來判斷來源請求是PC端還是移動端,然后服務器動態返回PC端頁面或者移動端頁面。nginx中很容易就出現該功能。京東,天貓,淘寶也是這樣子的。
前端響應式
主要是指通過媒體查詢來實現。
前端寫好一套代碼 html + css + javascript
,就可以冬天的根據屏幕的寬度來改變頁面的樣式
這種做法體驗不是最好,但是卻是最小的代碼實現了 兼容pc端和移動端。一般是對頁面要求不高或者小企業使用。
由於還要兼容到pc端,所以一般做響應式頁面 不會用太高級的h5 css3 的技術。
新做法
方案四:rem + viewport縮放
需要添加meta設置
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> |
換句話說,當我們指定一個元素的font-size為2rem
的時候,也就說這個元素的字體大小為根元素<html>
字體大小的兩倍,如果html
的font-size為12px
,那么這個2rem
的元素font-size就是24px
。同理當該元素為3rem
時,那么其實際
font-size就是36px
。
h1 { font-size: 2rem; } /* 2 × 12px = 24px */ p { font-size: 1.5rem;} /* 1.5 × 12px = 18px */ div {width: 20rem;} /* 20 * 12px = 240px*/ |
看到這里你應該就會發現,只要我們根據不同屏幕設定好根元素<html>
的font-size,其他已經使用了rem單位的元素就會自適應顯示相應的尺寸了。
rem計算
我們使用rem單位事先需要做的一件事情就是設置根元素<html>
的font-size,通常有兩種做法
方法一:JS計算
通過JavaScript讀取屏幕寬度,然后根據寬度計算出對應的尺寸並設置根元素的font-size。
const oHtml = document.getElementsByTagName('html')[0] const width = oHtml.clientWidth; // 320px的屏幕基准像素為12px oHtml.style.fontSize = 12 * (width / 320) + "px"; |
這樣iphone8(375px)下html
的font-size 就是14.0625px,iphone8p下font-size就是15.525px。
如果在iphone8(375px)下設置元素font-size為 1.7066rem, 效果跟設置其font-size為 24px 是一樣的(24 / 14.0625 = 1.7066)。
使用JS來獲取屏幕寬度的好處在於可以100%適配所有的機型寬度,因為其<html>
元素的基准尺寸是直接算出來的。既然是JS代碼,為了避免造成因為動態設置<html>
元素的font-size而造成頁面抖動,一般這部分代碼我們放在header
底部去加載,並內聯到html文檔里面。
實戰
將根元素的font-size擴大100倍,使用px的時候,根據設計圖除以100得到想要的px
!new function() {
var a = this;
a.width = 750,
a.fontSize = 100,
a.widthProportion = function() {
var b = (document.body && document.body.clientWidth || document.getElementsByTagName("html")[0].offsetWidth) / a.width;
return b > 1 ? 1 : b
},
a.changePage = function() {
document.getElementsByTagName("html")[0].setAttribute("style", "font-size:" + a.widthProportion() * a.fontSize + "px !important")
},
a.changePage(),
window.addEventListener("resize",
function() {
a.changePage()
},
!1)
};
|
方法二:媒體查詢
既然只是為了根據屏幕寬度來設置<html>
元素的字體大小,那我們完全也可以通過css3媒體查詢來完成這部分工作。
html { font-size: 14.0625px; } } @media screen and (min-width: 360px){ html { font-size: 13.5px; } } @media screen and (min-width: 320px){ html { font-size: 12px; } } html { font-size: 16px; } |
rem存在的問題
rem作為一種簡單粗暴解決不同屏幕下視圖的區別的一種方案,它可以解決本文出現的問題以及絕大多數移動端適配屏幕尺寸的問題。但是既然它並不是一個完美的解決方案,那就有其局限性所在。
大屏智能機時代確實幾乎完全替代了我十年前紙質化閱讀的習慣。從2011年至今,手上的手機屏幕寬度一直在提升,但是使用的看小說軟件的顯示字號幾乎是不變的。使用rem會在一定程度上打破用戶的文字內容閱讀習慣,特別是在大篇
幅的內容時。
iOS與Android平台的適配方式背后隱藏的設計哲學是這樣的:閱讀文字時,可讀性較好的文字字號行距等絕對尺寸數值組合與文字所在媒介的絕對尺寸關系不大。(可以這樣簡單理解:A4大小的報紙和A3大小甚至更大的報紙,舒適的閱
讀字號絕對尺寸是一樣的,因為他們都需要拿在手里閱讀,在手機也是上同理);在看圖片視頻時,圖片、視頻的比例應該是固定的,不應該出現拉伸變形的情況。而rem用在字號時,使字號在不同屏幕上的絕對尺寸不一致,違背了設計
哲學。
方案五:vw + vh
參考
阿里巴巴TXD移動端適配總結(viewport講的不錯)