手機端頁面自適應解決方案—rem布局(進階版,附源碼樣本)

來源:互聯網
上載者:User

標籤:code   define   執行   開啟   html   cimage   roi   換算   fun   

轉自:1190000007350680

一年前筆者寫了一篇 《手機端頁面自適應解決方案—rem布局》,意外受到很多朋友的關注和喜歡。但隨著時間的推移,該方案已然過時,故為大家介紹一個目前我極力推薦使用的,更加完美的方案——rem布局(進階版)

另外:
  • 此方案僅適用於移動端web
  • 文章底部常見問題說明第四條,筆者已給出一個相當便捷的解決方案,歡迎留言交流。(2017/9/9)

該方案使用相當簡單,把下面這段已壓縮過的 原生JS(僅1kb,源碼已在文章底部更新,2017/5/3) 放到 HTML 的 head 標籤中即可(注:不要手動設定viewport,該方案自動幫你設定)

<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調整頁面的縮放值,進而達到高清效果

有何優勢
  • 引用簡單,布局簡便
  • 根據裝置螢幕的DPR,自動化佈建最合適的高清縮放。
  • 保證了不同裝置下視覺體驗的一致性。(老方案是,螢幕越大元素越大;此方案是,螢幕越大,看的越多)
  • 有效解決移動端真實1px問題(這裡的1px 是裝置螢幕上的物理像素)
如何使用

重要的事情說三遍!
絕不是每個地方都要用rem,rem只適用於固定尺寸!
絕不是每個地方都要用rem,rem只適用於固定尺寸!
絕不是每個地方都要用rem,rem只適用於固定尺寸!
在相當數量的布局情境中(比如底部導航元素平分螢幕寬,大尺寸元素),你必須使用百分比或者flex才能完美布局!
看過 《手機端頁面自適應解決方案—rem布局》的朋友,應該對rem有所瞭解,這裡不再贅述,
此方案也是預設 1rem = 100px,所以你布局的時候,完全可以按照設計師給你的寫各種尺寸啦。
比如你在上量取的某個按鈕元素長 55px, 寬37px ,那你直接可以這樣寫樣式:

.myBtn {   width: 0.55rem;   height: 0.37rem;}
rem布局(進階版)實踐應用

為了讓朋友們更清晰感受此方案的巨大優勢,下面是源碼和Demo實踐應用1(請在手機端或者手機模式下瀏覽效果更佳!)實踐應用2(請在手機端或者手機模式下瀏覽效果更佳!)樣本源碼線上Demo常見問題說明,新手很有必要看一下(2017/1/19)

許多同學對該方案存在不少誤解導致使用出現各種問題,這裡統一回複下。

1.問:為啥手機網頁寬度是要640或者750的,我非得弄個666的不行咩?

答:老實說當然可以,不過為了規範,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 的原因了嗎?(真沒有歧視安卓機的意思。。。)

2.問:寬度用rem寫的情況下, 在 iphone6 上沒問題, 在 iphone5上會有橫向捲軸,何解?

答:假設你的寬度是750,在這個上可能有一個寬度為7rem(高清方案預設 1rem = 100px)的元素。我們知道,高清方案的特點就是幾乎完美還原,也就是說,你寫了一個寬度為 7rem 的元素,那麼在目前主流行動裝置上都是7rem。然而,iphone 5 的寬度為640,也就是6.4rem。於是橫向捲軸不可避免的出現了。
怎麼辦呢? 這是我目前推薦的比較安全的方式:如果元素的寬度超過寬度的一半(寬為640或750),果斷使用百分比寬度,或者flex布局。就像把等屏寬的圖片寬度設為100%一樣。

3.問:不是 1rem = 100px嗎,為什麼My Code寫了一個寬度為3rem的元素,在電腦端的Google瀏覽器上寬度只有150px?

答:先說高清方案代碼,再次強調咱們的高清方案代碼是根據裝置的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就可以了。

4.問:在此方案下,我如果引用了別的UI庫,那些UI庫的元素會顯得特別小,如何解決?

答:可以這樣去理解問題的原因,如果不用高清方案,別的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像素,那麼自行Google:css 0.5像素,有N多的解決方案,這裡不再贅述。

5.問:有時候字型會不受控制的變大,怎麼辦?

答:在X5新核心Blink中,在排版頁面的時候,會主動對字型進行放大,會檢測頁面中的主字型,當某一塊字型在我們的判定規則中,認為字型大小較小,並且是頁面中的主要字型,就會採取主動放大的操作。然而這不是我們想要的,可以採取給最大高度解決

解決方案:

*, *:before, *:after { max-height: 100000px }

補充:有同學反映,在一些情況下 textarea 標籤內的字型大小即便加上上面的方案,字型也會變大,無法控制。此時你需要給 textarea 的 display 設為 table 或者 inline-table 即可恢複正常。(感謝 程式媛喵喵 對此的補充!2017/7/7)

6.問:我在底部導航用的flex感覺更合適一些,請問這樣子混著用可以嗎?

答:咱們的rem適合寫固定尺寸。其餘的根據需要換成flex或者百分比。源碼樣本中就有這三種的綜合運用。

7.問:在高清方案下,一個標準的,較為理想的寬度為640的頁面應該是怎樣的?

點擊瀏覽:一個標準的640手機頁面設計稿參考(沒錯,在此方案中,你可以完全按照這張設計稿的尺寸寫布局了。就是這麼簡單!)

8.問:可以提供下這個高清方案的源碼嗎?
‘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`;};
9.問:我在使用 rem 布局進階方案的時候遇到了XXX的問題,如何解決?
  • 此方案久經考驗,具有普遍適用性,自身出致命問題的情況很少,至少筆者是沒遇到過。
  • 絕大多數你遇到的問題,都是由於對rem布局理解不到位導致的。本文對rem布局做了大量的解釋說明,配置了若干 demo,你可以把你遇到的問題放到demo裡測試。遇到問題時,首先問自己,為什麼這明顯的錯誤大家沒遇到就我遇到了??
  • 如果你真的經過充分驗證,比對,確實是rem布局自身出了問題,那麼請私信我,把還原問題情境的 demo 或者檔案發給我。謝謝!

手機端頁面自適應解決方案—rem布局(進階版,附源碼樣本)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.