移動H5頁面開發(fā)多屏適配 - 方案篇

此篇總結是在學習了 viewport 基礎知識,再參考了淘寶的 lib.flexible 可伸縮布局這個庫,自己推演了 lib.flexible 是怎么作出這個解決方案的。

上一篇我們說過,對于 device-width 相同但是分辨率不同的手機我們可以通過設置 meta viewport 把移動頁面的寬度歸一到一個統(tǒng)一的寬度(這樣一套布局就可以適用不同分辨率的手機)。但是現(xiàn)在不但 iphone 陣營自己出了好幾個 device-width (320px,375px,414px),android 陣營更時百花齊放。那么我們對于不同的寬度的頁面我們希望如果能用一套 css 搞定。最容易想到的就是使用百分比來設置尺寸。但是 css 百分比是根據(jù)父元素的尺寸來計算,而不是根元素譬如 viewport,這樣對嵌套過深的元素計算尺寸非常不友好。同理使用 em 單位也會產(chǎn)生同樣的問題。幸好 css3 出了一個新單位 rem,我簡單的介紹下 rem 的規(guī)則:根據(jù)根元素(html)的字體大小來計算當前尺寸。譬如說 html 這個元素的 font-size 設了 10px,那么當前頁面 1rem 就是 10px,2rem 就是 20px,如果 html 元素的 font-size 設置了 75px,則當前頁面 1rem = 75px,2rem = 150px。

如果我們把頁面寬度分成 100 份,把 html 的 font-size 設置成 viewport-width/100(px),則當前頁面 1rem 就等于 1% 頁面寬度,這樣使用 rem 作為單位開發(fā)就相當于用百分比單位來設置尺寸了。如果愿意可以把所有的尺寸都轉成百分比布局,那么所有不同寬度的頁面都可以用一套 css 搞定。這個方案是可以實現(xiàn)的,只要把 html 的 font-size 設置成 document.documentElement.clientWidth/100(px)。

那是不是簡單的寫下如下的代碼就搞定了多屏適配呢?

<html style="font-size:(document.documentElement.clientWidth/100)px">
  <head>
    <meta name="viewport" content="width=device-width">
    <style>
      div {
        width: 50rem;
      }
    </style>
  <head>
</html>

這樣的方案在高分辨率的手機上會有一系列的問題:

  1. 在大屏幕高分辨率的手機上,以 320px 為頁面寬度布局,元素過大,而且對于設計不友好(空間太?。?。
  2. 會出現(xiàn) 1px 占2個或者多個物理像素的情況,無法做到對設計稿高度還原。
  3. 譬如在 640x960 分辨率的手機上如果用 320px 布局,頁面上有《img src="xxx.png" style="width:25px;height:25px"/》,如果切圖使用 25x25 的圖片,會產(chǎn)生模糊的情況,因為其實高分辨率手機是把圖片放大了,原因大家網(wǎng)上搜下,這不是這篇主要總結的問題。

針對第一個問題高分辨率手機我們可以設置 initial-scale 來把初始化頁面縮小。打個比方 640x960 分辨率的手機設置 <meta name="viewport" content="width=device-width, initial-scale=0.5">,那么頁面初始化寬度就是 750px。

針對第二個問題也可以通過把頁面寬度設置成同手機分辨率寬度一樣,來做到 css 像素和物理像素 1:1 來真實還原設計稿。問題是我怎么知道手機分辨率是多少,且來看 window.devicePixelRatio: 他是密度無關像素(dip)和物理像素比(我們俗稱的 dpr)。舉個例子如果 device-width 是 320,window.devicePixelRatio = 2 說明手機分辨率是 640xYYY,window.devicePixelRatio = 3 說明手機分辨率是 960xYYY。那么我們根據(jù)自己的項目需求針對不同的分辨率的手機對上面的方案可以做一個改進,這次我們要動態(tài)生成 meta(下面是偽代碼,只是為了說明):

<html style="font-size:(document.documentElement.clientWidth/100)px">
  <head>
    <script>
      var deviceWidth = document.documentElement.clientWidth;
      var dpr = window.devicePixelRatio;
      var scale = 1 / dpr; // 如果我們做到 dip 和物理像素 1:1 
      var metaEl = document.createElement('meta');
      metaEl.setAttribute('name', 'viewport');
      metaEl.setAttribute('content', 'width=device-width, initial-scale=' + scale );
      document.firstElementChild.appendChild(metaEl);
    </script>
    <style>
      div {
        width: 50rem;
      }
    </style>
  <head>
</html>

當然這個 scale 怎么設置可以根據(jù)項目具體調整。

針對第三個問題我們的解決方案是不同分辨率,加載不同的圖片。還是那上面第三點問題中的例子,如果 dpr = 2,那么我就提供一個 50x50 的圖片放在你 25x25 的 img 元素里面,這樣就能解決圖片模糊的問題。但是如果每個圖片都需要判斷 dpr 動態(tài)設置 img 的 src,那么寫起來是很麻煩,是否能有方案統(tǒng)一處理?有!把 img 全部轉換成 background-image 然后用 css 來統(tǒng)一處理,看下代碼:

<html>
  <head>
    <script>
      var docEl = document.documentElement
      var deviceWidth = docEl.clientWidth;
      var dpr = window.devicePixelRatio;
      var scale = 1 / dpr; // 如果我們做到 dip 和物理像素 1:1 
      var metaEl = document.createElement('meta');
      metaEl.setAttribute('name', 'viewport');
      metaEl.setAttribute('content', 'width=device-width, initial-scale=' + scale );
      docEl.firstElementChild.appendChild(metaEl);
      // 給 html 添加 font-size 和 data-dpr
      docEl.style.fontSize = document.documentElement.clientWidth/100 + 'px';
      docEl.setAttribute('data-dpr', dpr);
    </script>
    <style>
      div {
        width: 50rem;
      }
      .page {
        width: 90rem;
        height: 100rem;
        background-image: url(bg.png) /* 25x25 圖片 */
      }
      [data-dpr="2"] .page {
        background-image: url(bg@2x.png) /* 50x50 圖片 */
      }

      [data-dpr="3"] .page {
        background-image: url(bg@3x.png) /* 75x75 圖片 */
      }
    </style>
  <head>
</html>

這樣不同分辨率的頁面自動加載不同的圖片,解決了第三個圖片模糊的問題。多屏適配的方案大致的內容就都在這里了,但是我們參看 lib.flexible 庫,它對字體推薦是使用 px 而非 rem,那么針對字體 css 同樣需要:

div {
    width: 1rem; 
    height: 0.4rem;
    font-size: 12px; /* 默認寫上dpr為1的fontSize */
}

[data-dpr="2"] div {
    font-size: 24px;
}

[data-dpr="3"] div {
    font-size: 36px;
}

網(wǎng)上搜了下,看到給出的理由是 :

設計師原本的要求是這樣的:任何手機屏幕上字體大小都要統(tǒng)一 (注意,字體不可以用rem,誤差太大了,且不能滿足任何屏幕下字體大小相同)

我覺得這個說法也是合理的,所以最終多屏適配的方案的細節(jié)還是需要大家根據(jù)自己的項目進行微調。

移動H5頁面開發(fā)多屏適配的方案內容總結到這里,我了解了大致的原理就可以放心使用 lib.flexible 了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容