推薦一個新的移動端多屏適配方案(h5+小程式)

琥珀_ray發表於2018-12-07

一個建議方案

這兩年小程式開發火爆,小程式推薦使用的rpx單位,即:750的設計稿,1rpx=1px,750rpx=100vw=100%,這個方案最大的好處在於,設計稿標記的尺寸可以直接用來寫css,不需要任何工具計算,開發者無需考慮相容問題,都由小程式自己去相容。 這給了我們團隊一個啟發:為什麼我們不把rpx單位或者說這種思想推廣開來呢,於是我們提出一個方案:把rpx用於整個前端開發,包括小程式、h5以及其他,打包時把rpx轉換為vw,不支援vw的瀏覽器做降級,開發者無需考慮單位轉換

這裡簡單介紹下我們建議的方案:

  1. 使用rpx書寫css,1rpx=1px(設計稿原始單位)
  2. 根據應用環境區分打包的時候要不要把rpx轉為vw(小程式就不需要轉換了),轉換方法建議用postss外掛:postcss-rpx-to-viewport
  3. 判斷自己的應用是否需要做vw降級,需要的話,只需在html檔案中body標籤最前面或最後面引入(或直接插入原始碼)vw-polyfill

非常簡單2-3步,搞定移動端多屏適配

上程式碼:

.foo {
  width: 750rpx;
  height: 150rpx;
  margin: 10rpx;
  padding: 1px 1rpx 1px 1rpx; /* all rpx will be converted */
  border: 4px solid gray;   /* px will not be converted */
  font-size: 15rpx;
  line-height: 14rpx;
}
複製程式碼
.foo {
  width: 100vw;
  height: 20vw;
  margin: 1.33333vw;
  padding: 6px 0.8vw 6px 0.8vw; /* all rpx will be converted */
  border: 4px solid gray;   /* px will not be converted */
  font-size: 2vw;
  line-height: 1.86667vw;
}
複製程式碼
.foo {
  width: 100rem;
  height: 20rem;
  margin: 1.33333rem;
  padding: 6px 0.8rem 6px 0.8rem; 
  border: 4px solid gray;  
  font-size: 2rem;
  line-height: 1.86667rem;
}
複製程式碼

寫在前面

本文假設你已經瞭解移動端多屏適配的一些必要知識,如 viewport、rem、vw、dpr、meta標籤等,如果有不熟悉的地方, 請移步:使用Flexible實現手淘H5頁面的終端適配 再聊移動端頁面的適配 兩篇文章,講的非常棒。

從接觸移動端開始,我們就被各種尺寸和密度的手機螢幕所煩惱,為了讓設計稿要在不同手機螢幕上有相對一致性的表現,我們先後嘗試過很多方案。比如:

  1. 用百分比進行佈局,px做細節處理 (缺點:不精準)
  2. 用meta標籤針對螢幕大小寫多個版本的css (缺點:太麻煩了)
  3. 用rem單位,用meta標籤設定htmlfont-size(缺點:只能根據螢幕大小分幾級去相容,不能做到完全相容)
  4. 大概15年底的時候,感謝@大漠的flexible.js(上面第一篇文件),通過js動態改變htmlfont-size來模擬vw的方案比較好的解決了我們面臨的問題(當然,這裡也存在一些問題,具體就不展開了)

如今,vw已經獲得大多數瀏覽器的支援,rem模擬vw的方案就不再是必須的了。下面聊聊怎麼樣使用vw做適配

方案優勢

讓我們就幾個問題來一起看下,新方案有哪些好處:

  1. 為什麼要用vw替代rem?

    • rem方案的初衷,其實就是模擬vw,現在vw已經得到大多數瀏覽器的支援,rem就不再是必須的了
    • flexible方案需要額外引入js檔案,還需要放啊head中,對於頁面效能來說,自然還有有點影響的。
    • js動態改變html font-size的方案,會觸發整個頁面樣式重新渲染,在部分瀏覽器上有肉眼可見的延遲樣式變動,體驗不好。
    • vw單位更直觀易懂,1vw就是頁面寬度的1%,很好理解,rem就需要各種換算了。。。
  2. vw相容性如何?

    • 雖然說大部分瀏覽器都已經支援vw單位了,但是主流機型中,仍然有一小撮是不支援的,要不要做降級,看自己的產品對應機型做取捨了。
    • 實際測試中,會發現不支援的機型和瀏覽器,其實不止下圖中這些,很多安卓高版本的部分瀏覽器也不支援。
      推薦一個新的移動端多屏適配方案(h5+小程式)
      圖一來之:caniuse
      推薦一個新的移動端多屏適配方案(h5+小程式)
      圖二來自文章:再聊移動端頁面的適配
  3. 為什麼要用rpx?

    • 如果你也面臨同時開發小程式和h5~
    • 如果你也經歷過設計稿標註出來100px,需要在心中除以2,再寫到css檔案上;
    • 還要寫各種less/sass 函式、混合巨集?太麻煩;
    • 用瀏覽器外掛自動轉換?rem的程式碼不好理解和維護;
    • 用post外掛自動轉換?要在px後面寫註釋,告訴外掛這個地方不用轉換,神煩;
    • 用了rpx後,只需要在需要轉換的地方寫rpx,不需要的寫px就好啦,互相沒影響。當然"rpx"只是個建議,你也可以用其他的代替,區分於"px"就好了~
  4. 如何方便的做降級?

    • 調研了幾款做vw降級的方案(沒興趣看細節直接略過,看下面一條解決方案),包括: Viewport Units Buggyfillvminpoly 其中 Viewport Units Buggyfill的方案大概是在css打包的使用,結合外掛postcss-viewport-units,把需要轉換單位的樣式都新增一個content屬性,樣式內容額外插入content一份。頁面載入時初始化 Viewport Units Buggyfill,判斷瀏覽器型號,根據是否安卓、版本等決定是否要採用降級,這個判斷方法不是很嚴謹,實際測試中,很多安卓高版本的手機(比如安卓6)也會存在vw不支援的情況,比如華為p9、mate9等, 然後通過document.styleSheets獲取所有樣式和content,把content屬性中的備用樣式插入 到樣式表中,聽起來就特別麻煩不是麼。。。。用的時候也很麻煩,要在打包中配置兩個外掛、html中還要再引用一個,另外css檔案體積也會變大,畢竟額外增加了很多content屬性。 vminpoly的方案感覺好一些,採用插入元素的方法動態判斷瀏覽器是否支援,然後重新載入css原始碼把vw轉換為px,缺點是頁面寬度變動的時候,需要重新轉換並渲染,而且vminpoly有點大,10kb左。

    • 於是,我們做了vw-polyfill這款降級方案,借鑑了一些上面方案的優勢,比如動態檢測瀏覽器是否支援vw的辦法 但是在方案上選擇了直接把vw轉換為rem的方案,設定下html的font-size。實現1rem=1vw。頁面寬度變化的時候,只需要更改html font-size,不需要全部重新轉換vw。 效能更高 ,整個方案有 更好的相容性 ,而且很小, 只有1kb 由於vw單位已經獲得了大多數瀏覽器的支援,如果你不想讓為了少數瀏覽器的降級影響多數使用者的頁面體驗(雖然已經非常小),可以放在body標籤最後載入,犧牲一丟丟不支援vw瀏覽器的使用者體驗。

    • 有興趣瞭解的請移步:vw-polyfill, 不到100行程式碼,只需要引入(建議直接注入html)一個js檔案,沒有任何依賴,也不需要其他外掛配合,就可以輕鬆實現降級。 例:

    * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
    }
    .a {
        width: 25vw;
        height: 25vw;
        background-color: #ff3336;
    }
    .b {
        width: 50vw;
        height: 50vw;
        background-color: #5f98ff;
    }
    複製程式碼
    <head>
      <meta charset="utf-8"/>
      <title>test vw polyfill</title>
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="stylesheet" href="test.css">
      <style>
        .c {
          width: 100vw;
          height: 100vw;
          background-color: #f8ff38;
        }
      </style>
      <style>
        body {
          background-color: antiquewhite;
        }
      </style>
    </head>
    <body>
    <div class="a">
      test div a
    </div>
    <div class="b">
      test div B
    </div>
    <div class="c">
      test div c
    </div>
    <script src="../vw-polyfill.min.js"></script>
    </body>
    複製程式碼

    效果:

推薦一個新的移動端多屏適配方案(h5+小程式)

  1. 如何書寫和打包?
    • 假設我們的設計稿是750px,元素A(class a)標註是100px,你只需要寫 .a {width: 100rpx} 即可
    • rpx轉為vw的辦法有很多,在此我們建議使用:postcss-rpx-to-viewport,不需要任何設定,直接在打包的時候加入。如何應用在vue和react專案中,請點選檢視readme。
    • 如果你的設計稿不是750也不影響,只需設定下外掛的 {layoutWidth: '你的設計稿尺寸'}
    • 這樣你的css檔案仍然保留rpx單位,和設計稿一一對應,更利於後期維護。
    • 其他rpx轉vw的方法,還有很多,比如其他postCss外掛、編輯器外掛、less/sass 函式、混合巨集等,可以自行選擇,這裡就不展開了。

其他問題

  1. 關於retina螢幕下實現 1px 方案

這個網上有挺多辦法的,早版本的flexible方案把解決辦法內建了,個人感覺有點重,還會造成寫字型書寫要結合css屬性 [data-dpr="2"] 來寫,建議大家還是在需要的時候自己另外處理吧。 有興趣請移步移動端1px細線解決方案總結

  1. 關於retina螢幕下 @2x @3x 圖片高清適配

同上,由於不是所有的圖片都需要採用@2x @3x方案,大家在需要的時候,可以選擇增加 @media 做適配,或者利用postCss外掛做自動化、結合阿里雲/其他雲的圖片處理介面。 當然,也有很多其他的方法,大家自行選擇哈 例:

      /* 普通螢幕(裝置畫素比例小於等於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);
          }
      }
      
      /* 高清螢幕(裝置畫素比例大於等於3)使用3倍圖  */
      @media only screen and (-webkit-min-device-pixel-ratio:3){
          .css{
              background-image: url(img@3x.png);
          }
      }     
複製程式碼
  1. 關於字型大小是否使用vw

佈局和影響視覺的字型,建議直接使用vw(即rpx),比如slogan、title等,還是那句話,設計稿標註是多少,就用多少,不需要[data-dpr="2"]這種~ 大段的描述性文字、段落可以酌情選擇,建議使用px,大屏手機可以展示更多文字,而不是(rpx、vw)簡單的變大

  1. 關於雪碧圖

和rem方案一樣,由於轉換後單位的小數,會造成雪碧圖偏差,建議使用其他方案代替比如base64,用也還是可以的,解決辦法網上很多網上也有很多 可以自己搜尋或移步:手淘的Flexible方案能使用雪碧圖嗎?

以上,文中部分引用均用超連結的形式標出

如有不準確之處,歡迎留言拍磚~

相關文章