[適配性]移動Webapp自適應方案

大搜車-自娛發表於2014-12-18

此次方案的優化點

  • 頁面元素會隨寬度的變化而自適應的放大和縮小,和原來不同的是,全頁面的高度、字型都會隨寬度變化,保持同比例的變化,保證頁面不會變形。頁面樣式只需要寫一套CSS佈局即可。
  • 對於無法獲取到螢幕寬度的手機(極少數個例),我們也可以通過自定義的模式新增支援

統一佈局規則

  1. 內部佈局統一使用px作為單位,可以根據視覺稿來還原;
  2. 字型也使用px,可以保持和其他的元素的相同的放縮比例,不要採用em,或者rem,因為目前沒有根據device-width來設定根節點的預設字型,使用rem會隨瀏覽器本身差異而變化,不可控;
  3. 圖片資源,根據設計的提供的資源情況而定。一般資源可根據寬度載入不同的圖片資源的方案。icon類資源,按建光的方案,使用icon fonts
  4. 列表和表格較多,可以考慮是否需要加入Pure.css來繪製表格;

可能存在的問題

  • border的寬度,設定為1px,在Retina螢幕上可能會顯示2個畫素。
  • 有的寬高比不正常的手機,大部分頁面可能會因為高度略高而垂直可滑動,我們的頁面基本垂直都是可以滑動的,這個方案可以通過設定高度可以解決,但是也會影響顯示效果。

前提準備


最初執行一段判斷程式碼,iOS和Android平臺的webkit的差異,需要區分來對待。
根據userAgent來區分裝置,然後載入不同的viewport配置。

var adaptUILayout = (function(){

//根據校正appVersion或userAgent校正螢幕解析度寬度值
var regulateScreen = (function(){
  var cache = {};

  //預設尺寸
  var defSize = {
    width  : window.screen.width,
    height : window.screen.height
  };

  var ver = window.navigator.appVersion;

  var _ = null;

  var check = function(key){
    return key.constructor == String ? ver.indexOf(key) > -1 : ver.test(key);
  };

  var add = function(name, key, size){
    if(name && key)
      cache[name] = {
        key : key,
        size : size
      };
  };

  var del = function(name){
    if(cache[name])
      delete cache[name];
  };

  var cal = function(){
    if(_ != null)
      return _;

    for(var name in cache){
      if(check(cache[name].key)){
        _ = cache[name].size;
        break;
      }
    }

    if(_ == null)
      _ = defSize;

    return _;
  };

  return {
    add : add,
    del : del,
    cal : cal
  };
})();


//實現縮放
var adapt = function(uiWidth){
  var
      deviceWidth,
      devicePixelRatio,
      targetDensitydpi,
  //meta,
      initialContent,
      head,
      viewport,
      ua;

  ua = navigator.userAgent.toLowerCase();
  //whether it is the iPhone or iPad
  isiOS = ua.indexOf('ipad') > -1 || ua.indexOf('iphone') > -1;

  //獲取裝置資訊,並矯正引數值
  devicePixelRatio = window.devicePixelRatio;
  deviceWidth      = regulateScreen.cal().width;

  //獲取最終dpi
  targetDensitydpi = uiWidth / deviceWidth * devicePixelRatio * 160;

  //use viewport width attribute on the iPhone or iPad device
  //use viewport target-densitydpi attribute on the Android device
  initialContent   = isiOS
      ? 'width='+ uiWidth +', user-scalable=no'
      : 'target-densitydpi=' + targetDensitydpi + ', width='+ uiWidth+', user-scalable=no';

  //add a new meta node of viewport in head node
  head = document.getElementsByTagName('head');
  viewport = document.createElement('meta');
  viewport.name = 'viewport';
  viewport.content = initialContent;
  head.length > 0 && head[head.length - 1].appendChild(viewport);
};
return {
  regulateScreen : regulateScreen,
  adapt : adapt
};
})();
/*
 *640為當期頁面指定的統一解析度,其他解析度下均為此解析度的放縮變化
 */
adaptUILayout.adapt(640);

上述方法的執行結果是(Android對應nexus5,其他手機target-densitydpi會有不同):

IOS: <meta name="viewport" content="width=640, user-scalable=no">
Android:<meta name="viewport" content="target-densitydpi=853.3333333333333, width=640, user-scalable=no">

上述方案可以解決市面上大多的手機的螢幕適配問題,但是對於有些特殊的獲取不到window的width的手機,可以通過自動新增的模式加入適配方案。

相關文章