以前的一篇《手機端頁面自適應解決方案—rem佈局》隨着時間的推移,該方案已然過期,故爲你們介紹一個目前我極力推薦使用的,更加完美的方案——rem佈局(進階版)javascript
該方案使用至關簡單,把下面這段已壓縮過的 原生JS(源碼已在文章底部更新,2017/5/3) 放到 HTML 的 head 標籤中便可(注:不要手動設置meta標籤viewport,該方案自動幫你設置)css
<script>!function(e){function t(a){if(i[a])return i[a].exports;var n=i[a]={exports:{},id:a,loaded:!1};return e[a].call(n.exports,n,n.exports,t),n.loaded=!0,n.exports}var i={};return t.m=e,t.c=i,t.p="",t(0)}([function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=window;t["default"]=i.flex=function(e,t){var a=e||100,n=t||1,r=i.document,o=navigator.userAgent,d=o.match(/Android[\S\s]+AppleWebkit\/(\d{3})/i),l=o.match(/U3\/((\d+|\.){5,})/i),c=l&&parseInt(l[1].split(".").join(""),10)>=80,p=navigator.appVersion.match(/(iphone|ipad|ipod)/gi),s=i.devicePixelRatio||1;p||d&&d[1]>534||c||(s=1);var u=1/s,m=r.querySelector('meta[name="viewport"]');m||(m=r.createElement("meta"),m.setAttribute("name","viewport"),r.head.appendChild(m)),m.setAttribute("content","width=device-width,user-scalable=no,initial-scale="+u+",maximum-scale="+u+",minimum-scale="+u),r.documentElement.style.fontSize=a/2*s*n+"px"},e.exports=t["default"]}]); flex(100, 1);</script>
這是阿里團隊的高清方案佈局代碼,所謂高清方案就是根據設備屏幕的DPR(設備像素比,又稱DPPX,好比dpr=2時,表示1個CSS像素由4個物理像素點組成) html
動態設置 html 的font-size, 同時根據設備DPR調整頁面的縮放值,進而達到高清效果。java
重要的事情說三遍!
毫不是每一個地方都要用rem,rem只適用於固定尺寸!
毫不是每一個地方都要用rem,rem只適用於固定尺寸!
毫不是每一個地方都要用rem,rem只適用於固定尺寸!
在至關數量的佈局情境中(好比底部導航元素平分屏幕寬,大尺寸元素),你必須使用百分比或者flex才能完美佈局!
看過 《手機端頁面自適應解決方案—rem佈局》的朋友,應該對rem有所瞭解,這裏再也不贅述,
此方案也是默認 1rem = 100px,因此你佈局的時候,徹底能夠按照設計師給你的效果圖寫各類尺寸啦。
好比你在效果圖上量取的某個按鈕元素長 55px, 寬37px ,那你直接能夠這樣寫樣式:react
.myBtn { width: 0.55rem; height: 0.37rem; }
許多同窗對該方案存在很多誤解致使使用出現各類問題,這裏統一回復下。git
答:老實說固然能夠,不過爲了規範,640或者750是相對合適的。
拿Iphone 5s 舉例,它的css像素寬度是320px,因爲它的dpr=2,因此它的物理像素寬度爲320 × 2 = 640px,這也就是爲何,你在5s上截了一張圖,在電腦上打開,它的原始寬度是640px的緣由。
那 iphone 6 的截圖寬度呢? 375 × 2 = 750
那 iphone 6 sp 的截圖寬度呢? 414 × 3 = 1242
以此類推,你如今能明白效果圖爲何通常是 640 ,750 甚至是 1242 的緣由了麼?(真沒有歧視安卓機的意思。。。)github
答:假設你的效果圖寬度是750,在這個效果圖上可能有一個寬度爲7rem(高清方案默認 1rem = 100px)的元素。咱們知道,高清方案的特色就是幾乎完美還原效果圖,也就是說,你寫了一個寬度爲 7rem 的元素,那麼在目前主流移動設備上都是7rem。然而,iphone 5 的寬度爲640,也就是6.4rem。因而橫向滾動條不可避免的出現了。
怎麼辦呢? 這是我目前推薦的比較安全的方式:若是元素的寬度超過效果圖寬度的一半(效果圖寬爲640或750),果斷使用百分比寬度,或者flex佈局。就像把等屏寬的圖片寬度設爲100%同樣。瀏覽器
答:先說高清方案代碼,再次強調我們的高清方案代碼是根據設備的dpr動態設置html 的 font-size,
若是dpr=1(如電腦端),則html的font-size爲50px,此時 1rem = 50px
若是dpr=2(如iphone 5 和 6),則html的font-size爲100px,此時 1rem = 100px
若是dpr=3(如iphone 6 sp),則html的font-size爲150px,此時 1rem = 150px
若是dpr爲其餘值,即使不是整數,如3.4 , 也是同樣直接將dpr 乘以 50 。安全
再來講說效果圖,通常來說,咱們的效果圖寬度要麼是640,要麼是750,不管哪個,它們對應設備的dpr=2,此時,1 rem = 50 × 2 = 100px。這也就是爲何高清方案默認1rem = 100px。而將1rem默認100px也是好處多多,能夠幫你快速換算單位,好比在750寬度下的效果圖,某元素寬度爲53px,那麼css寬度直接設爲53/100=0.53rem了。微信
然而極少狀況下,有設計師將效果圖寬定爲1242px,由於他手裏只有一個iphone 6 sp (dpr = 3),設計完效果圖恰好能夠在他的iphone 6 sp裏查看調整。一切完畢以後,他將這個效果圖交給你來切圖。因爲這個效果圖對應設備的dpr=3,也就是1rem = 50 × 3 = 150px。因此若是你量取了一個寬度爲90px的元素,它的css寬度應該爲 90/150=0.6rem。因爲我們的高清方案默認1rem=100px,爲了還原效果圖,你須要這樣換算。固然,一個技巧就是你能夠直接修改我們的高清方案的默認設置。在代碼的最後 你會看到 flex(100, 1) ,將其修改爲flex(66.66667, 1)(感謝簡友:V旅行指出此處錯誤! 2017/3/24)就不用那麼麻煩的換算了,此時那個90px的直接寫成0.9rem就能夠了。
答:我們的rem適合寫固定尺寸。其他的根據須要換成flex或者百分比。源碼示例中就有這三種的綜合運用。
點擊瀏覽:一個標準的640手機頁面設計稿參考(沒錯,在此方案中,你能夠徹底按照這張設計稿的尺寸寫佈局了。就是這麼簡單!)
'use strict'; /** * @param {Number} [baseFontSize = 100] - 基礎fontSize, 默認100px; * @param {Number} [fontscale = 1] - 有的業務但願能放大必定比例的字體; */ const win = window; export default win.flex = (baseFontSize, fontscale) => { const _baseFontSize = baseFontSize || 100; const _fontscale = fontscale || 1; const doc = win.document; const ua = navigator.userAgent; const matches = ua.match(/Android[\S\s]+AppleWebkit\/(\d{3})/i); const UCversion = ua.match(/U3\/((\d+|\.){5,})/i); const isUCHd = UCversion && parseInt(UCversion[1].split('.').join(''), 10) >= 80; const isIos = navigator.appVersion.match(/(iphone|ipad|ipod)/gi); let dpr = win.devicePixelRatio || 1; if (!isIos && !(matches && matches[1] > 534) && !isUCHd) { // 若是非iOS, 非Android4.3以上, 非UC內核, 就不執行高清, dpr設爲1; dpr = 1; } const scale = 1 / dpr; let metaEl = doc.querySelector('meta[name="viewport"]'); if (!metaEl) { metaEl = doc.createElement('meta'); metaEl.setAttribute('name', 'viewport'); doc.head.appendChild(metaEl); } metaEl.setAttribute('content', `width=device-width,user-scalable=no,initial-scale=${scale},maximum-scale=${scale},minimum-scale=${scale}`); doc.documentElement.style.fontSize = `${_baseFontSize / 2 * dpr * _fontscale}px`; };