將 HTML5 網站改為行動版

簡介

開發行動版網站是近期的熱門話題。今年,智慧型手機的銷量首次超越電腦。越來越多使用者透過行動裝置瀏覽網路,因此開發人員必須針對行動瀏覽器最佳化網站。

對許多開發人員來說,「行動」戰場仍是未知領域。 許多人現有的舊版網站完全忽略行動使用者。而是主要針對電腦版瀏覽設計,在行動瀏覽器中的體驗不佳。這個網站 (html5rocks.com) 也不例外。推出時,我們並未花太多心力在行動版網站上。

建立適合行動裝置瀏覽的 html5rocks.com

我認為,將 html5rocks (現有的 HTML5 網站) 擴充為適合行動裝置的版本,會是一項有趣的練習。我主要考量的是,要支援智慧型手機,最少需要做多少工作。我的目標並非建立全新的行動網站,並維護兩個程式碼集。這會耗費大量時間,我們已定義網站的結構 (標記)。我們有外觀和風格 (CSS)。核心功能 (JS) 已經存在。重點是,許多網站都面臨同樣的問題。

本文將探討我們如何建立針對 Android 和 iOS 裝置最佳化的 html5rocks 行動版。只要在支援其中一種 OS 的裝置上載入 html5rocks.com,就能看出差異。不會重新導向至 m.html5rocks.com 或其他類似的愚蠢行為。您會看到 html5rocks 的原貌,而且在行動裝置上看起來更美觀,運作也更順暢。

電腦版 html5rocks.com Mobile html5rocks.com
html5rocks.com 電腦版 (左) 和行動版 (右)

CSS 媒體查詢

HTML4 和 CSS2 支援媒體相關樣式表已有一段時間。例如:

<link rel="stylesheet" media="print" href="printer.css">

會指定列印裝置,並在列印時為網頁內容提供特定樣式。CSS3 進一步延伸媒體類型的概念,並透過媒體查詢強化其功能。 媒體查詢可更精確地標示樣式表,進一步擴充媒體類型的實用性。這樣一來,您就能針對特定範圍的輸出裝置自訂內容呈現方式,而不必變更內容本身。這聽起來很適合用來修改現有版面配置!

您可以在外部樣式表的 media 屬性中使用媒體查詢,指定螢幕寬度、裝置寬度、螢幕方向等。如需完整清單,請參閱 W3C 媒體查詢規格。

指定螢幕大小

在以下範例中,phone.css 會套用至瀏覽器視為「手持」的裝置,或螢幕寬度 <= 320 像素的裝置。

 <link rel='stylesheet'
  media='handheld, only screen and (max-device-width: 320px)' href='phone.css'>

在媒體查詢前面加上「only」關鍵字,會導致不符合 CSS3 規範的瀏覽器忽略規則。

以下程式碼會指定 641px 到 800px 之間的螢幕大小:

 <link rel='stylesheet'
  media='only screen and (min-width: 641px) and (max-width: 800px)' href='ipad.css'>

媒體查詢也可以顯示在內嵌 <style> 標記中。在直向模式下,下列項目會指定 all 媒體類型:

 <style>
  @media only all and (orientation: portrait) { ... }
 </style>

media="handheld"

我們需要暫停一下,討論media="handheld"。 事實上,Android 和 iOS 會忽略 media="handheld"。他們認為,使用者會錯過針對 media="screen" 的樣式表提供的高階內容,而開發人員不太可能維護品質較低的 media="handheld" 版本。因此,為了貫徹「完整網頁」的理念,大多數現代智慧型手機瀏覽器都會直接忽略手持式樣式表。

這項功能很適合用來指定行動裝置,但各種瀏覽器實作這項功能的方式不同:

  • 有些則只讀取手持裝置樣式表。
  • 有些瀏覽器只會讀取手持裝置樣式表 (如果有的話),否則會預設為螢幕樣式表。
  • 有些瀏覽器會同時讀取手持裝置樣式表和螢幕樣式表。
  • 有些則只會讀取螢幕樣式表。

Opera Mini 不會忽略 media="handheld"。如要讓 Windows Mobile 辨識 media="handheld",請將螢幕樣式表的媒體屬性值設為大寫:

 <!-- media="handheld" trick for Windows Mobile -->
 <link rel="stylesheet" href="screen.css" media="Screen">
 <link rel="stylesheet" href="mobile.css" media="handheld">

html5rocks 如何使用媒體查詢

行動版 html5rocks 廣泛使用媒體查詢。我們不必大幅變更 Django 範本標記,就能調整版面配置,真是太方便了!此外,各種瀏覽器對這類格式的支援也相當完善。

在每個網頁的 <head> 中,您會看到下列樣式表:

 <link rel='stylesheet'
  media='all' href='/static/css/base.min.css' />
 <link rel='stylesheet'
  media='only screen and (max-width: 800px)' href='/static/css/mobile.min.css' />

base.css 一直是 html5rocks.com 的主要外觀和風格,但現在我們針對螢幕寬度小於 800 像素的裝置套用新樣式 (mobile.css)。其媒體查詢涵蓋智慧型手機 (~320px) 和 iPad (~768px)。效果:我們在 base.css 中逐步覆寫樣式 (僅在必要時),讓行動裝置上的顯示效果更佳。

mobile.css 強制執行的部分樣式變更:

  • 減少整個網站多餘的空白/邊框間距。小螢幕意味著空間有限!
  • 移除 :hover 狀態。觸控裝置上不會顯示這類廣告。
  • 將版面配置調整為單欄。這部分稍後會再進一步說明。
  • 移除網站主要容器 div 周圍的 box-shadow。大型方塊陰影會降低網頁效能。
  • 使用 CSS 彈性方塊模型 box-ordinal-group 變更首頁各個部分的順序。您會發現「LEARN BY MAJOR HTML5 FEATURE GROUPS」在首頁上位於「TUTORIALS」部分之前,但在行動版上則位於其後。這種排序方式更適合行動裝置,且不需要變更標記。 CSS flexbox FTW!
  • 移除 opacity 項變更。變更 Alpha 值會影響行動裝置的效能。

行動版中繼標記

行動 WebKit 支援一些實用功能,可讓使用者在特定裝置上享有更優質的瀏覽體驗。

可視區域設定

第一個中繼設定 (也是最常使用的設定) 是可視區域屬性。設定可視區域可讓瀏覽器知道內容應如何配合裝置螢幕大小,以及網站已針對行動裝置進行最佳化。例如:

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

指示瀏覽器將可視區域設為裝置寬度,初始比例為 1。這個範例也允許縮放,這可能適合網站,但不適合網頁應用程式。我們可以使用 user-scalable=no 避免縮放,或將縮放比例限制在特定等級:

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

Android 擴充了可視區域中繼標記,讓開發人員指定網站開發時所用的螢幕解析度:

 <meta name="viewport" content="target-densitydpi=device-dpi">

target-densitydpi 的可能值為 device-dpi、high-dpi、medium-dpi、low-dpi。

如要針對不同的螢幕密度修改網頁,請使用 -webkit-device-pixel-ratio CSS 媒體查詢和/或 JavaScript 中的 window.devicePixelRatio 屬性,然後將 target-densitydpi 中繼屬性設為 device-dpi。這樣一來,Android 就不會在網頁中執行縮放,您也可以透過 CSS 和 JavaScript,針對每個密度進行必要調整。

如要進一步瞭解如何指定裝置解析度,請參閱 Android 的 WebView 說明文件。

全螢幕瀏覽

另外兩個中繼值為 iOS-sfic。apple-mobile-web-app-capable 和 apple-mobile-web-app-status-bar-style 會以類似應用程式的全螢幕模式轉譯網頁內容,並將狀態列設為半透明:

 <meta name="apple-mobile-web-app-capable" content="yes">
 <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">

如要進一步瞭解所有可用的中繼選項,請參閱 Safari 參考文件。

主畫面圖示

iOS 和 Android 裝置也接受連結的 rel="apple-touch-icon" (iOS) 和 rel="apple-touch-icon-precomposed" (Android)。當使用者將您的網站加入書籤時,這些標記會在主畫面上建立醒目的應用程式圖示:

 <link rel="apple-touch-icon"
      href="/static/images/identity/HTML5_Badge_64.png" />
 <link rel="apple-touch-icon-precomposed"
      href="/static/images/identity/HTML5_Badge_64.png" />

html5rocks 如何使用行動中繼標記

總而言之,以下是 html5rocks 的 <head> 區段程式碼片段:

 <head>
  ...
   <meta name="viewport"
        content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />

   <link rel="apple-touch-icon"
        href="/static/images/identity/HTML5_Badge_64.png" />
   <link rel="apple-touch-icon-precomposed"
        href="/static/images/identity/HTML5_Badge_64.png" />
  ...
 </head>

直式版面配置

在較小的螢幕上,垂直捲動比水平捲動更方便。在行動裝置上,建議將內容放在單欄直向版面配置中。 在 html5rocks 中,我們使用 CSS3 媒體查詢來建立這類版面配置。同樣地,不必變更標記。

教學課程索引。 教學課程。 HTML5 功能頁面。 作者個人資料頁面。
整個網站採用單欄垂直版面配置。

行動裝置最佳化

我們進行的大多數最佳化作業,都是一開始就應該完成的工作。例如減少網路要求數量、JS/CSS 壓縮、gzip 壓縮 (App Engine 免費提供),以及盡量減少 DOM 操作。這些技術是常見的最佳做法,但有時在急著推出網站時會遭到忽略。

自動隱藏網址列

行動瀏覽器的螢幕空間不如電腦版。 更糟的是,在不同平台上,有時即使網頁載入完成,螢幕頂端仍會顯示一個大大的網址列。

其中一個簡單的處理方式,就是使用 JavaScript 捲動頁面。即使只移動一個像素,也能解決惱人的網址列問題。 為了強制隱藏 html5rocks 上的網址列,我將 onload 事件處理常式附加到 window 物件,並將頁面垂直捲動一個像素:

網址列。
網址列不美觀,且會占用螢幕空間。
  // Hides mobile browser's address bar when page is done loading.
  window.addEventListener('load', function(e) {
    setTimeout(function() { window.scrollTo(0, 1); }, 1);
  }, false);

我們也將這個事件監聽器包裝在 is_mobile 範本變數中,因為電腦版不需要這個事件監聽器。

減少網路要求,節省頻寬

眾所周知,減少 HTTP 要求數量可大幅提升成效。行動裝置會進一步限制瀏覽器可建立的並行連線數量,因此減少這些不必要的要求,對行動網站更有幫助。此外,由於手機的頻寬通常有限,因此必須盡可能減少每個位元組。這可能會讓使用者花費不必要的費用!

以下是我們在 html5rocks 上採取的幾種方法,可盡量減少網路要求和頻寬:

  • 移除 iframe - iframe 速度緩慢!我們的大部分延遲來自教學頁面上的第三方分享小工具 (Buzz、Google Friend Connect、Twitter、Facebook)。這些 API 是透過 <script> 標記加入,並會建立 iframe,降低網頁速度。行動版已移除小工具。

  • display:none - 在某些情況下,如果標記不符合行動裝置設定檔,我們會隱藏標記。首頁頂端的四個圓角方塊就是很好的例子:

首頁上的方塊按鈕。
首頁上的方塊按鈕。

行動版網站缺少這些資訊。請注意,即使容器已透過 display:none 隱藏,瀏覽器仍會要求每個圖示。因此,光是隱藏這些按鈕是不夠的。這不僅會浪費頻寬,使用者甚至不會看到浪費頻寬的成果!解決方法是在 Django 範本中建立「is_mobile」布林值,有條件地省略部分 HTML。如果使用者在智慧型裝置上瀏覽網站,系統會略過按鈕。

  • 應用程式快取:不僅提供離線支援,還能加快啟動速度。

  • CSS/JS 壓縮:我們使用 YUI 壓縮器,而非 Closure 編譯器,主要是因為 YUI 壓縮器可同時處理 CSS 和 JS。我們遇到的其中一個問題是,內嵌媒體查詢 (出現在樣式表中的媒體查詢) 在 YUI 壓縮器 2.4.2 中發生錯誤 (請參閱這個問題)。使用 YUI Compressor 2.4.4 以上版本即可解決問題。

  • 盡可能使用 CSS 合併圖片。

  • 使用 pngcrush 壓縮圖片。

  • 針對小型圖片使用 dataURI。Base64 編碼會使圖片大小增加約 30%以上,但可節省網路要求。

  • 使用單一指令碼標記自動載入 Google 自訂搜尋,而非使用 google.load() 動態載入。後者會提出額外要求。

<script src="//www.google.com/jsapi?autoload={"modules":[{"name":"search","version":"1"}]}"> </script>
  • 我們的程式碼美化排版工具和 Modernizr 包含在每個頁面中,即使從未使用過也是如此。Modernizr 雖然好用,但每次載入時都會執行大量測試。部分測試會對 DOM 進行耗費資源的修改,導致網頁載入速度變慢。現在,我們只在實際需要這些程式庫的網頁上加入這些程式庫。-2 requests :)

其他效能調整:

  • 將所有 JS 移至頁面底部 (如果可行)。
  • 移除內嵌 <style> 標記。
  • 快取 DOM 查詢和最小化 DOM 操作:每次觸控 DOM 時,瀏覽器都會執行重排。在行動裝置上,重排版面的成本更高。
  • 將浪費資源的用戶端程式碼卸載至伺服器。具體來說,檢查目前頁面的導覽樣式設定: js var lis = document.querySelectorAll('header nav li'); var i = lis.length; while (i--) { var a = lis[i].querySelector('a'); var section = a.getAttribute("data-section"); if (new RegExp(section).test(document.location.href)) { a.className = 'current'; } }
  • 固定寬度的元素已替換為流動式 width:100% 或 width:auto。

應用程式快取

行動版 html5rocks 使用應用程式快取加快初始載入速度,並允許使用者離線閱讀內容。

在網站上導入 AppCache 時,請務必不要快取資訊清單檔案 (無論是在資訊清單檔案本身中明確快取,還是透過大量快取控制標頭隱含快取)。如果資訊清單遭到瀏覽器快取,偵錯就會變得非常困難。iOS 和 Android 在快取這個檔案方面做得特別好,但並未提供像電腦版瀏覽器那樣方便清除快取的方法。

為避免網站快取,我們首先將 App Engine 設為一律不快取資訊清單檔案:

- url: /(.*\.(appcache|manifest))
  static_files: \1
  mime_type: text/cache-manifest
  upload: (.*\.(appcache|manifest))
  expiration: "0s"

第二,我們使用 JS API,在新的資訊清單下載完成時通知使用者。系統會提示他們重新整理頁面:

window.applicationCache.addEventListener('updateready', function(e) {
  if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
    window.applicationCache.swapCache();
    if (confirm('A new version of this site is available. Load it?')) {
      window.location.reload();
    }
  }
}, false);

為節省網路流量,請保持資訊清單簡單。也就是說,請勿列出網站上的所有網頁。只要列出重要的圖片、CSS 和 JavaScript 檔案即可。您最不希望發生的情況,就是每次更新 appcache 時,行動瀏覽器都必須下載大量素材資源。請注意,當使用者造訪網頁時,瀏覽器會隱含快取 HTML 網頁 (且包含 <html manifest="..."> 屬性)。