像素完美的 WebView

發布日期:2014 年 2 月 28 日

您可以使用多種選項,為 WebView 建立完美的介面。

設定可視區域中繼標記

可視區域中繼標記是新增至網頁應用程式時最重要的標記。如果沒有這項標記,WebView 可能會假設您的網站是為桌面瀏覽器設計。這會讓網頁獲得較大的寬度 (通常為 980 像素),並縮放至符合 WebView 寬度。在大多數情況下,這會導致網頁的概覽版本過小,使用者必須捲動和縮放才能實際閱讀內容。

如果您希望網站的寬度為 WebView 寬度的 100%,請設定可視區域中繼標記:

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

將寬度設為特殊值 device-width,進一步控管頁面版面配置。

根據預設,WebView 會將可視區域設為 device-width,而非預設為電腦可視區域。不過,為了確保可靠且受控的行為,建議您加入 viewport 中繼標記。

顯示電腦版網站

在某些情況下,您可能需要顯示非行動裝置專用的內容。例如,您可能會顯示您無法控管的內容。在這種情況下,您可以強制 WebView 使用電腦大小的可視區域:

如果未設定這些方法且未指定可視區域,WebView 會嘗試根據內容大小設定可視區域寬度。

此外,您可能需要使用版面配置演算法 TEXT_AUTOSIZING,該演算法可增加字型大小,讓使用者在行動裝置上更容易閱讀。請參閱 setLayoutAlgorithm

採用回應式設計

回應式設計是一種設計介面的方法,可根據螢幕大小變更介面。

實作回應式設計的方法有很多種,最常見的一種是 @media 查詢,可根據裝置特性,將 CSS 套用至元素。

舉例來說,假設您想根據方向從垂直版面配置切換為水平版面配置。將 CSS 屬性設為預設為直向:

.page-container {
    display: -webkit-box;
    display: flex;

    -webkit-box-orient: vertical;
    flex-direction: column;

    padding: 20px;
    box-sizing: border-box;
}

如要切換為水平版面配置,請根據方向切換 flex-direction 屬性:

@media screen and (orientation: landscape) {
  .page-container.notification-opened {
    -webkit-box-orient: horizontal;
    flex-direction: row;
  }

  .page-container.notification-opened > .notification-arrow {
    margin-right: 20px;
  }
}

您也可以根據螢幕寬度變更版面配置。

例如,隨著實體螢幕尺寸變大,將按鈕寬度從 100% 調整為較小的尺寸。

button {
  display: block;
  width: 100%;
  ...
}

@media screen and (min-width: 500px) {
  button {
    width: 60%;
  }
}

@media screen and (min-width: 750px) {
  button {
    width: 40%;
    max-width: 400px;
  }
}

這些都是次要變更,但視 UI 而定,媒體查詢可協助您大幅變更應用程式的外觀,同時保留相同的 HTML。

清晰的圖片

螢幕尺寸和密度的多樣性也為圖片帶來挑戰。較小的圖片需要較少記憶體,且載入速度較快,但如果放大圖片,圖片會變得模糊。

以下提供幾個訣竅,讓您在任何螢幕上都能確保圖片清晰銳利:

  • 使用 CSS 製作可調整大小的效果。
  • 使用向量圖形。
  • 提供高解析度相片。

使用 CSS 實現可擴充的效果

請盡可能使用 CSS,而非圖片。某些 CSS 屬性組合可能需要大量資源才能算繪。請務必測試您使用的特定組合。

進一步瞭解首次顯示內容所需時間 (FCP),這是指從使用者首次前往網頁到畫面顯示網頁任何部分內容所需的時間。「內容」是指文字、圖片 (包括背景圖片)、<svg> 元素和非白色 <canvas> 元素。

使用向量圖形

可縮放向量圖形 (SVG) 是提供可縮放圖片的絕佳方式。對於適合向量圖形的圖片,SVG 可提供高品質圖片,且檔案大小非常小。

提供高解析度相片

使用適合高 DPI 裝置的相片,並使用 CSS 縮放圖片。這樣一來,圖片就能在各裝置上以高畫質顯示。如果在產生圖片時使用高壓縮 (低品質設定),您可能可以獲得良好的視覺效果,且檔案大小合理。

這種做法有幾個潛在的缺點:高度壓縮的圖片可能會出現一些視覺瑕疵,因此您需要進行實驗,判斷可接受的壓縮程度。而且在 CSS 中調整圖片大小可能會耗費大量資源。

如果高壓縮率不符合您的需求,請嘗試使用 WebP 格式,這種格式可提供高畫質圖片,且檔案大小相對較小。請記得為不支援 WebP 的 Android 版本提供備用方案。

精細的控管機制

在許多情況下,您無法為所有裝置使用單一圖片。在這種情況下,您可以根據螢幕大小和密度選取不同的圖片。使用媒體查詢,根據螢幕尺寸和密度選取背景圖片。

您可以使用 JavaScript 控制圖片的載入方式,但這會增加複雜度。

媒體查詢和螢幕密度

如要根據螢幕密度選取圖片,您必須在媒體查詢中使用 dpidppx 單位。dpi 單位代表每 CSS 英寸的點,dppx 則代表每 CSS 像素的點。

下表顯示 dpidppx 之間的關係。

裝置像素比例 一般螢幕密度 每 CSS 英寸的點數 (dpi) 每個 CSS 像素的點數 (dppx)
1x MDPI 96dpi 1dppx
1.5 倍 HDPI 144dpi 1.5dppx
2 XHDPI 192dpi 2dppx

一般螢幕密度值區間是由 Android 定義,並用於其他位置表示螢幕密度 (例如 https://screensiz.es)。

背景圖片

您可以使用媒體查詢將背景圖片指派給元素。舉例來說,如果您在像素比例為 1.0 的裝置上使用 256 x 256 像素的標誌圖片,可以使用下列 CSS 規則:

.welcome-header > h1 {
  flex: 1;

  width: 100%;

  max-height: 256px;
  max-width: 256px;

  background-image: url('../images/html5_256x256.png');
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}

如要在裝置像素比例為 1.5 (HDPI) 和 2.0 (XHDPI) 的裝置上,將此圖片換成較大的圖片,您可以新增下列規則:

@media screen and (min-resolution: 1.5dppx) {
  .welcome-header > h1{
    background-image: url('../images/html5_384x384.png');
  }
}

@media screen and (min-resolution: 2dppx) {
  .welcome-header > h1{
    background-image: url('../images/html5_512x512.png');
  }
}

接著,您可以將這項技巧與其他媒體查詢 (例如 min-width) 合併,這在考量不同板型規格時相當實用。

@media screen and (min-resolution: 2dppx) {
  .welcome-header > h1{
    background-image: url('../images/html5_512x512.png');
  }
}

@media screen and (min-resolution: 2dppx) and (min-width: 1000px) {
  .welcome-header > h1{
    background-image: url('../images/html5_1024x1024.png');

    max-height: 512px;
    max-width: 512px;
  }
}

您可能會發現,max-heightmax-width 會將 2ddpx 解析度的解析度設為 512 像素,而圖片解析度為 1024x1024 像素。這是因為 CSS 的「像素」實際上會考量裝置像素比率 (512 像素 * 2 = 1024 像素)。

<img/> 呢?

目前的網頁並沒有解決方案。我們有提出一些建議,但目前的瀏覽器或 WebView 尚未支援。

同時,如果您在 JavaScript 中產生 DOM,可以在精心設計的目錄結構中建立多個圖片資源:

images/
  mdpi/
    imagename.png
  hdpi/
    imagename.png
  xhdpi/
    imagename.png

接著,使用像素比例嘗試擷取最合適的圖片:

function getDensityDirectoryName() {
  if(!window.devicePixelRatio) {
    return 'mdpi';
  }

  if(window.devicePixelRatio > 1.5) {
    return 'xhdpi';
  } else if(window.devicePixelRatio > 1.0) {
    return 'hdpi';
  }

  return 'mdpi';
}

或者,您也可以變更頁面的基礎網址,藉此定義圖片的相對網址。

<!doctype html>
<html class="no-js">
<head>
  <script>
    function getDensityDirectoryName() {
      if(!window.devicePixelRatio) {
          return 'mdpi';
      }

      if(window.devicePixelRatio > 1.5) {
          return 'xhdpi';
      } else if(window.devicePixelRatio > 1.0) {
          return 'hdpi';
      }

      return 'mdpi';
    }

    var baseUrl =
        'file:///android_asset/www/img-js-diff/ratiores/'+getDensityDirectoryName()+'/';
    document.write('<base href="'+baseUrl+'">');
  </script>

    ...
</head>
<body>
    ...
</body>
</html>

這個方法會阻止網頁載入,並強制所有資源 (例如圖片、指令碼和 CSS 檔案) 使用絕對路徑,因為基本網址會指向密度專屬目錄。