懶人必備的移動端定寬網頁適配方案

jopen 9年前發布 | 61K 次閱讀 適配 移動Web開發框架 移動開發

 

如今移動設備的分辨率紛繁復雜。以前僅僅是安卓機擁有各種各樣的適配問題,如今 iPhone 也擁有了三種主流的分辨率,而未來的 iPhone 7 可能又會玩出什么新花樣。如何以不變應萬變,用簡簡單單的幾行代碼就能支持種類繁多的屏幕分辨率呢?今天就給大家介紹一種懶人必備的移動端定寬網頁適配方 法。

首先看看下面這行代碼:

<meta name="viewport" content="width=device-width, user-scalabel=no">

有過移動端開發經驗的同學是不是對上面這句代碼非常熟悉?它可能最常見的響應式設計的viewport設置之一,而我今天介紹的這種方法也是利用了 meta 標簽設置viewport來支持大部分的移動端屏幕分辨率。

目標

  • 僅僅通過配置<meta name="viewport">使得移動端網站只需要按照固定的寬度設計并實現,就能在任何主流的移動設備上都能看到符合設計稿的頁面,包括 Android 4+、iPhone 4+。
  • </ul>

    測試設備

    • 三星 Note II (Android 4.1.2) - 真機
    • 三星 Note III (Android 4.4.4 - API 19) - Genymotion 虛擬機
    • iPhone 6 (iOS 9.1) - 真機
    • </ul>

      iPhone

      iPhone 的適配比較簡單,只需要設置width即可。比如:

      <!-- for iPhone --> <meta name="viewport" content="width=320, user-scalable=no" />

      這樣你的頁面在所有的 iPhone 上,無論是 寬 375 像素的 iPhone 6 還是寬 414 像素的 iPhone 6 plus,都能顯示出定寬 320 像素的頁面。

      Android

      Android 上的適配被戲稱為移動端的 IE,確實存在著很多兼容性問題。Android 以 4.4 版本為一個分水嶺,首先說一說相對好處理的 Android 4.4+

      Android 4.4+

      為了兼容性考慮,Android 4.4 以上拋棄了target-densitydpi屬性,它只會在 Android 設備上生效。如果對這個被廢棄的屬性感興趣,可以看看下面這兩個鏈接:

      • Support for target-densitydpi is removed from WebKit
      • Bug 88047 - Remove support for target-densitydpi in the viewport meta tag
      • </ul>

        我們可以像在 iPhone 上那樣設置width=320以達到我們想要的 320px 定寬的頁面設計。

        <!-- for Android 4.4+ -->  <meta name="viewport" content="width=320, user-scalable=no" />

        Android 4.0 ~ 4.3

        作為 Android 相對較老的版本,它對 meta 中的 width 屬性支持得比較糟糕。以三星 Note II 為例,它的 device-width 是 360px。如果設置 viewport 中的 width (以下簡稱vWidth) 為小于等于 360 的值,則不會有任何作用;而設置vWidth為大于 360 的值,也不會使畫面產生縮放,而是出現了橫向滾動條。

        想要對 Android 4.0 ~ 4.3 進行支持,還是不得不借助于 頁面縮放 ,以及那個被廢除的屬性:target-densitydpi。

        target-densitydpi

        target-densitydpi 一共有四種取值:low-dpi (0.75), medium-dpi (1.0), high-dpi (1.5), device-dpi。在 Android 4.0+ 的設備中,device-dpi 一般都是 2.0。我使用手頭上的三星 Note II 設備 (Android 4.1.2) 進行了一系列實驗,得到了下面這張表格:

        </tr> </tbody>

        </tr>

        </tr>

        </tr>

        </tr>

        </tr>

        </tr>

        </tr>

        </tr>

        </tr>

        </tr> </tbody> </table>

        • vWidth *:指的是與 viewport 中設置的 width 的值相同。
        • device-dpi (2.0 )**:在 Android 4.0+ 的設備中,device-dpi 一般都是 2.0。
        • </ul>

          首先可以看到 320px 是個特別詭異的臨界值,低于這個臨界值后就會發生超出我們預期的事情。綜合考慮下來,還是采用target-densitydpi = device-dpi這一取值。如果你想要以 320px 作為頁面的寬度的話,我建議你針對安卓 4.4 以下的版本設置width=321。

          如果 body 的寬度超過屏幕可視范圍的寬度,就會出現水平的滾動條。這并不是我們期望的結果,所以我們還要用到縮放屬性initial-scale。計算公式如下:

          Scale = deviceWidth / vWidth

          這樣的計算式不得不使用 JS 來實現,最終我們就能得到適配 Android 4.0 ~ 4.3 定寬的代碼:

          var match,
              scale,
              TARGET_WIDTH = 320;

          if (match = navigator.userAgent.match(/Android (\d+.\d+)/)) { if (parseFloat(match[1]) < 4.4) { if (TARGET_WIDTH == 320) TARGET_WIDTH++; var scale = window.screen.width / TARGET_WIDTH; document.querySelector('meta[name="viewport"]').setAttribute('content', 'width=' + TARGET_WIDTH + ', initial-scale = ' + scale + ', target-densitydpi=device-dpi'); } }</pre>

          其中,TARGET_WIDTH就是你所期望的寬度,注意這段代碼僅在 320-720px 之間有效哦。

          縮放中的坑

          如果是 iPhone 或者 Android 4.4+ 的機器,在使用 scale 相關的屬性時要非常謹慎,包括initial-scale,maximum-scale和minimum-scale。 要么保證 Scale = deviceWidth / vWidth ,要么就盡量不用。來看一個例子:

          懶人必備的移動端定寬網頁適配方案

          在縮放比不能保證的情況下,即時設置同樣的width和initial-scale后,兩者的表現也是不一致。具體兩種機型采用的策略如何我還沒有探索出來,有興趣的同學可以研究看看。最省事的辦法就是在 iPhone 和 Android 4.4+ 上不設置 scale 相關的屬性。

          總結

          結合上面所有的分析,你可以通過下面這段 JS 代碼來對所有 iPhone 和 Android 4+ 的手機屏幕進行適配:

          var match,
              scale,
              TARGET_WIDTH = 320;

          if (match = navigator.userAgent.match(/Android (\d+.\d+)/)) { if (parseFloat(match[1]) < 4.4) { if (TARGET_WIDTH == 320) TARGET_WIDTH++; var scale = window.screen.width / TARGET_WIDTH; document.querySelector('meta[name="viewport"]').setAttribute('content', 'width=' + TARGET_WIDTH + ', initial-scale = ' + scale + ', target-densitydpi=device-dpi'); } } else { document.querySelector('meta[name="viewport"]').setAttribute('content', 'width=' + TARGET_WIDTH); }</pre>

          如果你不希望你的頁面被用戶手動縮放,你還可以加上user-scalable=no。不過需要注意的是,這個屬性在部分安卓機型上是無效的哦。

          其他參考資料

          1. Supporting Different Screens in Web Apps - Android Developers
          2. Viewport target-densitydpi support is being deprecated
          3. </ol>

            附錄 - 測試頁面

            有興趣的同學可以拿這個測試頁面來測測自己的手機,別忘了改viewport哦。

            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <meta name="viewport" content="width=250, initial-scale=1.5, user-scalable=no">
                <title>Document</title>
                <style>
                    body {
                        margin: 0;
                    }

                div {
                    background: #000;
                    color: #fff;
                    font-size: 30px;
                    text-align: center;
                }
            
                .block {
                    height: 50px;
                    border-bottom: 4px solid #ccc;
                }
            
                #first  { width: 100px; }
                #second { width: 200px; }
                #third  { width: 300px; }
                #fourth { width: 320px; }
                #log { font-size: 16px; }
            </style>
            

            </head> <body> <div id="first" class="block">100px</div> <div id="second" class="block">200px</div> <div id="third" class="block">300px</div> <div id="fourth" class="block">320px</div> <div id="log"></div> <script> function log(content) { var logContainer = document.getElementById('log'); var p = document.createElement('p'); p.textContent = content; logContainer.appendChild(p); }

                log('body width:' + document.body.clientWidth)
                log(document.querySelector('[name="viewport"]').content)
            </script>
            

            </body> </html></pre>

             本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
             轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
             本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!
        target-densitydpi viewport: width body width 屏幕可視范圍寬度
        low-dpi (0.75) vWidth <= 320 270 270

        vWidth > 320 vWidth* 270
        medium-dpi (1.0) vWidth <= 360 360 360

        vWidth > 360 vWidth* 360
        high-dpi (1.5) vWidth <= 320 540 540

        320 < vWidth <= 540 vWidth* vWidth*

        vWidth > 540 vWidth* 540
        device-dpi (2.0)** vWidth <= 320 720 720

        320 < vWidth <= 720 vWidth* vWidth*

        vWidth > 720 vWidth* 720
sesese色