其中方案 1.3.4.5的demo地址移動端適配方案javascript
移動端 Web 頁面,即常說的 H5 頁面、手機頁面、webview 頁面等。css
手機機設備屏幕尺寸不一,作移動端的 Web 頁面,須要考慮在安卓/IOS 的各類尺寸設備上的兼容,這裏總結的是針對移動端設備的頁面,設計與前端實現怎樣作能更好地適配不一樣屏幕寬度的移動設備。html
適配的目標前端
在不一樣尺寸的手機設備上,頁面「相對性的達到合理的展現(自適應)」或者「保持統一效果的等比縮放(看起來差很少)」。
<!-- markdown-to-slides index.md -o index.html -s slide.css -->java
要搞懂移動端的適配問題,就要先搞明白像素和視口。git
在移動端給一個元素設置 width:200px 時發生了什麼?這裏的 px 究竟是多長呢?像素是網頁佈局的基礎,可是咱們一直在用直覺使用它。github
iphone6 有 750 的物理像素,可是屏幕寬度像素是 375px???web
1.設備像素 device pixel編程
設備像素是物理概念,指的是設備中使用的物理像素,任何設備屏幕的物理像素的數量都是固定不變的。
好比 iphone6 的分辨率 1334 x 750px ,750px 指的是設備物理像素bootstrap
2.邏輯像素 css pixel
css 像素是 web 編程的概念,指的是 css 樣式中使用的邏輯像素
css px 是一個相對單位 相對的是設備像素
咱們網頁 css 和小程序用的是邏輯像素
eg:
iphone6 使用的是 retina 視網膜屏幕
2px x 2px 的設備像素表明 1px z 1px 的 css 像素
因此設備像素 1334 x 750 css 邏輯像素是 667 x 375
那麼,咱們如今再來講說一個元素 width:200px 之後會怎麼樣。這個元素跨越了 200 個 CSS 元素,200 個 CSS 元素至關於多少個設備像素取決於兩個條件:
這兩方面後面再解釋,先梳理一下手機硬件之間的關係,注意這裏使用的都是物理像素。
以 iPhone5 爲例,咱們已知的是:
1.分辨率 1136pt x 640pt
指屏幕上垂直有 1136 個物理像素,水平有 640 個物理像素
2.屏幕尺寸 4 英寸
注意英寸是長度單位,不是面積單位。4 英寸指的是屏幕對角線的長度。
3.屏幕像素密度 326ppi
屏幕像素密度(Pibel Per Inch)簡稱 ppi ,單位是 dpi(dot per inch)。這裏指屏幕水平或垂直每英寸有 326 個物理像素。原則上來講,ppi 越高越好,由於圖像會更加細膩清晰。
ppi 是能夠經過 分辨率 和 屏幕尺寸 計算獲得的:
<img src="./ppi.png"/>
這個網站列出了不少設備的分辨率和屏幕尺寸,而且計算了 ppi。
這個網站列出了不少設備的分辨率和屏幕尺寸,而且計算了 ppi。
桌面瀏覽器中,瀏覽器窗口就是約束你的 CSS 佈局視口(又稱初始包含塊)。它使全部 CSS 百分比寬度推算的根源,它的做用是 CSS 佈局限制了一個最大寬度,視口的寬度和瀏覽器窗口寬度一致。
可是在移動端,狀況就很複雜了。
在手機上,視口與移動端瀏覽器屏幕寬度再也不相關聯,是徹底獨立的,這個瀏覽器廠商定的視口被稱爲佈局視口。
佈局視口咱們是看不見的,只知道網頁的最大寬度是 980px ,而且被縮放在了屏幕內。
能夠這樣設置佈局視口的寬度:
<meta name="viewport" content="width=640" />
媒體查詢與佈局視口
@media (min-width: 700px) { ...; }
document.documentElement.clientWidth/Height 返回佈局視口的尺寸
有了 layout viewport,咱們還須要一個視口用來承載它,這個視口能夠簡單的認爲是手持設備物理屏幕的可視區域,
視覺視口是用戶正在看到的網頁的區域,大小是屏幕中 CSS 像素的數量。
window.innerWidth/Height 返回視覺視口的尺寸
很明顯,visual viewport 的尺寸不會是一個固定的值,甚至每款設備均可能不一樣。大體列幾種常見設備的 visual viewport 尺寸:
以 iPhone4S 爲例,會在其 320px② 的 visual viewport 上,建立一個寬 980px 的 layout viewport,因而用戶能夠在 visual viewport 中拖動或者縮放網頁,來得到良好的瀏覽效果;佈局視口用來配合 CSS 渲染布局,當咱們定義一個容器的寬度爲 100%時,這個容器的實際寬度是 980px 而不是 320px,經過這種方式大部分網頁就能以縮放的形式正常顯示在手機屏幕上了。
佈局視口明顯對用戶是不友好的,徹底忽略了手機自己的尺寸。因此蘋果引入了理想視口的概念,它是對設備來講最理想的佈局視口尺寸。理想視口中的網頁用戶最理想的寬度,用戶進入頁面的時候不須要縮放。
<meta name="viewport" content="width=device-width" />
定義理想視口是瀏覽器的事情,並不能簡單地認爲是開發者定義的,開發者只能使用。
screen.width/height 返回理想視口的尺寸,有嚴重的兼容性問題---可能返回兩種值:
Screen size tests 和 Understanding viewport 能夠測試你的設備的 screen.width 值,同一設備的不一樣瀏覽器返回的值多是不同的。這一狀況主要發生在默認瀏覽器和下載瀏覽器(如 UC、Chrome)之間。
關於 3 個視口,PPK已經作了很是棒的闡釋,你也能夠在 StackOverflow 上找到一些對此描述的相互補充,例如:1, 2,有興趣的童鞋也能夠看看
縮放是在放大或縮小 CSS 像素,好比一個寬度爲 200px 的元素不管放大,仍是 200 個 CSS 像素。可是由於這些像素被放大了,因此 CSS 像素也就跨越了更多的設備像素。縮小則相反。
縮放會影響視覺視口的尺寸
頁面被用戶放大,視覺視口內 CSS 像素數量減小;被用戶縮小,視覺視口內 CSS 像素數量增多就好了。這個道理應該是不難想的。
用戶縮放不會影響佈局視口
在下載瀏覽器中,能夠這麼算(理想視口與視覺視口的比):
zoom level = screen.width / window.innerWidth
禁止縮放
<meta name="viewport" content="user-scalable=no" />
設置縮放
<meta name="viewport" content="initial-scale=2" />
使用 initial-scale 有一個反作用:同時也會將佈局視口的尺寸設置爲縮放後的尺寸。因此 initial-scale=1 與 width=device-width 的效果是同樣的。
解決各類瀏覽器兼容問題的理想視口設置
<meta name="viewport" content="width=device-width,initial-scale=1" />
屏幕是否爲高密度也會影響設備像素和 CSS 像素的關係。
在縮放程度爲 100%(這個條件很重要,在後面會說到)時,他們的比例叫作設備像素比(device pixel ratio):
dpr = 設備像素 / CSS 像素
能夠經過 JS 獲得: window.devicePixelRatio
設備像素比也和視口有關:
dpr = 屏幕橫向設備像素 / 理想視口的寬
Name | Value | description |
---|---|---|
width | 正整數或 device-width | 定義視口的寬度,單位爲像素 |
height | 正整數或 device-height | 定義視口的高度,單位爲像素 |
initial-scale | [0.0-10.0] | 定義初始縮放值 |
minimum-scale | [0.0-10.0] | 定義縮小最小比例,它必須小於或等於 maximum-scale 設置 |
maximum-scale | [0.0-10.0] | 定義放大最大比例,它必須大於或等於 minimum-scale 設置 |
user-scalable | yes/no | 定義是否容許用戶手動縮放頁面,默認值 yes |
width 被用來定義 layout viewport 的寬度,若是不指定該屬性(或者移除 viewport meta 標籤),則 layout viewport 寬度爲廠商默認值。
若是想頁面默認以某個比例放大或者縮小而後呈現給用戶,那麼能夠經過定義 initial-scale 來完成。
<meta name="viewport" content="initial-scale=2" />
那麼用戶將會看到 2 倍大小的頁面內容。
在移動端,你可能會考慮用戶瀏覽不便,而後給予用戶放大頁面的權利,但同時又但願是在必定範圍內的放大,這時就可使用 maximum-scale 來進行約束。
<meta name="viewport" content="initial-scale=1,maximum-scale=5" />
假設頁面的默認縮放值 initial-scale 是 1,那麼用戶最終可以將頁面放大到這個初始頁面大小的 5 倍。
相似 maximum-scale 的描述,不過 minimum-scale 是用來指定頁面縮小比例的。
一般狀況下,爲了有更好地體驗,不會定義該屬性的值比 1 更小,由於那樣頁面將變得難以閱讀。
若是你不想頁面被放大或者縮小,經過定義 user-scalable 來約束用戶是否能夠經過手勢對頁面進行縮放便可。
<meta name="viewport" content="user-scalable=no" />
在 iphone6p 下 test.1.html 和 test.3.html 適配對比
<img src="./iphone6p1-3.png"/>
相對長度單位,相對於根元素(即 html 元素)font-size 計算值的倍數
兼容性
<img src="./rem.png"/>
瀏覽器默認爲 16px 可能形成 rem 計算上的麻煩和多位小數,因此,咱們也可使用 100px 初始化根元素:
<img src="./computed.png" height="220" width="650"/>
meida queries 的方式能夠說是我早期採用的佈局方式,它主要是經過查詢設備的寬度來執行不一樣的 css 代碼,最終達到界面的配置。核心語法是:
@media screen and (max-width: 600px) { /*當屏幕尺寸小於600px時,應用下面的CSS樣式*/ /*你的css代碼*/ }
優勢
缺點
它的 viewport 是固定的:
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no" />
高度定死,寬度自適應,元素都採用 px 作單位。
隨着屏幕寬度變化,頁面也會跟着變化,效果就和 PC 頁面的流體佈局差很少,在哪一個寬度須要調整的時候使用響應式佈局調調就行(好比網易新聞),這樣就實現了『適配』。
這也是淘寶使用的方案,根據屏幕寬度設定 rem 值,須要適配的元素都使用 rem 爲單位,不須要適配的元素仍是使用 px 爲單位。
實現原理
如 iphone6 plus 的 dpr 爲 3, 則頁面總體放大 3 倍, 1px(css 單位)在 plus 下默認爲 3px(物理像素)
而後 viewport 設置爲 1/3, 這樣頁面總體縮回原始大小. 從而實現高清。
這樣整個網頁在設備內顯示時的頁面寬度就會等於設備邏輯像素大小,也就是 device-width。 這個 device-width 的計算公式爲:設備的物理分辨率/(devicePixelRatio * scale), 在 scale 爲 1 的狀況下,device-width = 設備的物理分辨率/devicePixelRatio 。
當設計以 iphone6 爲標準,出 750px 的設計稿時,此時 dpr=2
width = document.documentElement.clientWidth = 375px; rem = 375px / 7.5 = 50px; // font-size = 50px dpr = 2 時, 1rem = 100px, initial-scale=0.5, 縮放爲0.5。
根據不一樣屏幕動態寫入 font-size,以 rem 做爲寬度單位,固定佈局視口。
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no" />
以 640px 設計稿和 750px 的視覺稿,網易這樣處理的:
var width = document.documentElement.clientWidth // 屏幕的佈局視口寬度 var rem = width / 7.5 // 750px設計稿將佈局視口分爲7.5份 var rem = width / 6.4 // 640px設計稿將佈局視口分爲6.4份
在 750px 設計稿上:
//在ipone6上: width = document.documentElement.clientWidth = 375px; rem = 375px / 7.5 = 50px; // font-size = 50px //在ipone5上: width = document.documentElement.clientWidth = 320px; rem = 320px / 7.5 = 42.667px; // font-size = 42.667px;
百分比適配,沒有 1px 適配,有字體大小適配。
經過如下代碼來控制 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)
如:荔枝 FM、網易應用
固定佈局視口,寬度設置固定的值,總寬度爲 640px,根據屏幕寬度動態生成 viewport。(設計稿應該是 640px 的)
<meta name="viewport" content="width=640, minimum-scale = 0.5625, maximum-scale = 0.5625, target-densitydpi=device-dpi" />
網頁寬度始終爲 640px。縮放比例 scale 爲:
var scale = window.screen.width / 640
百分比適配,部分 1px 適配,沒有字體適配。
新增了尺寸單位。在寫 CSS 樣式時,開發者須要考慮到手機設備的屏幕會有不一樣的寬度和設備像素比,採用一些技巧來換算一些像素單位。WXSS 在底層支持新的尺寸單位 rpx ,開發者能夠免去換算的煩惱,只要交給小程序底層來換算便可,因爲換算採用的浮點數運算,因此運算結果會和預期結果有一點點誤差。
rpx(responsive pixel): 能夠根據屏幕寬度進行自適應。規定屏幕寬爲 750rpx。如在 iPhone6 上,屏幕寬度爲 375px,共有 750 個物理像素,則 750rpx = 375px = 750 物理像素,1rpx = 0.5px = 1 物理像素。
設備 | 物理像素 | css 像素 | rpx->px | px->rpx |
---|---|---|---|---|
iPhone5 | 320px | 320px | 1rpx = 0.42px | 1px = 2.34rpx |
iPhone6 | 750px | 375px | 1rpx = 0.5px | 1px = 2rpx |
iPhone6+ | 1080px | 414px | 1rpx = 0.552px | 1px = 1.81rpx |
建議: 開發微信小程序時設計師能夠用 iPhone6 做爲視覺稿的標準。
自適應是最先出現的,後面纔有了響應式。響應式佈局等於流動網格佈局,而自適應佈局等於使用固定分割點來進行佈局。
響應式的基本概念是(Responsive design):
簡而言之,就是一個網站可以兼容多個終端——而不是爲每一個終端作一個特定的版本。
自適應的解釋(Adaptive design):
自適應佈局給了你更多設計的空間,由於你只用考慮幾種不一樣的狀態。
若是用響應式佈局來處理的話,用不一樣設備(電腦、平板、手機)去訪問此頁面,最後看到的佈局和內容有很大不一樣。而若是用自適應佈局去處理的話,那無論訪問設備如何的不一樣(下圖是三臺尺寸不同的手機),最後看到的頁面內容和佈局基本上仍是同樣的,就是尺寸略有不一樣。
響應式
pro-list-hd hidden-xs
col-6 pad-6x
col-sm-4 col-pd-12 col-mb-12
自適應
// 若是大於1000px,就用:對應PC端頁面 @media screen and (min-width: 1000px) { ...; } // 若是在小於1000px和大於768px之間: 對應平板端頁面 @media screen and (max-width: 1000px) and (min-width: 768px) { ...; } // 若是小於768px: 對應手機端頁面 @media screen and (max-width: 768px) { ...; }
柵格化佈局,本例利用 bootstarp 的柵格系統
<img src="./sgxt.png" />
<img src="./sg.png" />
<img src="./768.png" height="170"/>
<img src="./769.png" height="170"/>
<img src="./992.png" height="170"/>
在移動端 web 開發中,UI 設計稿中設置邊框爲 1 像素,前端在開發過程當中若是出現 border:1px,測試會發如今某些機型上,1px 會比較粗,便是較經典的移動端 1px 像素問題。
div { width: 1px; height: 100%; display: block; border-left: 1px solid #e5e5e5; -webkit-transform: scale(0.5); transform: scaleX(0.5); }
缺點:
圓角沒法實現,實現 4 條邊框比較麻煩,而且只能單獨實現,若是嵌套,會對包含的效果產生不想要的效果,因此此方案配合:after 和 before 獨立使用較多。
利用 CSS 對陰影處理的方式實現 0.5px 的效果
-webkit-box-shadow: 0 1px 1px -1px rgba(0, 0, 0, 0.5);
優勢:
基本全部場景都能知足,包含圓角的 button,單條,多條線。
缺點:
顏色很差處理, 黑色 rgba(0,0,0,1) 最深的狀況了。有陰影出現,很差用。
大量使用 box-shadow 可能會致使性能瓶頸。
四條邊框實現效果不理想。
使用 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; }
優勢: 能夠設置單條,多條邊框 能夠設置顏色
缺點: 大量使用漸變可能致使性能瓶頸 代碼量大 多背景圖片有兼容性問題
1. 使用 srcset 標籤(WebKit 最新特性 srcset 簡介)
<img src="http://g.ald.alicdn.com/bao/uploaded/i1/TB1d6QqGpXXXXbKXXXXXXXXXXXX_!!0-item_pic.jpg_160x160q90.jpg" srcset=" http://img01.taobaocdn.com/imgextra/i1/803091114/TB2XhAPaVXXXXXmXXXXXXXXXXXX_!!803091114.jpg 2x, http://gtms04.alicdn.com/tps/i4/TB1wDjWGXXXXXbtXVXX6Cwu2XXX-398-510.jpg_q75.jpg 3x " />
2. 使用 js 自帶的 Image 異步加載圖片
<img id="img" data-src1x="xxx@1x.jpg" data-src2x="xxx@2x.jpg" data-src3x="xxx@3x.jpg" />
var dpr = window.devicePixelRatio if (dpr > 3) { dpr = 3 } var imgSrc = $('#img').data('src' + dpr + 'x') var img = new Image() img.src = imgSrc img.onload = function(imgObj) { $('#img') .remove() .prepend(imgObj) //替換img對象 }
3. 背景圖片高清解決方法(對於 dpr=2,1 個 css 像素對應 4 個物理像素)
對於 dpr=1,物理像素和 css 相同,圖片高清。但對於 dpr=2,致使每一個像素點實際上有 4 倍的普通像素點,反過來講,一個 CSS 像素點實際分紅了四個,這樣就形成了顏色只能近似選取,因而,咱們看上去就變得模糊了。因此使用 2x 的圖片就剛恰好。
使用 media 來處理
/* 普通顯示屏(設備像素比例小於等於1)使用1倍的圖 */ .css { background-image: url(img_1x.png); } /* 高清顯示屏(設備像素比例大於等於2)使用2倍圖 */ @media only screen and (-webkit-min-device-pixel-ratio: 2) { .css { background-image: url(img_2x.png); } }
使用 [image-set]() 來處理
https://www.html.cn/book/css/...
.css { background-image: url(1x.png); /*不支持image-set的狀況下顯示*/ background: -webkit-image-set( url(1x.png) 1x, /* 支持image-set的瀏覽器的[普通屏幕]下 */ url(2x.png) 2x, /* 支持image-set的瀏覽器的[2倍Retina屏幕] */ url(3x.png) 3x /* 支持image-set的瀏覽器的[3倍Retina屏幕] */ ); }
<center>-- End --</center>