移動端適配之懶適配

關於移動端的適配方案,如今其實已經有不少了,什麼百分比、font-size+rem、視窗單位(vw、vh)等等,在介紹懶適配以前,先說說我經常使用的百分比吧。android

百分比佈局ios

  元素的size:頁面上的元素的width都使用百分比來實現,好比一行三列,每列就是33.33%,高度能夠基於padding-bottom來實現,也可讓內部元素來支撐,這個主要看需求。git

  字體大小:這個通常使用px,根據設計圖來進行修改,最小12pxgithub

  總體頁面:設置一個max-width,而後居中顯示web

  上面差很少就是百分比佈局的一些要點,這其中有關size的都須要根據設計圖來縮放,計算量仍是挺大的,主要是太麻煩。。設計模式

靈感來源瀏覽器

  懶適配的靈感來源是看了淘寶的適配方案,使用viewport來對頁面進行縮放,但淘寶的適配不單單依賴於此,在這裏就不展開了。app

viewport佈局

  <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no,target-densitydpi=device-dpi" />字體

  解釋一下上面這個viewport的做用吧,width=device-width,視窗的width爲設備的width。initial-scale=1,初始化的縮放爲1(至關於什麼都不幹)。user-scalable=no,禁止用戶手動去縮放(在某些安卓上沒有做業)。target-densitydpi=device-dpi,去兼容安卓低版本不支持縮放的問題。

思路

  使用viewport來進行縮放,縮放的計算公式,設備的可視寬度/設計圖的寬度,還有一些兼容和web的處理移動端須要使用meta來縮放,web端須要使用zoom來縮放

  移動端使用meta來進行縮放,由於考慮到須要適配web端,因此必須使用zoom來兼容

  頁面全部元素都須要按照設計圖來固定size,由於縮放也是安裝設計圖來進行縮放的

  在開發的過程當中遇到android4.4如下和魅族的某些手機使用meta縮放有一些問題,因此這些狀況也使用zoom配合target-densitydpi=device-dpi來進行縮放

  對ios設備在手機觸發orientationchange事件,screen獲取差別進行處理。

  在orientationchange的回調裏增長一個定時器,解決某些低端安卓機獲取可視區信息延遲的問題

代碼

不解釋了,直接上代碼和註釋吧

/*這種設計模式下,移動端須要使用meta來縮放,web端須要使用zoom來縮放
                  頁面全部元素都必須按照設計圖的尺寸來固定
              web端的縮放比例,預計的顯示寬度/設計圖的寬度
              android 4.4如下對viewport縮放支持不太好,使用zoom配合target-densitydpi=device-dpi來縮放
                  魅族手機使用viewport縮放有點問題,須要使用上面的方法處理
                  
                  手機旋轉時,android系瀏覽器和safari獲取視窗的不一樣
                  
                  假如android和safari的size都是320*640
                  
                  在豎屏模式下   window.screen.width  window.screen.height
                  android        320                  640
                  safari         320                  640
                  
                  在橫屏模式下   window.screen.width  window.screen.height
                  android        640                  320
                  safari         320                  640
                  在orientationchange的回調裏增長一個定時器,解決某些低端安卓機獲取可視區信息延遲的問題
             **/

 

function scale(deWidth,webWidth){//deWidth設計圖的寬度,webWidth兼容web頁面的寬度,項目在web須要顯示的寬度(不能超過deWidth)
    var changeTimer = null,sWidth = window.screen.width;
    if(/iPhone|iPad|iPod/.test(navigator.userAgent)&&typeof window.orientation!=="undefined"&&window.orientation !== 0){
        sWidth = window.screen.height;
    }
    if(navigator.userAgent.indexOf("Mobile")!==-1){
        window.onorientationchange = function(){
            changeTimer&&clearTimeout(changeTimer);
            changeTimer = setTimeout(function(){
                if(/iPhone|iPad|iPod/.test(navigator.userAgent)&&typeof window.orientation!=="undefined"&&window.orientation !== 0){
                    sWidth = window.screen.height;
                }else{
                    sWidth = window.screen.width
                }
                if(sWidth/deWidth<=1){
                    if (navigator.userAgent.match(/Android (\d+\.\d+)/)){
                        if(parseFloat(navigator.userAgent.match(/Android (\d+\.\d+)/)[1])<4.4||navigator.userAgent.indexOf("MZ-")!==-1){
                            
                            document.documentElement.style.zoom = sWidth/deWidth;
                            return false;
                        }
                    }
                    var meta = document.createElement("meta");
                    meta.setAttribute("name","viewport");
                    meta.setAttribute("content","width=device-width,initial-scale="+(sWidth/deWidth).toFixed(2)+",user-scalable=no,target-densitydpi=device-dpi");
                    
                    document.querySelector("[name=viewport]").remove();
                    document.head.appendChild(meta);
                }
            },500)
        }
        if(sWidth/deWidth<=1){
            if (navigator.userAgent.match(/Android (\d+\.\d+)/)){
                
                if(parseFloat(navigator.userAgent.match(/Android (\d+\.\d+)/)[1])<4.4||navigator.userAgent.indexOf("MZ-")!==-1){
                    document.documentElement.style.zoom = sWidth/deWidth;
                    return false;
                }
            }
            
            var meta = document.createElement("meta");
                meta.setAttribute("name","viewport");
                meta.setAttribute("content","width=device-width,initial-scale="+(sWidth/deWidth).toFixed(2)+",user-scalable=no,target-densitydpi=device-dpi");
                document.querySelector("[name=viewport]").remove();
                document.head.appendChild(meta);
        }
    }else{
        document.documentElement.style.zoom = webWidth/deWidth;
    }
}

能夠在這裏看看效果 demo

2017-07-03 update

解決window.screen在某些狀況下,獲取到的並非可視區的問題,使用document.documentElement.clientWidth代替

在resize的時候還原zoom或者meta 從新去獲取正確的視窗信息(由於縮放的緣由,拿到的size是被放大了,之因此不記錄縮放係數,由於有可能致使精度問題)

解決firefox不支持zoom,使用scale兼容

縮放規則更改
在安卓設備(4.4以上)上統一使用zoom來縮放(meta,target-densitydpi=device-dpi在某些內核下會自帶縮放,即便沒有設置initial-scale)

安卓設備(4.4如下)使用zoom + target-densitydpi=device-dpi

非安卓的使用<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no" />來縮放

var Scale = {
    init:function(deWidth,webWidth){
        var that = this,changeTimer = null;
        that.sWidth = document.documentElement.clientWidth;
        that.deWidth = deWidth;
        that.webWidth = webWidth;
        if(navigator.userAgent.match(/Android (\d+\.\d+)/)&&(parseFloat(navigator.userAgent.match(/Android (\d+\.\d+)/)[1])<4.4)){
                        var meta = document.createElement("meta");
                            meta.setAttribute("name","viewport");
                            meta.setAttribute("content","width=device-width,initial-scale=1,user-scalable=no,target-densitydpi=device-dpi");
                            
                            document.querySelector("[name=viewport]").remove();
                            document.head.appendChild(meta);
        }
        if(navigator.userAgent.indexOf("Mobile")!==-1){
            window.onorientationchange = function(){
                that.resetScale();
                changeTimer&&clearTimeout(changeTimer);
                changeTimer = setTimeout(function(){
                    that.sWidth = document.documentElement.clientWidth;
                    taht.setScale();
                },500)
            }
            that.setScale();
        }else{
            if(navigator.userAgent.indexOf("Firefox")!==-1){
                document.documentElement.style.transform = "scale("+that.webWidth/that.deWidth+")";
            }else{
                document.documentElement.style.zoom = that.webWidth/that.deWidth;
            }
        }
    },
    setScale:function(){
        var that = this;
        if(that.sWidth/that.deWidth<=1){
            if(navigator.userAgent.match(/Android (\d+\.\d+)/)){
                document.documentElement.style.zoom = that.sWidth/that.deWidth;
            }else{
                var meta = document.createElement("meta");
                meta.setAttribute("name","viewport");
                meta.setAttribute("content","width=device-width,initial-scale="+(that.sWidth/that.deWidth)+",user-scalable=no");
                document.querySelector("[name=viewport]").remove();
                document.head.appendChild(meta);
            }
            
            
        }
    },
    resetScale:function(){
        document.documentElement.style.zoom = 1;
        var meta = document.createElement("meta");
        meta.setAttribute("name","viewport");
        meta.setAttribute("content","width=device-width,initial-scale=1,user-scalable=no");
        document.querySelector("[name=viewport]").remove();
        document.head.appendChild(meta);
                    
    }
}

 

結語

上面只是粗略的代碼,可優化的地方還不少,最主要是這種懶適配的思想,固然,由於這種方法使用的較少,應該還存在不少的問題,歡迎指出。

相關文章
相關標籤/搜索