移動端開發-viewport實現響應式設計

1. 不使用viewport出現的問題

提到響應式設計,大家首先想到的可能是 Bootstrap , @media 。前者是一個響應式UI庫,風格比較扁平化,類似的還有雅虎的Pure。@media是CSS3的屬性,利用它可以在不依賴其他庫的情況下實現響應式設計。如果你使用過媒體查詢,應該熟悉下面的代碼:

可查看github下載實例代碼

        @media screen and (min-width: 960px) {
          body { background-color: blue; }
        }

        @media screen and (max-width: 960px) and (min-width: 500px) {
          body { background-color: red; }
        }

        @media screen and (max-width: 500px) {
          body { background-color: yellow; }
        }

我在body里加了一段話,在PC端效果如下:
開始:
這裏寫圖片描述

縮小瀏覽器窗口:
這裏寫圖片描述

再縮小瀏覽器窗口:
這裏寫圖片描述

我把這樣頁面放到服務器上,用我的手機訪問,我的手機屏幕寬度是414px。那麼這個頁面在我手機上應該是黃色。請看屏幕截圖:
這裏寫圖片描述

是藍色的。那麼問題來了,爲什麼媒體查詢失效了呢。這是由於設備尺寸和Viewport尺寸不一致導致的。爲了解釋這個問題,首先我們要理解移動設備上的1px != css中的1px。

2. css中的px與移動設備的px

在css中我們一般使用px作爲單位,在桌面瀏覽器中css的1個像素往往都是對應着電腦屏幕的1個物理像素,這可能會造成我們的一個錯覺,那就是css中的像素就是設備的物理像素。但實際情況卻並非如此,css中的像素只是一個抽象的單位,在不同的設備或不同的環境中,css中的1px所代表的設備物理像素是不同的。影響css中px與設備px換算的因素主要有以下兩個:

  • 設備尺寸
  • 用戶縮放

設備尺寸
iphone3的分辨率爲320x480,在iphone3上,一個css像素確實是等於一個屏幕物理像素的。從iphone4分辨率提高了一倍,變成640x960,但屏幕尺寸卻沒變化,這就意味着同樣大小的屏幕上,像素卻多了一倍,這時,一個css像素是等於兩個物理像素的。其他設備類似。
用戶縮放
當用戶把頁面放大一倍,那麼css中1px所代表的物理像素也會增加一倍;反之把頁面縮小一倍,css中1px所代表的物理像素也會減少一倍。你可以想象,css中的px是一個一個小格子,在縮放頁面的時候,其實是在縮放每個小格子,而設備物理像素顯然是大小不變的。

在移動端瀏覽器中以及某些桌面瀏覽器中,window對象有一個devicePixelRatio屬性,它的官方的定義爲:設備物理像素和設備獨立像素的比例,也就是 devicePixelRatio = 物理像素 / 獨立像素。css中的px就可以看做是設備的獨立像素,所以通過devicePixelRatio,我們可以知道該設備上一個css像素代表多少個物理像素。在上面例子中增加js腳本:

window.alert(window.devicePixelRatio);

在PC端:
這裏寫圖片描述

在我的手機上:
這裏寫圖片描述

設備像素比是不同的。

3. 三種視口(viewport)

你可能以爲我囉嗦這麼多終於要進入正題了。咳咳,其實我還是想讓你瞭解下面三個概念。如果你熟悉移動端開發,請跳過這節直接看4 ,如果你剛剛接觸移動端開發,我建議你讀下去,早晚你得了解。

3.1 佈局視口(layout viewport)

移動設備上的瀏覽器認爲自己必須能讓所有的網站都正常顯示,即使是那些不是爲移動設備設計的網站。但如果以瀏覽器的可視區域作爲viewport的話,因爲移動設備的屏幕都不是很寬,所以那些爲桌面瀏覽器設計的網站放到移動設備上顯示時,必然會因爲移動設備的viewport太窄,而擠作一團,甚至佈局什麼的都會亂掉。所以這些瀏覽器就決定默認情況下把viewport設爲一個較寬的值,比如980px,這樣的話即使是那些爲桌面設計的網站也能在移動瀏覽器上正常顯示了。這個寬度被稱爲佈局視口(layout viewport),可以通過document.documentElement.clientWidth獲得。

3.2 視覺視口(visual viewport)

雖然獨立佈局視口的創造很大程度地幫助了桌面網站到手機上的轉移,但我們不能完全無視移動端設備的屏幕尺寸。一些CSS聲明與用戶見到的東西有關,而與CSS的初始包含塊無關。並且,有時候知道用戶看到了網站的哪些部分對web開發者會有幫助。視覺視口是用戶正在看到的網站的區域,對於的javascript屬性是window.innerWidth.
縮放會影響視覺視口的大小。當縮放程度是100%時,視覺視口與設備屏幕一樣寬。放大使視覺視口變得更小,因爲屏幕上顯示的CSS像素更小了,而縮小會讓視覺視口更大,因爲屏幕上的CSS像素更多了。因此縮放程度和視覺視口的大小是逆相關的:放得越大,視覺視口越小。
注意:當用戶縮放時,只有視覺視口的尺寸會發生改變,佈局視口不會改變。移動端的縮放不會導致CSS佈局被重新計算。

3.3 理想視口(ideal viewport)

現在越來越多的網站都會爲移動設備進行單獨的設計,所以必須還要有一個能完美適配移動設備的viewport。所謂的完美適配指的是,首先不需要用戶縮放和橫向滾動條就能正常的查看網站的所有內容;第二,顯示的文字的大小是合適,比如一段14px大小的文字,不會因爲在一個高密度像素的屏幕裏顯示得太小而無法看清,理想的情況是這段14px的文字無論是在何種密度屏幕,何種分辨率下,顯示出來的大小都是差不多的。當然,不只是文字,其他元素像圖片什麼的也是這個道理。這個視口被稱爲理想視口(ideal viewport),這個尺寸是廠商確定的。
只有當網站是爲手機準備的時候才應該使用理想視口。只有主動地往頁面裏添加meta視口標籤時理想視口才會生效。如果沒有meta視口標籤聲明,那麼佈局視口將會維持它的默認寬度,理想視口只有當顯式地使用它的時候纔會產生影響:

/這一行代碼告訴瀏覽器,佈局視口的寬度應該與理想視口的寬度一致
<meta name="viewport" content="width=device-width">

3.4 測試三種視口

在head標籤中加入<meta name="viewport" content="width=device-width">,使佈局視口寬度等於理想視口寬度,加入下面js代碼進行測試。

    var ratio = window.devicePixelRatio;
    var layoutWidth = document.documentElement.clientWidth;
    var visualWidth = window.innerWidth;
    window.alert('devicePixelRatio: ' + ratio + ' || layout viewport: ' + layoutWidth + ' || visual viewport: ' + visualWidth);

PC端:
這裏寫圖片描述
手機:
這裏寫圖片描述

4 使用meta標籤控制viewport實現響應式設計

移動設備默認的viewport是layout viewport,也就是那個比屏幕要寬的viewport,但在進行移動設備網站的開發時,我們需要的是ideal viewport。那麼怎麼才能得到ideal viewport呢?這就該輪到meta標籤出場了。

4.1 設置meta標籤

我們在開發移動設備的網站時,最常見的的一個動作就是把下面這個東西複製到我們的head標籤中:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">

該meta標籤的作用是讓當前viewport的寬度等於設備的寬度,同時不允許用戶手動縮放。meta標籤中共有6個關鍵字:

  • width:可以用width來設置viewport的寬度,以替代那些不合適的默認寬度。我們可以給其設定一個固定大小,但設定成device-width更加明智一些,這樣我們可以兼容不同大小的屏幕。
  • height:同width
  • initial-scale:控制默認的縮放比例,縮放是相對於ideal viewport來縮放的
  • minimum-scale:這個是用戶可以縮放頁面的最大比例
  • maximum-scale:這個是用戶可以縮放頁面的最小比例
  • user-scalable:如果設置了user-scalable=no,用戶將無法對頁面進行縮放

瞭解這些以後,我們在測試例子中的head標籤中加入viewport,使理想視口寬度等於佈局視口寬度:

<meta name="viewport" content="width=device-width">

PC端網頁效果不變,手機端訪問效果:
這裏寫圖片描述
這是我們想要的效果了。

4.2 動態改變meta標籤

第一種方法

可以使用document.write來動態輸出meta viewport標籤,例如:

document.write('<meta name="viewport" content="width=device-width,initial-scale=1">')

第二種方法

通過setAttribute來改變

<meta id="testViewport" name="viewport" content="width = 380">
<script>
var mvp = document.getElementById('testViewport');
mvp.setAttribute('content','width=480');
</script>
發佈了82 篇原創文章 · 獲贊 82 · 訪問量 44萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章