在你的 Rails App 實作 AMP
AMP 是 Google 在 2016 年 2 月所推出的加速行動網頁(Accelerate Mobile Pages)開源專案,能讓靜態內容網頁快速呈現。
根據 What is AMP,AMP 在運作上由三個部分組成:
- AMP HTML:基本 HTML 配合 AMP 的規則與屬性,以符合效能的需求。
- AMP JS:使用 AMP JS 函式庫來確保 AMP HTML 頁面可以快速呈現。
- AMP Cache:Google AMP Cache 用來提供快取好的 AMP HTML 網頁。
HTML 和 JS?這不是網頁初學者也能上手的東西嗎?!可是進一步參考 AMP HTML Specification 會發現所謂「受限的基本 HTML」必須滿足以下條件:
- 只接受 inlined style,不接受透過
<link rel=”stylesheet”>
形式讀取的 CSS 檔案 - 不能使用自定義或第三方的 Javascript
img
標籤必須替換成amp-img
並預先定義圖片的width
與height
- 部分標籤如
iframe
,embed
或object
必須替換成 AMP 定義的格式或被禁止使用 - ……(更多請參考 AMP 官方文件)
因此,導入 AMP 的大多是以內容為主的新聞或部落格網站,減少對 UI 的要求以提升使用者的閱讀體驗。儘管我們可以建立一個全面支援 AMP 的網站,但這可能會大大限制 UI 設計的發展且必須耗費更多時間來開發。
假設你有個 Rails 專案,除了主要頁面之外,也有定期會發表文章的內容頁面,我們可以選擇性地為你的專案快速導入 AMP。
AMP HTML
註:本篇 HTML 範例以 Slim 語法為主
建立 AMP Templete
這邊的做法是保有原本的頁面,並另外設計該頁面的 AMP 版本。
首先,我們需要建立符合 AMP 規範的 HTML:
- 複製
app/views/layouts/application.html.slim
並重新命名為application.amp.slim
- 調整
application.amp.slim
以符合 AMP HTML Specification #Required markup - 同樣複製你想要導入 AMP 的頁面(e.g.
app/views/blogs/show.amp.erb
)並改為.amp.erb
為了讓 Google Search 在找到非 AMP 頁面時能知道該頁面有 AMP 版本,我們需要特別設定 link
標籤:
- 在
app/views/layouts/application.html.slim
的head
中加上
link href="#{url_for}" rel="amphtml" /
- 在
app/views/layouts/application.amp.slim
的head
中加上
link href="#{url_for}" rel="canonical" /
設定 Controller
在導入 AMP 頁面所屬的 controller 底下加上:
respond_to do |format|
format.html
format.amp
end
設定 mime_types.rb
在 config/initializers/mime_types.rb
中加上
Mime::Type.register_alias "text/html", :amp
這時候開啟 Server 並在 URL 後面加上 .amp
就能瀏覽該頁面 AMP 的版本
AMP 驗證
在 URL 後面加上 #development=1
就能在 Console 中驗證你的 AMP 頁面。
看到 Powered by AMP ⚡ HTML ......
表示你的頁面已經順利導入 AMP,但別高興得太早,直到修正所有錯誤並印出 AMP validation successful.
才真的成功 ⚡️ 在那之前都只是 Another Miserable Problem.
關於 AMP errors 可以參考 Resolving validation errors – AMP 來 debuuuuuug 🐞
Inlined CSS 塞好塞滿
這時通常會看到這樣的錯誤訊息…
The attribute 'href' in tag 'link rel=stylesheet for fonts' is set to the invalid value 'base.css'.
你可能會 OS:『我有成千上萬行的 CSS 而且還是用 Sass 編譯過來的,誰在那邊跟你一行一行 inlined CSS!』作為設計師,驚恐指數再乘上 8.7 😱
由於在 AMP 裡 link rel=stylesheet
只接受如 Google Fonts 或 Font Awesome 等 custom fonts。當我們需要處理獨立的 CSS 檔案時,可以參考 Supported CSS – AMP 使用 {% include "/assets/css/main.min.css" %}
或以下方法:
- 在
application_helper.rb
新增一個 method:
def render_css(path)
raw Sass::Engine.for_file("#{Rails.root}/app/assets/stylesheets/#{path}", {
load_paths: ["#{Rails.root}/app/assets/stylesheets"],
style: :compressed
}).to_css
end
- 接著在
application.amp.slim
的head
中加上:
style[amp-custom]
= render_css('amp.sass')
如此一來就能輕鬆引入編譯好的 CSS 作為 inlined style。但 AMP 限制使用 CSS 的目地正是為了縮短載入速度,因此也限制了 inlined style 的大小不得超過 50 KB。建議另開檔案 import AMP 需要的 style 即可。
排除第三方 JavaScript
好不容易解決 CSS,可是瓶頸之後還有瓶塞 👻
The tag 'script' is disallowed except in specific forms.
這時你可能又要尖叫加三級。重看不重用的特效先拔掉、社群分享的按鈕也拔掉、連留言功能都要拔掉 ⋯⋯ 什麼?!連 hamburger button 也要拔掉。就說太快就會很空虛啊 Orz
雖然 AMP 限制 JavaScript 的使用,但也提供許多 AMP Components 作為替代方案。你可以在 Learn AMP by Example 尋找合適的替代方法,不僅有詳細的說明也有完整的 sample code 或 live demo。
舉例來說,AMP 有自己的 lightbox 套件 amp-lightbox 可以做替換,或使用 amp-sidebar 代替 responsive navbar。比較複雜的互動如 Scroll to top 則結合 amp-position-observer 和 amp-animation 而成。
善用 AMP Components 已足夠解決大部分的問題、讓你的 AMP 頁面幾乎和原本的頁面一樣。如果你熟練 JavaScript 也可以嘗試撰寫符合 AMP 條件的方法來完善你的專案。
沒圖沒真相:amp-image
amp-img
標籤必須定義圖片的 width
和 height
來提升載入速度。這時可能會碰到一個問題:你的產品提供後台讓使用者自由編輯圖文,那要怎麼知道使用者上傳圖片的大小呢?!
FastImage 在這裡提供一個很有效的解法,它能幫助我們輕鬆抓取圖片的大小:
- 安裝
gem 'fastimage'
在
app/helpers/application_helper.rb
中新增一個 method:def get_img_size(src) FastImage.size(Rails.root.to_s + "/public" + src) # path_to_image end
get_img_size(src)
會回傳一個陣列(e.g[900, 675]
)正是我們需要的寬度與高度。如果使用者在後台編輯完、儲存在欄位裡的資料是一段完整的 HTML code,我們可以再新增一個 method:
def content_with_amp_img(content) markup = Nokogiri::HTML.fragment(content) markup.css('img').each do |img| img_w, img_h = get_img_size(img['src']) img.name = 'amp-img' img.set_attribute('width', img_w) img.set_attribute('height', img_h) img.set_attribute('layout', "responsive") end markup.to_html end
Nokogiri::HTML.fragment(content)
會把 HTML 依照標籤切割成獨立的物件,加上.css('img')
就能取出所有img
標籤。先把img
改成amp-img
再透過get_img_size(img['src'])
分別加上width
和height
。layout
可以參考 AMP 官方文件設定需要的屬性。最後,使用.to_html
就可以把全部的物件再組回一般的 HTML 格式。在你的
show.amp.slim
就可以呼叫content_with_amp_img(content)
來取得包涵amp-img
的內容了
小結
儘管本篇看似勸退文無誤(X)但很多雷如果事先知道的話都能直接避開,因此也可以將本文章定位成「導入 AMP 要先知道的幾件事。」請繫緊安全帶,加速愉快 😉