精通移動端布局 - 實踐篇 -


本文大多數的內容基本都是從多篇博客或相關文章中進行篩選,提煉出來,原本我也想用我匱乏的語言來描述,但是發現別人已經總結的更好了,所以...我還是乖乖的站在巨人的肩膀上吧~~


完整目錄:

基本概念
    物理像素
    設備獨立像素
    CSS 像素
    PPI的概念
    DPR的概念
    縮放的概念
    viewPort 的概念
    viewport 渲染流程
    Meta 標簽說明

移動端布局實踐
    混合方式
    REM 方式
        響應式
        JS自動換算
    縮放方式
        CSS3 縮放
        viewport 縮放

相關補充
    為什么需要meta標簽?
    傳統響應式布局與移動端響應式的區別
    移動端字體以及大小的設置
    移動端背景圖縮放設置
    使用Sass提高px與rem轉換效率
    通過Chrome進行真機調試
    weinre 遠程調試


移動端布局實踐#

混合方式

混合方式實現的移動端布局實際上就是對PC端布局技術的組合使用,它主要包含以下技術:

  • 定位布局
  • 浮動布局
  • 可塑性布局
  • 百分比布局
  • 相對單位

將這些布局方法根據頁面每個不同部分的特性進行組合使用,例如模態框,彈出層等可以采用定位方式,而頁面元素的排版可以采用浮動布局,也可以使用具有可塑性的Flex布局方案,對於元素的尺寸可以采用百分比或者其它相對單位,而這便是我稱之為“混合方式”的原因。
混合方式進行的移動端網頁布局,所采用的技術通常都具有靈活、可伸縮、可塑等特點,甚至連使用的單位,最好都是相對單位,也只有這樣才能滿足屏幕尺寸多樣性的移動設備。

對於混合布局技術,我首先要說幾點我認為比較重要的基礎知識點:

· 聲明meta標簽
通過meta標簽來聲明viewport是進行手機端頁面開發的必須也是起始步驟

<meta name="viewport" content="width=device-width,maximum-scale=1,minimum-scale=1,user-scalable=no />

· 百分比計算公式
如果你在進行移動端網頁布局中使用到了百分比單位,那么這個公式你一定要清楚

百分比 = 目標尺寸 / 上下文尺寸。

其中目標尺寸就是當前元素的尺寸,而上下文尺寸則是包含當前元素的父元素,通過 目標尺寸 / 上下文尺寸 便可以得到我們需要的百分比結果,另外個人建議百分比結果保留所有小數。

· 設置閥值
可伸縮的布局方案有一個本質特點就是會根絕顯示設備的尺寸進行自適應調整,這一特性本身就是我們所期待的,但是在某些極端的環境下,比如過大或過小的屏幕下,某些元素尺寸也會變的過大或者過小,或者圖片被嚴重拉伸,導致失真等,從而使顯示效果變的很差,而下面的這些CSS屬性就可以很簡單解決這些問題。

max-width:  //設置最大寬度閾值
min-width:  //設置最小寬度閾值
max-height  //設置最大高度閾值
min-height  //設置最小高度閾值

在使用上可以將它們作用在目標元素上,或者對目標元素有所限制的上級元素。

· 對於單位的認識
對於網頁布局的單位,我們不僅要知道px就夠了,還要知道其它幾個比較常用的單位,特別是CSS3推出的一些新的度量單位。

em
em 是一種相對單位,它相對於父元素的字體大小。
em 常用於可縮放的字體需求中,比如在一個多行段落文本中,如果我們設置行高為 line-height:16px 這一固定的像素值,那么一旦在縮放或者改變了文字的大小的情況下,字體會發生大小變化,但是行高的值卻不會發生改變,永遠為16px,如果我們設置行高為 line-height:1em 那么此時行高的值便是一種相對的情況,它會隨着文字大小的改變而改變。
因為em是相對於父元素的字體大小,所以在使用上我們通常都是為 body 設置字體大小,這樣便可以實現一改全改的效果。另外我們還需要了解的是,瀏覽器默認的字體大小是16px,因此 1em 也就等於 16px。

rem
rem是一種相對單位,它相對於根元素 html 的字體大小。
利用這一特性,rem常用於移動端頁面布局,下文中我們會更詳細的說到。

vh/vw
vh/vw都是相對於視口的單位,瀏覽器視口的區域就是通過 window.innerWidth以及 window.innerHeigth 度量得到的范圍。
瀏覽器會將整個視口的寬度或者高度划分為100等份,因此1vw或者1wh就是相對視口寬度或者高度的1%。例如瀏覽器視口的寬度是1920,那么 1920/100 每等份即19.2px。
vh/vw 在使用上很類似與百分比,但是vh/vw也具有百分比不具有的特性,那就是相對於視口,例如當父級元素不具有尺寸的時候,百分比便無法產生作用,但是相對於視口的vh/vw則可以。
vh/vw 還可以應用在一個頁面上有很多垂直排列的區塊,而且每個區塊的高度都是當前瀏覽器顯示區域高度的情況下。

vmin / vmax
vmin / vmax 也是相對於視口的單位,但是vmin會根據視口寬高最小的那個為基准,然后分為100等份,而vmax 則會以視口寬高最大的那個一個為基准,然后分為100等份。

在了解了以上的基本知識后,我會根據一個現成的示例去解讀混合方式的使用實例,這里我就以手機新浪網為例。
首先打開手機新浪網:https://sina.cn/,在chrome下按 F12 ,從上至下觀察,我們可以看到,新浪手機版頁面的head中,通過meta標簽對viewport的尺寸以及縮放進行了調整,再大致的看下頁面內容我們可以看出手機新浪網上很好的運用了H5新增的語義化標簽,例如:

section : 定義每個區域
details : 設置display:none隱藏,來表述對區域內容或作用的聲明
mark    : 標記內容,比如廣告等。
nav     : 用作導航
aside   : 用於表示與頁面主內容松散相關的內容,經常用於側邊欄、廣告、友情鏈接、引文以及導航元素等。
header  : 定義頭部區域
footer  : 定義了網頁的尾部,它主要包含聯系方式、地址、備案信息等。

再從整體到細節,首先是banner區域,我們會發現banner區域的HTML結構很簡單,就是 div > a > img + mark 結構,而且img的寬度是100%即當前顯示區域的100%,高度則是自動適應。

banner

接着,我們看手機版的頭部,它位於banner的下面,主要由logo、兩個按鈕以及常用功能按鈕(天氣,登錄)等組成,整個布局的思路是左右結構,logo與兩個切換按鈕都是左浮動,而常用功能按鈕則是采用右浮動。這樣的好處就體現於在左右兩個結構之間留下了足夠多的空白區域。
再接着的便是導航區域,導航的按鈕數量很多,但是結構依然很簡單,就是 nav > a 結構,並且所有的 a 進行左浮動,因為 a 中的內容都是文字,所以每個導航按鈕的高度可以通過 line-height 進行控制,每個按鈕之間的間隔則用 padding 撐開,寬度則是根據一行要展示的按鈕數量除以1,這里一行顯示6個再考慮到間距,因此寬度都是15%,采用百分比單位,最后通過 white-space:nowrap 強制控制按鈕內容不換行。

nav

再往下便是焦點圖區域,這個區域跟我們平常編寫焦點圖基本相似,所以就不在贅述。
最后便是頁面主要的資訊內容區域,通過控制台我們可以得到內容區域的主要結構是 dl > dt + dd 並且 dl 應用了 display:flex,所以dl中的dt與dd便會水平並排自動划分寬度排列。dt中的是新聞圖片,而dd中則存放新聞標題以及icon,而且dd也應用了box特性,並通過以下CSS屬性,設置其內容及子元素的水平以及垂直排列方式

-webkit-box-orient:vertical; // 設置內容或子元素為上下垂直排列
-webkit-box-pack:justify     // 設置內容或子元素為兩端排列

zw

總的來說,混合模式在使用上其優點在於技術上接近傳統PC端頁面的布局方式,而你所要做的只是對PC上的布局技術進行稍微的改變,但是其缺點也很明顯那就是關鍵元素高寬和位置都不變,只有容器元素在做伸縮變換,所以對於混合模式下的布局,元素、圖片、文字在設計的時候都 要滿足以下特性:

·彈性的元素控件
·自適應的圖片尺寸
·流式的文字展示

更直觀的理解,可以看下圖:

設計稿的特點

REM 方式

REM 是一種相對單位,它依據的是“根”節點的字體 (font-size) 的大小。
REM 是目前移動端頁面布局常用的方式,它可以使整個頁面的所有元素都隨着顯示設備尺寸的變化而相應的調整自己的尺寸,從而增強頁面對設備適配的靈活性,這種變化我稱之為“頁面的縮放”。
既然REM會讓頁面根據不同的顯示設備進行適配縮放,那么必然就會有一個 標准頁面尺寸,就目前而言,整個前端開發界使用最多的標准頁面尺寸則是根據iphone4或者 iPhone5為依據的 640px*1366px ,也有以iphone6為基准的750px。這個標准的頁面尺寸,我們可以將其定義為1,如果當前的顯示設備尺寸小於標准頁面尺寸(640px或者750px)那么便讓頁面尺寸縮小,使其小於1。而當顯示設備尺寸大於標准頁面尺寸,我們即可以做一些其它的適配,也可以將頁面整個居中顯示在顯示設備中然后不進行任何縮放操作。
通過上述,我們可以知道兩個關鍵點,一是頁面的縮放,這個我們等下會說到,二就是采用rem為單位進行頁面布局,實際上rem布局與px布局並沒有什么本質的區別,這個我們可以代入實例去理解,比如現在 htmlfont-size的大小是100px,即 1rem = 100px,如果現在頁面中要放入一個200*200的盒子,那么按照等比關系,即:

div{
    width:2rem;
    height:2rem;
    background:gray;
}

除了將rem與px結合起來進行理解rem布局的原理,淘寶的前端工程師也提出了另一種理解方式,這種方式的優點在於可以向后與 vw/vh 進行兼容理解,首先將頁面划分為100分,每一份的寬度為(n)px,設定1rem = 10n,如果基准頁面是640px的話,那么每份即6.4px 而 1rem = 64px。如果現在有一個 200px * 200px 的盒子,那么按照rem與px的等比關系,即:

div{
    width:3.125rem;
    height:3.125rem;
    background:gray;
}

最后我們談談 REM 實現的頁面縮放適配原理, rem 是依據 html標記的 font-size 大小的相對單位,對於使用rem為單位的頁面,在被載入到顯示設備顯示的時候,會根據顯示設備的尺寸,然后對應的修改html標簽的font-size值,這樣便可以一處修改,整個頁面內容都會發生改變,即實現根據設備尺寸進行縮放的效果。
REM方式進行移動端布局的原理都是相同的,但是不同的在與對於設備尺寸的檢測上,就目前而言分為兩種,一種是通過CSS meida查詢,另一種則是通過JS檢測。

響應式

響應式方式就是通過 CSS media 對顯示設備進行媒體查詢來改變rem與px的對應關系。
下面我貼出我己工作中使用到的移動端媒體查詢規則:

@media screen and (min-width:320px) and (max-width:359px) {
  html {
    font-size: 50px;
  }
}
@media screen and (min-width:360px) and (max-width:374px) {
  html {
    font-size: 56.25px;
  }
}
@media screen and (min-width:375px) and (max-width:383px) {
  html {
    font-size: 58.59375px;
  }
}
@media screen and (min-width:384px) and (max-width:399px) {
  html {
    font-size: 60px;
  }
}
@media screen and (min-width:400px) and (max-width:413px) {
  html {
    font-size: 62.5px;
  }
}
@media screen and (min-width:414px) and (max-width:431px) {
  html {
    font-size: 64.6875px;
  }
}
@media screen and (min-width:432px) and (max-width:479px) {
  html {
    font-size: 67.5px;
  }
}
@media screen and (min-width:480px) and (max-width:539px) {
  html {
    font-size: 75px;
  }
}
@media screen and (min-width:540px) and (max-width:639px) {
  html {
    font-size: 84.375px;
  }
}
@media screen and (min-width:640px) {
  html {
    font-size: 100px;
  }
  body {
    max-width: 640px !important;
    margin: 0px auto !important;
  }
}

在上面這段CSS媒體查詢代碼中,我們以一個640px寬度的設計稿為基准的頁面尺寸,並設定 html 標記的 font-size 值為100px,然后檢測載入當前頁面的顯示設備尺寸,對應的改變font-size的值,最后再進行相應的縮放適配顯示頁面,當顯示設備尺寸大於基准頁面尺寸時則居中顯示在顯示設備中。
響應式REM布局的優點在於可以根據設計稿的特點,自定義的對某些設備進行單獨適配,而缺點是檢測規則固定不可變,這一點相比於“JS自動換算”更為明顯。

JS自動換算

根絕響應式方式的REM思路,我們就可以很簡單的通過JS代碼寫出相應的JS換算方式。
代碼如下:

(function(win,doc){

	var timer = null,
		html = doc.documentElement,
		baseWidth = html.dataset.basewidth*1 || 640,
		metaEl = document.querySelector('meta[name="viewport"]'),
		event = 'onorientationchange' in win ? 'onorientationchange' : 'resize';

	if(!metaEl){
		metaEl = document.createElement('meta');
		metaEl.setAttribute('name','viewport');
		metaEl.setAttribute('content','initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=0');
		html.firstElementChild.appendChild(metaEl);
	}

	function layoutCalc(){

		var width = html.getBoundingClientRect().width,
			ratio = width / baseWidth * 100,
			devicePixelRatio = window.devicePixelRatio,
			rem = ratio < 100 ?  ratio < 50 ? 50 : ratio : 100;

		if(!/\.\d+/.test(devicePixelRatio.toString())){
			html.dataset.dpr = devicePixelRatio;
		}

		html.style.fontSize = rem + 'px';

	}

 	win.addEventListener(event,function(){
 		clearTimeout(timer);
 		timer = setTimeout(layoutCalc,300);
 	},false);

 	win.addEventListener('pageShow',function(e){
 		if(e.persisted){
 			clearTimeout(timer);
 			timer = setTimeout(layoutCalc,300);
 		}
 	},false);

 	layoutCalc();

}(window,document));

功能說明:

· 自定義基准頁面尺寸
通過為 html 標簽添加 data-basewidth 屬性來自定義指定基准頁面的尺寸。
示例:

<html data-basewidth="750" >
</html>

· 定義頁面內容的字體大小
對於一些符合標准的dpr值(只要是整數,例如:1,2,3),都會為 html 標簽再附加一個 data-dpr 屬性,然后開發者便可以根據這個屬性為條件,實現在不同dpr情況下,對內容字體的大小的調整。
示例代碼:

html[data-dpr="1"] .dpr-text{
	font-size:12px;
}
html[data-dpr="2"] .dpr-text{
	font-size:24px;
}
html[data-dpr="3"] .dpr-text{
	font-size:36px;
}
<p class="dpr-text">測試文字</p>

相比“響應式方式”JS自動換算無需添加規則,適合於各類型的顯示設備。

縮放方式

同樣是“縮放” REM方式在縮放的時候,會改變元素的尺寸,而下面要提到的縮放方式,並不會改變元素的原有尺寸,可以理解成只是在視覺上將內容或者頁面縮放至與當前顯示設備相匹配的尺寸。
這種縮放方式,也可以分為兩種類型:

· 通過CSS3的transform對元素進行縮放。
· 對viewport進行縮放。

CSS3 縮放

首先貼出具體的代碼(我已經做好注釋):

function pageScale(opt) {
	var ua = navigator.userAgent,
		wp = ua.match(/Windows Phone ([\d.]+)/),
		android = ua.match(/(Android);?[\s\/]+([\d.]+)?/),
		dom = document.querySelectorAll(opt.selector), // 獲取要縮放的DOM,可以多個。
		dw = document.documentElement.clientWidth, // 獲取當前顯示設備的寬度
		dh = document.documentElement.clientHeight, // 獲取當前顯示設備的高度
		pw = opt.width || 320, //獲取設計稿的最小尺寸 - 寬度
		ph = opt.height || 568, // 獲取設計稿的最小尺寸 - 高度
		mode = opt.mode || 'cover', // 獲取顯示模式
		origin = opt.origin || 'left top 0', // 設置縮放中心點
		ratio = 0, // 定義比值
		i = dom.length; // 獲取要調整DOM的個數

	// 根據模式的不同,從而生成響應的比值,總的來說contain模式只關注寬高中最小的那個。
	if (mode == "contain") {
		if (pw > ph) {
			ratio = dw / pw;
		} else {
			ratio = dh / ph;
		}

	} else if (mode == "cover") { // cover模式下,只關注寬高最大的那個。
		if (pw < ph) {
			ratio = dw / pw;
		} else {
			ratio = dh / ph;
		}

	} else {
		ratio = dw / pw;
	}

	function calcScale(_mode, obj, num) {

		var _o = obj.style;
		_o.width = pw + "px";
		_o.height = ph + "px";
		_o.webkitTransformOrigin = origin;
		_o.transformOrigin = origin;
		_o.webkitTransform = "scale(" + num + ")";
		_o.transform = "scale(" + num + ")";
		// 兼容android 2.3.5系統下body高度不自動刷新的bug
		if (_mode == "auto" && android) {
			document.body.style.height = ph * num + "px";
		} else
		if (_mode == "contain" || _mode == "cover") { //因為通過transform進行縮放,並不會導致DOM的重繪,因此就不會改變DOM的原有尺寸,所以在縮放的時候,還是根絕原有尺寸進行縮放,從而導致縮放后位置發生偏移。從而需要定位進行位置的調整。
			_o.position = "absolute";
			_o.left = (dw - pw) / 2 + "px";
			_o.top = (dh - ph) / 2 + "px";
			_o.webkitTransformOrigin = "center center 0";
			_o.transformOrigin = "center center 0";
			// 阻止默認滑屏事件
			if (wp) {
				document.body.style.msTouchAction = "none";
			} else {
				document.ontouchmove = function (e) {
					e.preventDefault()
				}
			}
		}
	}

	// 循環DOM,依次執行縮放計算函數。
	while (--i >= 0) {
		calcScale(mode, dom[i], ratio);
	}

}

調用方式:

 window.onload = window.onresize = function(){
     pageScale({
         selector : '.box', //模塊的類名
         mode : 'cover',    // auto || contain || cover 
         width : '320',     //默認寬320px 
         height : '568',     //默認高568px
         origin : 'center center 0' //縮放中心點,可選,在contain和cover模式下無效,默認為"left top 0"
     })
  }

這種CSS3縮放實現的移動端適配,是我在白樹的一篇《pageResponse - 讓H5適配移動設備全家》博客中看到的,然后我在其基礎上按照自己的理解,進行了小小的修改。
總的來說,想使用 白樹 這種縮放的方式,第一步需要准備一個大而且高清的設計稿,比如按照iphone5的 640px*1136px,然后調用方法時,要注意在參數中寬度與高度都要按照最小適配的那個尺寸為起始,例如我這里就是 320px*568px 。尤其要注意的是,如果頁面中有插入圖,需要將插入圖的尺寸調整為 320*568。
具體HTML代碼示例:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport">
	<title>pageResponse</title>
</head>
<body>
	<div class="box">
		<img src="demo.jpg" width="320" height="504" alt="">
	</div>
</body>
</html>

viewport 縮放

viewport縮放,它的大致原理是取當前viewport的deviceWidth值與設計稿的寬進行相除,然后得到兩者相差的比例值,再設置meta標簽的initial-scale的為這個比例值,從而縮放整個viewport,這種方式的優點在於布局時,完全可以按照PC端方式(可以用px為單位哦)進行布局,並且對於高版本的安卓,通過設置target-densitydpi屬性 讓其自動調整物理像素與邏輯像素的對應關系。
具體代碼如下:

var phoneWidth = parseInt(window.screen.width); // 取得顯示設備的邏輯像素,需要注意的是 screen.width方式 可能不准
var phoneScale = 680 / phoneWidth;

var ua = navigator.userAgent;
if (/Android (\d+\.\d+)/.test(ua)) {
	var version = parseFloat(RegExp.$1);
	// andriod 2.3到4.0
	if ((version > 2.3) && (version < 3.0)) {
		document.write('<meta name="viewport" content="width=680, minimum-scale = ' + phoneScale + ', maximum-scale = ' + phoneScale + ',user-scalable=no,target-densitydpi=device-dpi">');

	} else {
		// andriod 2.3一下那完全不需要 誰特么還用那么老的東西?!
		document.write('<meta name="viewport" content="width=680, user-scalable=no, target-densitydpi=device-dpi">');
	}
	// 其他系統
} else {
	document.write('<meta name="viewport" content="width=680, user-scalable=no, target-densitydpi=device-dpi">');
}

總的說,縮放方式實際上有一種缺陷,那就是ios系統會出現元素顯示區域與實際元素所在區域有一定的偏移,影響文本、圖片的查看和復制,微信中無法識別二維碼。在沒有文本復制和識別二維碼的頁面時可以用這種方法。


參考鏈接:
http://www.codeceo.com/article/font-size-web-design.html
https://github.com/amfe/lib-flexible
http://www.xiaoxiangzi.com/Programme/CSS/4298.html

下一篇:精通移動端布局 - 補充篇 - 【准備中】....
上一篇:精通移動端布局 - 概念篇 -


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM