該方案使用至關簡單,把下面這段已壓縮過的 原生JS(僅1kb,源碼已在文章底部更新,2017/5/3) 放到 HTML 的 head 標籤中便可(注:不要手動設置viewport,該方案自動幫你設置),此方案僅適用於移動端webcss
<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(normal,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=normal?1: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=normal?"50px": a/2*s*n+"px"},e.exports=t["default"]}]); flex(false,100, 1);</script>
這是阿里團隊的高清方案佈局代碼,所謂高清方案就是根據設備屏幕的DPR(設備像素比,又稱DPPX,好比dpr=2時,表示1個CSS像素由4個物理像素點組成)** 動態設置 html 的font-size, 同時根據設備DPR調整頁面的縮放值,進而達到高清效果**。html
毫不是每一個地方都要用rem,rem只適用於固定尺寸!
在至關數量的佈局情境中(好比底部導航元素平分屏幕寬,大尺寸元素),你必須使用百分比或者flex才能完美佈局!
此方案也是默認 1rem = 100px,因此你佈局的時候,徹底能夠按照設計師給你的效果圖寫各類尺寸啦。
好比你在效果圖上量取的某個按鈕元素長 55px, 寬37px ,那你直接能夠這樣寫樣式:react
.myBtn { width: 0.55rem; height: 0.37rem; }
答:老實說固然能夠,不過爲了規範,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 的緣由了麼?git
答:假設你的效果圖寬度是750,在這個效果圖上可能有一個寬度爲7rem(高清方案默認 1rem = 100px)的元素。咱們知道,高清方案的特色就是幾乎完美還原效果圖,也就是說,你寫了一個寬度爲 7rem 的元素,那麼在目前主流移動設備上都是7rem。然而,iphone 5 的寬度爲640,也就是6.4rem。因而橫向滾動條不可避免的出現了。
怎麼辦呢? 這是我目前推薦的比較安全的方式:若是元素的寬度超過效果圖寬度的一半(效果圖寬爲640或750),果斷使用百分比寬度,或者flex佈局。就像把等屏寬的圖片寬度設爲100%同樣。github
答:先說高清方案代碼,再次強調我們的高清方案代碼是根據設備的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 。web
再來講說效果圖,通常來說,咱們的效果圖寬度要麼是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(false, 100, 1) ,將其修改爲flex(false, 66.66667, 1)就不用那麼麻煩的換算了,此時那個90px的直接寫成0.9rem就能夠了。安全
答:能夠這樣去理解問題的緣由,若是不用高清方案,別的UI庫的元素在移動設備上(假設這個設備是iphone 5好了)顯示是正常的,這沒有問題,而後咱們在這個設備上將該頁面截圖放到電腦上看,發現寬度是640(問答1解釋過了),根據你的像素眼大體測量,你發現這個設備上的某個字體大小應該是12px,而你在電腦上測量應該是24px。app
如今咱們使用高清方案去還原這個頁面,那麼字體大小應該寫爲 0.24rem 纔對!iphone
因此,若是你引用了其餘的UI庫,爲了兼容高清方案,你須要對該UI庫裏凡是應用px的地方作相應處理,即: a px => a*0.02 rem
(具體處理方式因人而異,有模塊化開發經驗的同窗可以使用相似的 px2rem 的插件去轉化,也能夠徹底手動處理)
然而真實狀況每每更爲複雜,好比,你引入了百度地圖(N個樣式須要處理轉換);或者你引入了一個
framework;又或者你使用了 video 標籤,上面默認的尺寸樣式很難處理。等等這些棘手問題
面對這些狀況,此時咱們的高清方案若是再也不壓縮頁面,那麼以上問題將迎刃而解。
基於這樣的思路,筆者對高清方案的源碼作了以下修改,即添加一個叫作 normal 的參數,由它來控制頁面是否壓縮。
在文章頂部代碼的最後,你會看到 flex(false, 100, 1)
,默認狀況下頁面是開啓壓縮的。
若是你須要禁止壓縮,因爲咱們的源碼執行後,直接將flex函數掛載到全局變量window上了,此時你直接在須要禁止壓縮的頁面執行 window.flex(true)
就能夠了,而rem的用法保持不變。
有一點美中不足的是,若是禁止了頁面壓縮,高清屏的1像素就不能實現了,若是你必需要實現1像素,那麼自行谷歌:css 0.5像素,有N多的解決方案,這裏再也不贅述。
答:在X5新內核Blink中,在排版頁面的時候,會主動對字體進行放大,會檢測頁面中的主字體,當某一塊字體在咱們的斷定規則中,認爲字號較小,而且是頁面中的主要字體,就會採起主動放大的操做。然而這不是咱們想要的,能夠採起給最大高度解決
解決方案:
*, *:before, *:after { max-height: 100000px }
補充:有同窗反映,在一些狀況下 textarea
標籤內的字體大小即使加上上面的方案,字體也會變大,沒法控制。此時你須要給 textarea
的 display
設爲 table
或者 inline-table
便可恢復正常。
答:我們的rem適合寫固定尺寸。其他的根據須要換成flex或者百分比。源碼示例中就有這三種的綜合運用。
點擊瀏覽:一個標準的640手機頁面設計稿參考(沒錯,在此方案中,你能夠徹底按照這張設計稿的尺寸寫佈局了。就是這麼簡單!)
通常來說,使用了這個方案是不必用媒體查詢了,
點擊瀏覽:一個標準的640手機頁面設計稿參考(沒錯,在此方案中,你能夠徹底按照這張設計稿的尺寸寫佈局了。就是這麼簡單!)
1 'use strict'; 2 3 /** 4 * @param {Boolean} [normal = false] - 默認開啓頁面壓縮以使頁面高清; 5 * @param {Number} [baseFontSize = 100] - 基礎fontSize, 默認100px; 6 * @param {Number} [fontscale = 1] - 有的業務但願能放大必定比例的字體; 7 */ 8 const win = window; 9 export default win.flex = (normal, baseFontSize, fontscale) => { 10 const _baseFontSize = baseFontSize || 100; 11 const _fontscale = fontscale || 1; 12 13 const doc = win.document; 14 const ua = navigator.userAgent; 15 const matches = ua.match(/Android[\S\s]+AppleWebkit\/(\d{3})/i); 16 const UCversion = ua.match(/U3\/((\d+|\.){5,})/i); 17 const isUCHd = UCversion && parseInt(UCversion[1].split('.').join(''), 10) >= 80; 18 const isIos = navigator.appVersion.match(/(iphone|ipad|ipod)/gi); 19 let dpr = win.devicePixelRatio || 1; 20 if (!isIos && !(matches && matches[1] > 534) && !isUCHd) { 21 // 若是非iOS, 非Android4.3以上, 非UC內核, 就不執行高清, dpr設爲1; 22 dpr = 1; 23 } 24 const scale = normal ? 1 : 1 / dpr; 25 26 let metaEl = doc.querySelector('meta[name="viewport"]'); 27 if (!metaEl) { 28 metaEl = doc.createElement('meta'); 29 metaEl.setAttribute('name', 'viewport'); 30 doc.head.appendChild(metaEl); 31 } 32 metaEl.setAttribute('content', `width=device-width,user-scalable=no,initial-scale=${scale},maximum-scale=${scale},minimum-scale=${scale}`); 33 doc.documentElement.style.fontSize = normal ? '50px' : `${_baseFontSize / 2 * dpr * _fontscale}px`; 34 };