關於移動端的適配方案,如今其實已經有不少了,什麼百分比、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); } }
結語
上面只是粗略的代碼,可優化的地方還不少,最主要是這種懶適配的思想,固然,由於這種方法使用的較少,應該還存在不少的問題,歡迎指出。