寫在最前:
對於移動端頁面的開發自己很早就想做下簡單的總結了,但感覺不知道該從何說起,有一天看了兩篇網上一位作者的文章(後面資源裡面會給出連結),覺得寫得真的是很好,但是還有一些問題我不是很清楚,所以自己也查閱了相關的文獻,結合前面那位作者的一些思路,寫下了這篇總結。當然,有說的不對的地方,還望指出,謝謝。
準備工作:
照例,貼下我的部落格地址,別忘了去點贊哈~
兩個畫素:裝置畫素+css畫素
- 裝置畫素:絕對單位,裝置畫素即裝置的物理畫素,對於每個裝置來說,其裝置畫素是固定的,它是每個裝置能控制顯示的最小單位。通常我們所說的1920x1080畫素分別率就用的是裝置畫素。
- css畫素:適用於web程式設計,是前端開發在描述css樣式時經常用到的畫素單位。比如,設定某個div的寬度為width:200px,這個就是css畫素,是一種抽象概念,實際上並不存在。
頁面的縮放:
- 當使用者放大或者縮小頁面時,改變的是css畫素,而裝置畫素不會發生改變。如:頁面中一個div,它的寬度是200px,當使用者操作頁面,放大兩倍,此時一個css畫素的面變成了4個裝置畫素的面積:寬放大2倍x高放大兩倍
- 頁面縮放比例(zoom level)= screen.width / window.innerWidth (一般情況下可以這麼計算)
裝置畫素比(DPR):
- 在頁面縮放比為1的情況下,裝置畫素比(DPR) = 裝置畫素個數 / 視覺視口css畫素個數(device-width)
- 對於不同的裝置來說裝置畫素比是不一樣的。在早期iphone的DPR值是等於1的,但是後來引入了高密度螢幕,即為了更清晰的展示畫面,在有限的裝置空間內引入了更多的裝置畫素。所以後來iphone裝置的DPR就改變了,值一般為2。可以通過偵錯程式看到裝置的裝置畫素比,如下圖所示:
場景再現:
移動端需求:給你一個750px的設計稿,上面畫了一個200px的矩形框。
既然是寫移動端頁面,作為一名前端開發者,我想你們首先就會在裡面敲下這樣一句話:
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0">
複製程式碼
看上去只有那麼熟悉了。這句話什麼意思?它有什麼作用呢?彆著急,我們先來理解下viewport這個概念。
viewport:
viewport即視口,它的作用是限制頁面的根元素即。在PC端,視口可以看成只有一個,即我們所看到的頁面視窗,它的大小由瀏覽器視窗來決定。但是在M端視口分為兩類:視覺視口(visual viewport)和佈局視口(layout viewport),後文我會詳細解釋為什麼移動端有這兩個視口。(既然M端做了這樣的劃分,我們也可以對PC端採取同樣的方式,即PC端viewport就是PC端的visual viewport)
所以,對於PC端來說,根元素的大小就可以由visual viewport來確定了。那麼,怎麼計算呢?下面分情況給出相應的計算方式:
- 瀏覽器沒有出現(橫向、縱向)滾動條且沒有人為的去設定元素的寬高(html的寬高可以人為的去設定,但是一般情況下我們不建議這樣做):
html的寬度 = document.documentElement.clientWidth = document.documentElement.offsetWidth = window.innerWidth
複製程式碼
- 瀏覽器出現滾動條且沒有人為的去設定元素的寬高:
html的寬度 = document.documentElement.clientWidth = document.documentElement.offsetWidth = window.innerWidth - 滾動條的寬度
複製程式碼
- 人為設定了的寬度時:
html的寬度 = document.documentELement.offsetWidth
複製程式碼
如此,PC端就可以按照其viewport的尺寸進行頁面的佈局。有了上面的基礎,我們接下來看看M端頁面。M端較之於PC端,一個顯然的不同就是裝置的尺寸。M端的螢幕寬度大多<=400px,不像PC端那樣,動不動就是上千畫素。這樣PC端的頁面到了移動端,可謂是不堪入目,下面是真實的網站截圖,
- PC端頁面:
- PC端頁面放到移動端:
可以看到,在沒有做M頁面優化的情況下,PC端頁面放到M端時,為了讓你看清整個頁面,強行把裡面的內容進行縮放,以至於模糊不清,簡直無法直視。(當然人家的頁面是做了M端優化的,為了看效果我是把裡面的給刪掉了,哈哈哈,機智吧~)
如何解決M端裝置尺寸太小的問題呢:
既然移動端的視覺視口太窄(瀏覽器的寬度)而不能滿足css佈局的需求,那麼就想辦法弄一個更寬的視口出來,滿足M端佈局需求。此時,layout viewport應運而生。
佈局視口比視覺視口要寬的多,M端就是根據佈局視口來進行css佈局的。而且在M端,元素的大小是由佈局視口來確定的,就像我們之前談到的PC端和視覺視口的關係那樣。那麼,佈局視口到底有多大呢,以及他是怎樣去計算的呢?
對於M端來說,其佈局視口的大小取決於瀏覽器廠商,一些常見的佈局視口取值如下表所示:
browser | viewport width |
---|---|
Safiri | 980px |
Opera | 850px |
Android WebKit | 800px |
IE | 974px |
跟PC端有點類似,佈局視口的大小可有下面的方式取得:
佈局視口的寬度 = document.documentElement.clientWidth
佈局視口的高度 = document.documentElement.clientHeight
複製程式碼
有了這個佈局視口的概念後,我們再來看看PC端頁面放到M端,會呈現出怎樣的情況:
看到了麼,此時頁面到了M端以後,不會強行的去縮放裡面的內容,而是根據佈局視口的大小去進行css佈局,由於佈局視口比視覺視口(瀏覽器的寬度)大很多,就出現了滾動條。所以,通過滾動頁面你可以清楚的看到頁面的整個內容了。但是,這還不是我們想要的M端頁面,我們想要怎樣一種效果呢?應該是這樣:我們不想頁面出現滾動條,而且想要頁面所有的內容都呈現在我們的視野範圍內。即要是我們能夠自己去控制M端佈局視口的大小就好了,讓它以一個使用者比較舒適的大小呈現在螢幕上,標籤幫我們完成了這一舉動,讓我們繼續看看吧。
meta:
最初是由蘋果公司提出的,後來被多家瀏覽器廠商複製。其目的是為了調整M端佈局視口的大小,以適應各種寬度的移動裝置。該標籤應該置於標籤內,其語法如下所示:
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" user-scalable=no>
複製程式碼
是不是很熟悉,對啦,我們在文章的開頭時曾寫過。關於viewport我們不再解釋,下面簡單說一下content裡面的內容。content屬性的值是一個字串,字串裡面的內容是由逗號隔開的名值對,一共5個:
- width:佈局視口的寬度,可以自己設定準確的值如width=300,也可以是一些特殊值,如width=device-width,顧名思義就是裝置的寬度
- initial-scale:設定頁面的初始縮放程度,可以是小數
- minimum-scale:設定頁面的最小縮放程度
- maximum-scale:設定頁面的最大縮放程度
- user-scalable: 是否允許使用者對頁面進行縮放
所以,列子中程式碼的含義就是,設定佈局視口的寬度為裝置的寬度,頁面的初始縮放比例、最小縮放比例以及最大縮放比例值為1,不允許使用者縮放頁面。
好了,寫到這裡,大家或多或少對有了一定的瞭解吧,下面我們就開始真正的移動端頁面開發了,哈哈哈,費了老大勁兒解釋,但是我覺得很有必要吧。
移動端頁面開發:
&承接上面的需求,我們在750px的設計稿(其實這也是現在iPhone6/7的設計稿樣子)上看到了一個寬高都是200px的綠色矩形框,如下圖所示:
於是我們這樣設計程式碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>移動端頁面開發</title>
<style>
* {
margin: 0;
padding: 0;
}
.weekend {
width: 200px;
height: 200px;
background-color: green;
}
</style>
</head>
<body>
<div class="weekend"></div>
</body>
</html>
複製程式碼
效果如下所示:
咋一看,哎,不對呀,矩形框的寬高沒有問題,但是設計稿上的裝置寬度是750,而瀏覽器顯示的寬度則是375,這是怎麼回事呢。其實,設計稿是按照裝置畫素去設計的,所以在頁面縮放比為1的情況下,根據公式:
DPR = 裝置畫素/視覺視口css畫素個數(device-width)
複製程式碼
在iphone7上DPR=2,所以1個css畫素等效於2個裝置畫素,所以對於矩形框的寬度,應該設為200/2=100px,當然對於其他的DPR值,我們應該用設計稿上的裝置畫素/DPR,得到真正應該得到的css畫素。但是,如果我們不想每次都去計算真正的css畫素值,而是讓瀏覽器自動去計算呢。別忘了,我們前面提到的中content的 值initial-scale,它縮放的是css的畫素,所以利用這個特性,設定initial-scale = 1/DPR,此時M端一個裝置畫素就等於一個css畫素了,這樣我們就可以直接將設計稿上的畫素值設為css的畫素值,而不用人為的去計算了。程式碼如下: (多說一句,利用window.devicePixelRatio可以獲取裝置的DPR值)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>移動端頁面開發</title>
<style>
* {
margin: 0;
padding: 0;
}
.weekend {
width: 200px;
height: 200px;
background-color: green;
}
</style>
</head>
<body>
<div class="weekend"></div>
<script>
var scale = 1/window.devicePixelRatio;
document.querySelector('meta[name="viewport"]').setAttribute('content', 'width=device-width, initial-scale=' + scale + ', user-scalable=no')
</script>
</body>
</html>
複製程式碼
效果如下所示:
這下好了,好像達到我們想要的效果了,可是為什麼說好像呢,看到這裡的朋友不知道有沒有想過這樣一個問題,假如現在你不是iphone7的裝置,而是iphone5,他們的DPR值都為1,但是裝置的寬度卻是不一樣的。然而我們的程式碼設計並沒有考慮到這樣的情況,我們來驗證下這個想法,用iphone5看一下頁面效果,如下所示:
果然,iphone5上還是100px,這該如何是好呢?我們應該留意到了這樣一個現象,隨著裝置的寬度在變化,因為我們設定了頁面佈局視口的寬度值等於device-width,而html的寬度又是由佈局視口所決定的(document.documentElement.clientWidth),所以只要我們想到有什麼辦法能讓頁面中元素的寬度能夠隨著根元素的變化而變化,這樣我們就能夠達到想要的效果了。是的,沒錯,就是rem,我想對於rem這個概念應該並不陌生吧。簡單來說,rem是一個相對單位,是相對於html字型大小的單位。舉個例子: 當我們設定html {font-size: 10px}時,設定頁面某個div {width: 2rem},此時div經過計算後的寬度就等於2*10即20px。所以,通過rem的這個功能,我們就可以實現我們想要的效果了。開始寫吧,程式碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>移動端頁面開發</title>
<style>
* {
margin: 0;
padding: 0;
}
.weekend {
width: 2.666667rem;
height: 2.666667rem;
background-color: green;
}
</style>
</head>
<body>
<div class="weekend"></div>
<script>
var scale = 1/window.devicePixelRatio;
document.querySelector('meta[name="viewport"]').setAttribute('content', 'width=device-width, initial-scale=' + scale + ', user-scalable=no');
document.documentElement.style.fontSize = document.documentElement.clientWidth / 10;
</script>
</body>
</html>
複製程式碼
程式碼修改的地方有兩處,一個是script裡面,新增了一個修改根元素fontSize的語句,為什麼要除以100呢,因為直接取document.documentElement.clientWidth的值感覺有點略大了,這個標準孫便設計的,想怎麼來怎麼來。==但是有個地方我們得注意一下:==就是font-size的最小值問題,我們不能設定得太小否則無效== 。另外一個地方就是style裡面css樣式,因為是750px的設計稿,所以width值設定為200/(750/100),同樣如果是640px的設計稿,就是200/(640/100),哈哈,大功告成,我們來看一看效果:
終於,大功告成,真是不容易啊,可是,這個真的就是最佳的解決方案麼?那可未必。你們看,我們在設定css的樣式的時候,需要用設計稿上的樣式去除以fontSize轉化後的值,比如說750的設計稿,就要除以75;640的設計稿就要除以64,畢竟這些值不是什麼容易除盡的值,所以計算起來還比較麻煩。那有沒有什麼解決方案呢?哈哈哈,辦法總比困難多,根據網上有人提出的解決方案,完美的解決了這個問題,其實就一句話,我這裡不做解釋,留給各位自己去體會,相信在前面介紹的基礎上,這段程式碼是很容易解釋的,程式碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="">
<title>移動端頁面開發</title>
<style>
* {
margin: 0;
padding: 0;
}
.weekend {
width: 2rem;
height: 2rem;
background-color: green;
}
</style>
</head>
<body>
<div class="weekend"></div>
<script>
document.documentElement.style.fontSize = document.documentElement.clientWidth / 7.5 + 'px';
</script>
</body>
</html>
複製程式碼
就一句話,巧妙的解決了移動端設計的問題,對於設計稿上的寬度,只要除以100即可。
寫在最後:
終於,這篇文章算是完結了,花了自己一個週六的時間,當然裡面關於最後移動端頁面的設計思路是對別人文章的很大借鑑,但是整體很多地方都有自己的想法總結與移動端知識的延伸。其實,我們再來看M端,無外乎兩個方面是我們需要考慮的問題:一個是移動端一個css畫素和一個裝置畫素的對等關係,一個是不同裝置的寬度自適應問題。知道怎麼去解決這兩個問題,那麼你就算是基本上掌握了移動端頁面設計的主要思想。當然,不管是對別人借鑑也好,還是自己領悟也好,主要是自己對這部分知識點有所掌握,能夠站在自己的角度獨立完成這篇總結,對我而言也是極好的。裡面有些說得不正確的地方,還望各位讀者指出,謝謝~
參考資料:
A tale of two viewports — part one