https://www.jianshu.com/p/985d26b40199javascript
該方案使用至關簡單,把下面這段已壓縮過的 原生JS(僅1kb,源碼已在文章底部更新,2017/5/3) 放到 HTML 的 head 標籤中便可(注:不要手動設置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(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只適用於固定尺寸!
毫不是每一個地方都要用rem,rem只適用於固定尺寸!
毫不是每一個地方都要用rem,rem只適用於固定尺寸!
在至關數量的佈局情境中(好比底部導航元素平分屏幕寬,大尺寸元素),你必須使用百分比或者flex才能完美佈局!
看過 《手機端頁面自適應解決方案—rem佈局》的朋友,應該對rem有所瞭解,這裏再也不贅述,
此方案也是默認 1rem = 100px,因此你佈局的時候,徹底能夠按照設計師給你的效果圖寫各類尺寸啦。
好比你在效果圖上量取的某個按鈕元素長 55px, 寬37px ,那你直接能夠這樣寫樣式:java
.myBtn { width: 0.55rem; height: 0.37rem; }
許多同窗對該方案存在很多誤解致使使用出現各類問題,這裏統一回復下。react
答:老實說固然能夠,不過爲了規範,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 。瀏覽器
再來講說效果圖,通常來說,咱們的效果圖寬度要麼是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)(感謝簡友:V旅行指出此處錯誤! 2017/3/24)就不用那麼麻煩的換算了,此時那個90px的直接寫成0.9rem就能夠了。app
答:能夠這樣去理解問題的緣由,若是不用高清方案,別的UI庫的元素在移動設備上(假設這個設備是iphone 5好了)顯示是正常的,這沒有問題,而後咱們在這個設備上將該頁面截圖放到電腦上看,發現寬度是640(問答1解釋過了),根據你的像素眼大體測量,你發現這個設備上的某個字體大小應該是12px,而你在電腦上測量應該是24px。
如今咱們使用高清方案去還原這個頁面,那麼字體大小應該寫爲 0.24rem 纔對!
因此,若是你引用了其餘的UI庫,爲了兼容高清方案,你須要對該UI庫裏凡是應用px的地方作相應處理,即: a px => a*0.02 rem
(具體處理方式因人而異,有模塊化開發經驗的同窗可以使用相似的 px2rem 的插件去轉化,也能夠徹底手動處理)
(2017/9/9更新)然而真實狀況每每更爲複雜,好比,你引入了百度地圖(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
便可恢復正常。(感謝 程序媛喵喵 對此的補充!2017/7/7)
答:我們的rem適合寫固定尺寸。其他的根據須要換成flex或者百分比。源碼示例中就有這三種的綜合運用。
點擊瀏覽:一個標準的640手機頁面設計稿參考(沒錯,在此方案中,你能夠徹底按照這張設計稿的尺寸寫佈局了。就是這麼簡單!)
通常來說,使用了這個方案是不必用媒體查詢了,
點擊瀏覽:一個標準的640手機頁面設計稿參考(沒錯,在此方案中,你能夠徹底按照這張設計稿的尺寸寫佈局了。就是這麼簡單!)
'use strict'; /** * @param {Boolean} [normal = false] - 默認開啓頁面壓縮以使頁面高清; * @param {Number} [baseFontSize = 100] - 基礎fontSize, 默認100px; * @param {Number} [fontscale = 1] - 有的業務但願能放大必定比例的字體; */ const win = window; export default win.flex = (normal, 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 = normal ? 1 : 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 = normal ? '50px' : `${_baseFontSize / 2 * dpr * _fontscale}px`; };
做者:_minooo_連接:https://www.jianshu.com/p/985d26b40199來源:簡書著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。