博客 / 詳情

返回

移動端自適應的常見手段

完整高頻題庫倉庫地址:https://github.com/hzfe/awesome-interview

完整高頻題庫閲讀地址:https://febook.hzfe.org/

相關問題

  • 介紹 meta 的 viewport 值
  • rem 和 vw 的值是根據什麼計算的
  • 1px 顯示問題
  • 如何適配劉海屏

回答關鍵點

viewport 相對單位 媒體查詢 響應式圖片

移動端開發的主要痛點是如何讓頁面適配各種不同的終端設備,使不同的終端設備都擁有基本一致的視覺效果和交互體驗。移動端常見的適配方案有以下幾種,一般都是互相搭配使用。包括:

  • 視口元信息配置
  • 響應式佈局
  • 相對單位
  • 媒體查詢
  • 響應式圖片
  • 安全區域適配

知識點深入

1. 相關概念

1.1 像素

image

分辨率(Resolution)

分辨率是指位圖圖像中細節的精細程度,以每英寸像素(ppi)衡量。每英寸的像素越多,分辨率就越高。

物理像素(Physical pixels)

物理像素是一個設備的實際像素數。

邏輯像素(Logical pixels)

是一種抽象概念。在不同的設備下,一個邏輯像素代表的物理像素數不同。CSS 像素是邏輯像素。

為了在不同尺寸和密度比的設備上表現出一致的視覺效果,使用邏輯像素描述一個相同尺寸的物理單位。在具有高密度比的屏幕下,一個邏輯像素對應多個物理像素。

設備像素比(Device Pixel Ratio)

當前顯示設備的物理像素分辨率與 CSS 像素分辨率之比。

相關問題:圖片或 1px 邊框顯示模糊

在移動端中,常見圖片或者 1px 的邊框在一些機型下顯示模糊/變粗的問題。基於對像素相關的概念理解,可知 CSS 中的 1px 是指一個單位的邏輯像素。一個單位的邏輯像素映射到不同像素密度比的設備下,實際對應的物理像素不同。

因此,同樣尺寸的圖片在高密度比的設備下,由於一個位圖像素需要應用到多個物理像素上,所以會比低密度比設備中的視覺效果模糊。

1.2 視口

image

視口(viewport)

視口一般是指用户訪問頁面時,當前的可視區域範圍。通過滾動條滑動,視口可以顯示頁面的其他部分。在 PC 端上,<html> 元素的寬度被設置為 100% 時,等同於視口大小,等同於瀏覽器的窗口大小。通過 document.documentElement.clientWidthwindow.innerWidth 可以獲取視口寬度。CSS 佈局基於視口大小進行計算。

由於移動設備尺寸較小,如果基於瀏覽器窗口大小的視口進行佈局,會導致一些沒有適配過移動設備樣式的站點佈局錯亂,用户體驗差。為了讓移動端也能正常顯示未適配移動設備的頁面,從而引入佈局視口和視覺視口的概念。

佈局視口(layout viewport)

佈局視口的寬度默認為 980px,通常比物理屏幕寬。CSS 佈局會基於佈局視口進行計算。移動設備的瀏覽器基於虛擬的佈局視口去渲染網頁,並將對應的渲染結果縮小以便適應設備實際寬度,從而可以完整的展示站點內容且不破壞佈局結構。

視覺視口(visual viewport)

視覺視口是佈局視口的當前可見部分。用户可以通過縮放來查看頁面內容,從而改變視覺視口,但不影響佈局視口。

2. 使用 viewport 元標籤配置視口

開發者可以通過 <meta name="viewport"> 對移動端的佈局視口進行設置。如果不進行 viewport 元標籤的設置,可能會導致開發者設定的較小寬度的媒體查詢永遠不會被使用,因為默認的佈局視口寬度為 980px。

<!-- width 屬性控制視口的大小。device-width 值指代設備屏幕寬度。 -->
<!-- initial-scale 屬性控制頁面首次加載時的縮放級別。-->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

3. 使用現代響應式佈局方案

除了使用浮動佈局和百分比佈局外,目前比較常見的是使用 Flexbox 或 CSS Grid 來實現靈活的網格佈局。可以根據以下條件來選擇佈局方案:

  1. 需要一維還是二維佈局:Flexbox 基於一條主軸方向進行佈局。CSS Grid 可劃分為行和列進行佈局。如果只需要按照行或列進行佈局則使用 Flexbox;如果需要同時按照行和列控制佈局則使用 CSS Grid。
  2. 專注佈局結構還是內容流:Flexbox 專注於內容流。Flex Item 的寬度或高度由項目中的內容決定。Flex Item 根據其內部內容和可用空間進行增長和縮小。CSS Grid 專注於精確的內容佈局結構規則。每個 Grid Item 都是一個網格單元,沿水平軸和垂直軸排列。如果允許內容靈活的分配空間則使用 Flexbox;如果需要準確控制佈局中項目的位置則使用 CSS Grid。

image

4. 使用媒體查詢(Media Queries)

媒體查詢允許開發者根據設備類型和特徵(如屏幕分辨率或瀏覽器視口寬度)來按需設置樣式。

/* 當瀏覽器寬度至少在 600px 及以上時 */
@media screen and (min-width: 600px) {
  .hzfe {
    /* 對 .hzfe 應用某些樣式  */
  }
}

/* 當設備 DPR 為2時的樣式 */
@media screen and (-webkit-min-device-pixel-ratio: 2) {
  .border-1 {
    border-width: 0.5px;
  }
}

5. 使用相對單位

移動端開發需要面對十分繁雜的終端設備尺寸。除了使用響應式佈局、媒體查詢等方案之外,在對元素進行佈局時,一般會使用相對單位來獲得更多的靈活性。

rem

根據 W3C 規範可知,1rem 等同於根元素 html 的 font-size 大小。

由於早期 vw、vh 兼容性不佳,一個使用廣泛的移動端適配方案 flexible 是藉助 rem 來模擬 vw 特性實現移動端適配。在設計與開發時,通常會約定某一種尺寸為開發基準。開發者可以利用工具(如 px2rem)進行絕對單位 px 和其他 rem 單位的自動換算,然後利用 flexible 腳本動態設置 html 的字體大小和<meta name="viewport">

vw/vh

由於目前 vw、vh 相關單位獲得了更多瀏覽器的支持,可以直接使用 vw、vh 單位進行移動端開發。

同理於 flexible 方案,使用 vw、vh 也需要對設計稿中的尺寸進行換算,將 px 轉換為 vw 值,常見的工具如 postcss-px-to-viewport 等可以滿足需求。

image

6. 使用響應式圖片

展示圖片時,可以在 picture 元素中定義零或多個 source 元素和一個 img 元素,以便為不同的顯示/設備場景提供圖像的替代版本。從而使得圖片內容能夠靈活響應不同的設備,避免出現圖片模糊或視覺效果差以及使用過大圖片浪費帶寬的問題。

source 元素可以按需配置 srcset、media、sizes 等屬性,以便用户代理為不同媒體查詢範圍或像素密度比的設備配置對應的圖片資源。如果沒有找到匹配的圖像或瀏覽器不支持 picture 元素,則使用 img 元素作為回退方案。

<picture>
  <source
    srcset="hzfe-avatar-desktop.png, hzfe-avatar-desktop-2x.png 2x"
    media="(min-width: 990px)"
  />
  <source
    srcset="hzfe-avatar-tablet.png, hzfe-avatar-tablet-2x.png 2x"
    media="(min-width: 750px)"
  />
  <source
    srcset="hzfe-avatar-mobile.png, hzfe-avatar-mobile-2x.png 2x"
    media="(min-width: 375px)"
  />
  <img
    srcset="hzfe-avatar.png, hzfe-avatar-2x.png 2x"
    src="hzfe-avatar.png"
    alt="hzfe-default-avatar"
  />
</picture>

7. 適配安全區域

由於手機廠商各有特色,目前手機上常見有圓角(corners)、劉海(sensor housing)和小黑條(Home Indicator)等特徵。為保證頁面的顯示效果不被這些特徵遮蓋,需要把頁面限制在安全區域範圍內。

<meta name="viewport" content="initial-scale=1, viewport-fit=cover" />

設置 viewport-fit=cover 後,按需藉助以下預設的環境變量,對元素應用 padding,從而確保它們不會被一些以上特徵遮蓋:

  • safe-area-inset-left
  • safe-area-inset-right
  • safe-area-inset-top
  • safe-area-inset-bottom
/* 例子:兼容劉海屏 */
body {
  /* constant 函數兼容 iOS 11.2 以下*/
  padding-top: constant(safe-area-inset-top);
  /* env 函數兼容 iOS 11.2 */
  padding-top: env(safe-area-inset-top);
}

參考資料

  1. iOSRes
  2. Viewport concepts
  3. A tale of two viewports
  4. Responsive Design
  5. Relationship of grid layout to other layout methods
  6. Designing Websites for iPhone X
user avatar sunhengzhe 頭像 susouth 頭像 suporka 頭像 waweb 頭像 79px 頭像 lidalei 頭像 mapvthree 頭像 warn 頭像 cipchk 頭像 beilee 頭像 william_wang_5f4c69a02c77b 頭像 tofrankie 頭像
42 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.