移動端頁面開發
移動客戶端的開發類型(站在前端立場上來說),主要是三種:
Native App(原生APP),也就是完全使用移動設備系統語言寫的客戶端,iPhone iPad就是純Object-C,安卓就是純JAVA, 是性能最棒的開發方式,但靈活性不好。
Web App, 就是在移動瀏覽器里打開的,純HTML+CSS+JS,說白了就是個網頁,只不過非常的富應用,比如手機瀏覽器訪問的GMAIL。就是在瀏覽器里打開的頁面。IOS支持可以在桌面創建訪問的快捷方式,但是說到底還是打開Safari跑。而且對設備硬件的接口什么的挺薄弱。
Hybrid App.[HTML5 in mobile devices] 。實際上是使用原生寫了一個容器,然后使用HTML+CSS+JS來實現用戶界面和交互。Web App的短處便可以克服(因為自己寫的容器可以輔助暴露偏底層的接口,比如本地存儲或者麥克風控制之類),同時比起純原生的java或者object-c開發靈活性要高(更新可以更快更迅速,也不依賴於市場,因為說白了,就是自己下載更新網頁資源。)實際上這種方式已經不限於移動端。豌豆莢其實是個pc端的hybrid app。
就目前來說,我們只需要考慮webkit內核的瀏覽器和chrome,uc,qq,小米手機瀏覽器就好了。移動端更新換代比pc快多了,兼容性問題會越來越少。但移動設備的尺寸不同,移動端需要做大量的適配工作。
一.移動端彈性布局適配
1.邏輯分辨率和物理分辨率
眾所周知,手機屏幕分辨率是手機的重要參數之一。
大家都知道移動端設備屏幕尺寸非常多,碎片化嚴重。尤其是Android,你會聽到很多種分辨率:480×800, 480×854, 540×960, 720×1280, 1080×1920,而且還有傳說中的2K屏、4K、5k等。近年來iPhone的碎片化也加劇了:640×960, 640×1136, 750×1334, 1242×2208。
俗話說物理分辨率是硬件所支持的,邏輯分辨率是軟件可以達到的。
物理尺寸是指屏幕的實際大小。大的屏幕同時必須要配備高分辨率,也就是在這個尺寸下可以顯示多少個像素,顯示的像素越多,可以表現的余地自然越大。而真正決定顯示效果的,是邏輯像素尺寸。
我們在viewport中,獲取到的,如"width-device",是邏輯像素。所以我們的適配是針對邏輯像素尺寸的。
dpi,表示的是每英寸所擁有的像素(pixel)數目,數值越高,即代表顯示屏能夠以越高的密度顯示圖像。當達到人眼的極限分辨率時,喬幫主給它取了一個很高端的名字——Retina。
2.rem
em單位是相對於父節點的font-size。CSS3新增了一個相對單位rem(root em,根em)。
這個單位與em有什么區別呢?區別在於使用rem為元素設定字體大小時,仍然是相對大小,但相對的只是HTML根元素。這個單位可謂集相對大小和絕對大小的優點於一身,通過它既可以做到只修改根元素就成比例地調整所有字體大小,又可以避免字體大小逐層復合的連鎖反應。目前,除了IE8及更早版本外,所有瀏覽器均已支持rem。對於不支持它的瀏覽器,應對方法也很簡單,就是多寫一個絕對單位的聲明。這些瀏覽器會忽略用rem設定的字體大小。
3.創建媒體查詢
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
meta標簽表示:強制讓文檔的寬度與設備的寬度保持1:1,並且文檔最大的寬度比例是1.0,且不允許用戶點擊屏幕放大瀏覽;
媒體查詢還有很多參數,這里不再細述。
4.適配方案
我們采用rem進行移動端的適配。根據設計稿定高寬設計出來頁面,然后轉換為rem單位。
第一種:CSS
@media only screen and (max-width: 320px), only screen and (max-device-width:320px) { html { font-size:10px; } } @media only screen and (max-width: 640px), only screen and (max-device-width:640px) { html { font-size:20px; } } .test-div{width: 10rem;}
那么這個.test-div的寬度在320px的分辨率下會是10 * 10 = 100px, 在640下是10 * 20 = 200px,從而達到了彈性縮放的目的。
但是這樣做還是有2個問題:
①隨着各種新手機的發布,分辨率也碎片化了,我們無法預知將來會出現的分辨率寬度,我們不可能把所有要兼容的分辨率寫到css里。
②這樣寫只能做到頁面適配不同的寬度,對於那種在各種屏幕上都要在一屏幕內顯示的頁面,就沒有辦法適配了。
第二種:CSS+js
比較理想解決適配的問題就得靠js了,思路非常簡單,判斷一下當前終端的寬度和設計稿寬度的比例,計算出需要縮放的倍數,然后根據這個倍數值改變html的字體大小即可。
如果需要橫豎屏都適配,那么根據終端寬高比例較小的那一個來計算。用通俗的語言來說,如果終端屏幕比設計稿更加寬矮一些,那么久根據它和設計稿的高度比例來計算字體。插件代碼如下:
/* # 按照寬高比例設定html字體, width=device-width initial-scale=1版 # @pargam win 窗口window對象 # @pargam option{ designWidth: 設計稿寬度,必須 designHeight: 設計稿高度,不傳的話則比例按照寬度來計算,可選 designFontSize: 設計稿寬高下用於計算的字體大小,默認20,可選 callback: 字體計算之后的回調函數,可選 } # return Boolean; # xiaoweili@tencent.com # ps:請盡量第一時間運行此js計算字體 */ (function ($, window) { var init = function(option){ var count = 0, designWidth = option.designWidth, designHeight = option.designHeight || 0, designFontSize = option.designFontSize || 20, callback = option.callback || null, root = document.documentElement, body = document.body, rootWidth, newSize, t, self; !function () { rootWidth = root.getBoundingClientRect().width; self = self ? self : arguments.callee; //如果此時屏幕寬度不准確,就嘗試再次獲取分辨率,只嘗試20次,否則使用win.innerWidth計算 if( rootWidth !== window.innerWidth && count < 20 ) { window.setTimeout(function () { count++; self(); }, 0); } else { newSize = getNewFontSize(designWidth,designHeight,designFontSize); //如果css已經兼容當前分辨率就不管了 if( newSize + 'px' !== getComputedStyle(root)['font-size'] ) { root.style.fontSize = newSize + "px"; return callback && callback(newSize); }; }; }(); orientchange(t); } //返回root元素字體計算結果 var getNewFontSize = function(designWidth,designHeight,designFontSize) { var scale = designHeight !== 0 ? Math.min(window.innerWidth / designWidth, window.innerHeight / designHeight) : window.innerWidth / designWidth; return parseInt( scale * 10000 * designFontSize ) / 10000; } //橫豎屏切換的時候改變fontSize,根據需要選擇使用 var orientchange =function(t) { window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", function() { clearTimeout(t); t = setTimeout(function () { self = self ? self : arguments.callee; }, 200); }, false); } var Mobileadapter = function(opt){ if (!opt) { throw("配置不可為空"); } var settings = $.extend({ designWidth: 640, designHeight: 1136, designFontSize: 20, callback: function (argument) { console.timeEnd("test") } }, opt); init.call(this, settings); } $.initMobileadapter = Mobileadapter; }(jQuery, window));
使用:
<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script> <script type="text/javascript" src="mobileadp.js"></script> <script> $(function () { $.initMobileadapter({ designWidth: 650, designHeight: 1800, designFontSize: 20 }); }(jQuery, window)); </script>
幾點問題:
①這段代碼對viewport有要求,必須是width=device-width initial-scale=1,即窗口的大小是設備物理寬度(分辨率 / devicePixelRatio),並且禁止縮放。另外還有一種做法就是手機淘寶的做法,窗口大小是分辨率寬度,然后縮放倍數是1/devicePixelRatio,這里暫且不討論。
②安卓上的問題。經過實測,有些安卓機器,使用1的viewport,在頁面剛加載的時候。不管是讀取window.innerWidth,還是doc的getBoundingClientRect().width,或者是body的clientWidth,都不是設備的物理寬度。所以使用setTimeout,異步100ms執行獲取屏幕寬度的代碼就准確了。
因為width=device-width initial-scale=1,documentElement的寬度又是100%,所以當這兩個值相等的時候我們可以認為目前獲取到的屏幕寬度是准確的。那么使用此條件作為判斷條件,不斷的setTimeout(fun(){}, 0)去判斷,當此條件為真時改變documentElement的字體。可以盡可能快的執行目標代碼。但是又萬一這兩個值一直不相等又不能無限的死循環下去,所以設置了一個嘗試上限,到上限之后用窗口寬度來計算(縮放比例不對的話用戶起碼可以看到完整的頁面)。在chrome下測試,執行40次代碼的平均時間是230ms,考慮到安卓機的js引擎速度,將上限設為了20。
③建議將這段代碼放到head里,第一時間計算好html的fontSize,避免重繪。如果你有有一些跟獲取dom元素尺寸相關的操作,就得放到這個計算函數的回調里面了,這時候就不能放到head里(因為運行的時候dom都還沒加載),只能放到底部或者doc的ready事件里了。最佳實踐是有一個全屏的loading畫面,當fontSize計算好了之后再把真正的頁面展示出來。
4.基礎適配器
以Chrome Emulation的Apple iPhone4為基礎(最小屏幕)適配。
5.px與rem的轉換
移動端設備的分辨率:iPhone設備分辨率寬度分別為640、750、828,現在的設計稿一般是使用640、750的寬度。實際開發時需要將寬高減半,包括字體。那么寬度為640px的設計稿對應的designFontSize就是20px。
將px轉換為rem的公式:&rem=$px /designFontSize * 1rem(&、$為數字);
在css編寫中,我們可以通過函數計算出轉換后的rem。如在sass編寫rem轉換函數如下:
// pixels to rems $designFontSize: 20px !default; //640px psd @function pxToRem($px) { @return $px / $designFontSize * 1rem; }
在編寫css時直接量取psd設計稿的值,如:
.test-div{width: pxToRem(60px);}
二.移動端頁面開發
由於移動端的兼容性較好,盡量使用HTML5+CSS3。尤其CSS3。
CSS3,除了文字陰影(text-shadow)、盒子陰影(box-shadow)、圓角(border-radius)、背景漸變(background: linear-gradient(#000, #fff))、2D變換(transition)、動畫(animation)等大家耳熟能詳的常用屬性外,還有如-webkit-mask、-webkit-text-stroke、-webkit-nbsp-mode、-webkit-tap-highlight-color、-webkit-box-reflect、-webkit-marquee、-webkit-box等。其中-webkit-box可以很好的布局。
三.移動端js:jQuery Mobile還是Zepto
jQuery Mobile和Zepto是移動端的js庫。jQuery Mobile相當於PC端的jQuery UI,它提供了很多頁面的UI庫,能夠很快的開發出漂亮的界面,適合公司沒有UI設計師的前端開發人員來進行移動端的開發。Zepto相當於PC端的jQuery,它提供了很多方法和功能,能夠很快的實現各種需求和功能,適合公司有UI設計師的前端開發人員來進行移動端的開發。
jQuery Mobile的缺點,主要有兩點:一是重,二是UI限制太大。當然jQuery Mobile性能上沒有zepto好。
zepto.js是一個專為mobile WebKit瀏覽器(如:Safari和Chrome)而開發的一個JavaScript框架。它標榜自己在其簡約的開發理念,能夠幫助開發人員簡單、快速地完成開發交付任務。更重要的是這個JS框架,是超輕量級的,只有5KB。zepto.js的語法借鑒並且兼容jQuery。
若考慮移動端與WEB端的統一性選用jquery,單純從移動端來講zepto.js是首選。
四.移動端的模塊化組件(大多基於Jquery)
1.整屏滾動組件
可以查看另外一篇文章《全屏滾動-jQuery插件實現》。
2.動畫組件
使用預定義的動畫Animate.css
①檢測動畫結束事件:
$('#yourElement').one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', doSomething);
②可以更改動畫的持續時間,增加延遲或改變顯示次數:
#yourElement { -vendor-animation-duration: 3s; -vendor-animation-delay: 2s; -vendor-animation-iteration-count: infinite; }
注意:一定要在CSS恬當的的前綴(webkit, moz等)代替“vendor”。
③添加延遲動畫:
selector.delay(300).queue(function(){ //do something })
另外,可以使用move.js實現自定義動畫。
3.拉拽刷新組件
4.touch對應的swipe事件組件。
-------------------------------------------------------------------------------------------------------------------------------------
完
轉載需注明轉載字樣,標注原作者和原博文地址。
更多閱讀:
http://ons.me/wp-content/uploads/2014/04/flexbox.html
http://www.superslide2.com/TouchSlide/
http://www.cnblogs.com/aimyfly/p/3843977.html
http://www.w3cplus.com/mobile/mobile-terminal-refactoring-mobile-layout.html

