移動端佈局基礎概念指南

前言

這篇文章主要討論了移動端頁面渲染與佈局的一些基本概念例如 viewportcss 像素, 這些內容是瞭解移動端頁面適配的基本前提.javascript

在這篇文章中記錄了這些基本的概念, 由於我並不從事移動端開發, 文章有誤, 歡迎指正.css

移動端渲染表現

爲了簡單起見, 咱們不從概念講起, 咱們先來看看一個固定寬度的元素被放置到移動端瀏覽器中會發生什麼.html

有以下代碼:java

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    .example{
      width: 900px;
      background-color: aqua;
    }
  </style>
</head>
<body>
  <div class="example">
    個人寬度是 900px
  </div>
</body>
</html>

固然桌面瀏覽器渲染效果確定在咱們意料之中啦✨:android

圖片: 1920px下chrome渲染的效果:
批註 2019-07-18 165112.pngweb

而下面展現了圖片展現了幾個移動端瀏覽器渲染的結果:chrome

圖片: 移動端瀏覽器渲染效果:
1563439703821.jpgwindows

這裏咱們簡單的介紹一下圖片中瀏覽器的版本, 這些瀏覽器在後文的截圖中版本都是不會發生變化的.瀏覽器

瀏覽器 版本 平臺
chrome 75 windows10
chrome 75 android9
edge 42 android9
Samsung 9.3 android9

仔細觀察咱們發現:900px 寬的 div 沒有佔滿屏幕, 也就是說屏幕的寬度比 900px 還要大.
那麼屏幕寬度究竟是多大呢, 咱們插入一行代碼來獲取HTML元素的寬度:iphone

<script>
  document.write(`html元素的寬度是${document.documentElement.clientWidth}`);
</script>

不一樣瀏覽器的顯示結果爲:
1563441464510.jpg

他們都輸出了一樣的數據那就是 980 在某種程度上咱們知道了頁面的寬度, 原來頁面是 980px 的寬度因此 900px 的div沒法鋪滿一行.

對於移動瀏覽器它感知到本身的視口的寬度是 980px, 此時它渲染的比例就和一個 橫向分辨率爲 980px 的桌面顯示器渲染的同樣. 只不過移動終端的屏幕是一個小號的顯示器而已.
在沒有更改頁面的設置的狀況下或者說默認的狀況下, 移動終端的瀏覽器會按照 980px 的寬度來渲染頁面, 而後再將頁面縮放到適合屏幕的大小.

不理解不要緊, 咱們使用一張圖來理解這一行爲:
1563443177628.jpg

爲何會有這種行爲?

緣由很簡單, 在移動設備剛剛興起的時候大多數的頁面都是爲桌面設計的在當時一個頁面的內容區域的寬度通常在 980px 之內.

可是移動設備屏幕的分辨率很小, 例如某款手機的屏幕的橫向分辨率是 320px 徹底不足以容納爲桌面設計的頁面.

和如今的狀況相反, 手機廠商得設計一種方式來兼容現有的頁面確保頁面在移動端佈局正常, 因此手機瀏覽器的默認內容區域的寬度被設置爲桌面頁面內容區域的典型值 980px(不一樣設備不一樣,後面有統一方法), 爲了瀏覽效果和桌面一致將內容區域平鋪到屏幕上.

這樣確保了佈局正常且手機屏幕上瀏覽的總體效果和在桌面上的一致, 不過說到底移動端的橫向分辨率只有 320px 天然有些內容看不清楚這個時候怎麼辦呢 -> 雙擊縮放唄🤣.

默認渲染方式致使的問題

回想一下移動端瀏覽器的兩個默認的渲染行爲:

  1. 頁面內容區域大小爲 980px
  2. 將頁面區域按照比例縮放到屏幕的大小

對於響應式設計來講, 這種默認的行爲有些問題. 例如第一種行爲會致使媒體查詢沒沒法使用, 由於移動端頁面寬度固定 980px.

第二種自動縮放的行爲會致使頁面模糊(高分辨率的頁面縮放到低分辨率的終端上), 或者難以辨別內容(高分辨率的終端致使文字過小).

在無額外的配置影響下, 下面的例子中的媒體查詢不會起做用, 由於頁面寬度爲 980px 不會變化:

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    .example {
      width: 900px;
      background-color: aqua;
    }

    @media screen and (max-width:960px) {
      .example {
        background-color: red;
      }
    }
  </style>
</head>

<body>
  <div class="example">
    個人寬度是 900px
  </div>
  <script>
    document.write(`html元素的寬度是${document.documentElement.clientWidth}`);
  </script>
</body>

</html>

因此一個天然的想法就產生了頁面的大小應該和屏幕大小一致纔對啊, 這樣咱們就能夠根據不一樣的屏幕尺寸來定製頁面展現的效果.

初識 viewport 屬性

須要藉助於 meta 標籤來完成, 經過設置 <meta name="viewport" content=""> 來控制頁面的渲染.

在大部分的IDE和文本編輯器中這行代碼被放到了建立HTML文件的模板裏, 因此不少人會以爲眼熟:

<meta name="viewport" content="width=device-width, initial-scale=1.0">

這裏你能夠基本將這行代碼理解爲 "調整視口寬度和設備寬度一致", 更多的討論咱們在隨後的中會提到.

圖片:適應設備寬度後的渲染效果:
1563458168665.jpg

注意:上面圖片中的三個瀏覽器實際上都是有橫向滾動條的, 由於 900px 的 div 寬度超過了視口寬度.

頁面中的內容顯得更加大了一些, 除此之外看起來也沒太大變化嘛. 不過這個手機看起來分辨率挺低的啊 html元素寬度竟然是 412px , 這個年頭的老人機的分辨率都比這個高了吧!

是的 HTML元素寬度確實是 412px , 可是個人手機屏幕的橫向分辨率倒是 1440px, 爲何?

看來咱們又有了一個新的問題, 不過好在下一章中咱們就能夠解開這個謎團了.

css像素與物理像素

css 中的 px 單位也就是咱們常說的 "像素" 和顯示器屏幕這個物理設備上提到的 "像素" 不是同一個東西, 換句話說 "css 中的像素" 不等於 "物理像素", 物理像素是屏幕上實際的像素點, 而 css 像素 是一個虛擬的單位.

這有點違反直覺, 由於在桌面瀏覽器上咱們設置的一個 1px 大小的元素, 他所佔的實際大小也是一個像素.

這由於大部分狀況下桌面操做系統中設定的屏幕分辨率和顯示器的物理分辨率都是一致的, 因此就會形成 "css 中的像素" 和 屏幕上的像素是同一個概念的誤會.

不過證實 "css 中的像素" 不等於 "屏幕像素" 也不難, 例如在 windows 10 中你能夠在 顯示設置->縮放與佈局 中設置系統縮放比例爲 125%. 此時一個橫向分辨率爲 1920 的顯示器去輸出 html 元素的寬度的時候是 1536px.

圖片: 縮放選項:
批註 2019-07-18 222819.png

圖片:chrome和firefox的 HTML 元素的寬度:
1563459939233.png

另外你也能夠簡單的經過 ctrl + 滾輪上/下 來調整瀏覽器的縮放來模擬這種狀況. 不過你始終要記住這無非是使用了多個物理像素來顯示一個 css 像素 而已.

注意: 修改系統縮放比例會致使 window.screen 讀取到的數據也是縮放後的而不是屏幕的原始分辨率.

css 像素與設備像素比

在早期的移動設備中常見的橫向物理分辨率是 320px. 可是在現代的移動設備中的屏幕物理分辨率大部分都超過了 320px, 實際上現現在桌面顯示器還在 1080p 的階段, 移動設備的分辨率大部分都接近 2k 了, 因此這裏會出現一個問題, 移動設備的屏幕過小若是一個css像素等於一個物理像素那麼顯示的東西會擠在一團致使沒法瀏覽. 因此終端廠商會在設備裏面內置了一個 "最佳顯示分辨率" 用於優化顯示.

毫無疑問大部分的終端中這個 "最佳顯示分辨率" 都小於設備的 "物理分辨率" , 由於它們使用多個 "物理像素" 來顯示一個 "css像素".

例如:咱們有一個設備的橫向物理像素數量是 1920, 某個終端製造商設置的內置的最佳顯示值是 960, 那麼咱們就是用一個css像素來對應兩個物理像素, 效果就是把顯示的內容放大了一倍, 那麼這個比值就是 1920 / 960 = 2 ,而這個值就是常說的設備像素比, 在瀏覽器中這個值咱們可使用 windows.devicePixelRatio 來獲取.

我在 windows 10 系統縮放 125% 狀況下和移動端中執行以下代碼:

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .example {
      width: 900px;
      background-color: aqua;
    }

  </style>
</head>

<body>
  <div class="example">
    個人寬度是 900px
  </div>
  <script>
    document.write(`html元素的寬度是${document.documentElement.clientWidth}px`);
    document.write(`<br>`); 
    document.write(`設備像素比是${window.devicePixelRatio}`);
    document.write(`<br>`); 
    document.write(`實際的物理分辨率是 ${screen.width} * ${window.devicePixelRatio} = ${screen.width * window.devicePixelRatio}px`);
  </script>
</body>

</html>

windows 10 輸出結果以下:
1570633377630.png

一個高分辨率的手機會有一個更大的設備像素比, 這樣文字纔可以大才能看的清楚:
1570634979264.jpg

瞭解 viewport

viewport(視口) 的概念很是簡單, 至關於瀏覽器整塊渲染區域, 或者說它等於瀏覽器窗口, viewport 擁有它的寬高.

在一個空白的頁面中存在一個 div 這個 div 被設置了樣式:

div {
    width:30%;
    height:500px;
}

他的寬度被設定了一個相對值, 當窗口寬度發生改變的時候, 他會隨着改變寬度. 那麼這個百分比值相對的是誰呢? 根據規範是相對於父元素, body 的父元素是 htmlhtml 的父元素就是 viewport.

移動端 viewport 模型

移動端的狀況比較複雜一些, 這裏有兩個基本概念 visual viewportlayout viewport.

如今的移動端頁面都是通過適配的, 因此要想找到一個早先的移動頁面來舉例比較困難, 不過請請你試想之前你用手機瀏覽那些沒有作移動端適配的頁面所發生的狀況.

這種狀況就是, "頁面上的內容很是小, 你須要經過雙指放大才能夠看清頁面上的細節, 此時的頁面每每會有橫向滾動條", 例以下方這張中國銀行電腦版在移動端的截圖:
1570962455438.png

這種行爲就好像透過望遠鏡觀察星空同樣, 星空的大小是固定的, 可是咱們能夠透過望遠鏡選擇放大來觀察局部的細節仍是縮小來觀察總體.

上面的例子中 "星空" 就是咱們的頁面, 而望遠鏡就是咱們的手機屏幕, 星空表明的就是 layout viewport 也就是咱們的頁面, 而望遠鏡表明的就是 visual viewport 也就是咱們的頁面的可視區域.

星空有固定的大小, 那麼 layout viewport 固定的大小是多少, 這個取決於瀏覽器, 不過如今常見的大小是 980px, 這個值你能夠在本文稍早的移動端截圖中找到.

你在頁面上設置的 css 像素 都會做用在 layout viewport 上, 而不是 visual viewport 上.

度量 layout viewport

layout viewport 能夠經過 document.body.clientWidth/Height 來進行獲取, 本質上咱們沒法直接獲取 layout viewport 的大小, 可是在默認狀況下 HTML 元素的大小就是 layout viewport 的大小, 由於塊級元素繼承了 viewport 的 100% 的寬度.

就像以前提到的同樣 layout viewport 的值在未經設置的狀況下是固定的. 不管設備是豎屏仍是橫屏這個寬度都是 980px(默認狀況下).

圖片: 豎屏效果:
1570963629053.png

圖片: 橫屏效果:
1570963659633.png

能夠看到 document.body.clientWidth/Height 的值(圖片標紅的位置) 並未發生變化.

度量 visual viewport

visual viewport 能夠經過 window.innerWidth/Height 來進行衡量. 這個屬性會以 css 像素 做爲單位返回值, 告訴你頁面中還有多少空間能夠用於佈局, 很顯然當頁面放大這個值會減小, 頁面縮小這個值會變大.

一個更加明顯的例子就是, 當移動端鍵盤彈起的時候 visual viewport 會發生改變, 而 layout viewport 是不會變化的, 經過這個差別咱們能夠判斷鍵盤是否彈出.

注意: window.innerWidth/Height 這個值會包含滾動條的大小.

VisualViewport 對象

注意: 這裏介紹的 VisualViewport 仍是一項實驗中功能.

Visual Viewport APIVisualViewport 接口表明了給定窗口的 visual viewport.

這個對象接口是一個全局屬性, 它提供了兩個事件:

  • resizevisual viewport 大小改變的時候觸發
  • scrollvisual viewport 滾動的時候觸發

使用示例:

window.visualViewport.addEventListener('resize', resizeHandler);

另外他還提供了一些有用的屬性, 這些屬性都是隻讀的:

使用 <meta name="viewport">

<meta name="viewport"> 屬性在乎義在於控制 layout viewport 的寬度(由於 web 開發不關心高度). 你能夠爲其指定 css 像素 來獲取一個固定的寬度.

可是在大部分狀況下咱們但願 layout viewport 是跟隨設備的大小而改變的, 下面咱們經過修改其 width 屬性來控制它的大小:

示例1, 設置爲 500px:

<meta name="viewport"  content="width=500px">

示例2, 等於屏幕的物理像素:

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

注意: 就像我以前在 css 像素與物理像素 這節提到的, 這個屬性最終獲得的值並不會是實際的物理像素, 而是由設備廠商提供的一個建議值.

除了能夠指定 width 咱們還能夠指定其餘的屬性, 這些屬性經過逗號隔開, 例如使用 user-scalable=no 來禁止用戶縮放頁面, 使頁面看起來像原生應用:

<meta name="viewport"  content="width=device-width, user-scalable=no">

下方的表格中提供了 viewport 的幾個可選屬性:

屬性 描述
width 設置layout viewport 的寬度,爲一個正整數,或字符串"width-device"
initial-scale 設置頁面的初始縮放值,爲一個數字,能夠帶小數
minimum-scale 容許用戶的最小縮放值,爲一個數字,能夠帶小數
maximum-scale 容許用戶的最大縮放值,爲一個數字,能夠帶小數
height 設置layout viewport 的高度,這個屬性對咱們並不重要,不多使用
user-scalable 是否容許用戶進行縮放,值爲"no"或"yes", no 表明不容許,yes表明容許

width=device-width 功能同樣的還有 initial-scale=1, 有時咱們會經常看到這兩個屬性是被同時設置的:

<meta name="viewport" content="width=device-width, initial-scale=1">

經過設置 initial-scale=1 是告訴瀏覽器相對於 ideal viewport (這個概念來自於 Meta viewport 一文, 我把它理解設備廠商內置的最佳顯示分辨率也就是 device-witdh的大小) 進行縮放且縮放一倍, 因此他會和 width=device-width 效果一致.

一樣根據文中所述, 這種寫法是用來解決兼容問題, 由於 IE 不支持 initial-scale=1 而 iphone 和 ipad 不支持 width=device-width.

當這兩個屬性同時使用的時候:

<meta name="viewport" content="width=400, initial-scale=1">

瀏覽器會取它們兩個中較大的那個值, 若是 ideal viewport 是 500px 那麼瀏覽器就會使用 500px, 反之使用 400px.

next step

在後續我會介紹幾種常見的移動端適配方案, 和它們的工做原理, 因爲工做關係可能須要一些時間纔會寫完.

參考

十分建議讀者閱讀下列的幾篇文章, 它們一樣也是本文章的重要參考來源之一, 原文是英文的, 不過已經被他人翻譯完成, 可是因爲原連接已經丟失, 這裏提供轉載的地址, 原文一共有三篇, 這裏按順序給出:

https://www.jianshu.com/p/738...

https://www.jianshu.com/p/692...

https://www.cnblogs.com/yelon...

相關文章
相關標籤/搜索