Accelerated Mobile Pages (AMP) 實戰守則

Accelerated Mobile Pages (AMP)

這是由 google 所推出的一個 web standard, 其立意良好, 主要是希望能讓 web developer 藉由其所發出來的 web components 來快速 build 出 high performance 以及有效解決 mobile device 差異化所衍生出來的點點滴滴, 不僅如此, google 更是把 AMP bundle 至其 mobile search, 只要您原本的 web page 有製作 AMP version 並且在頁面上明確指出其路徑, 那麼在 google mobile search result page 中便會優先顯示 AMP page

搜尋關鍵字 – brembo zl1

如上圖所示, 我們在 mobile device 上進行 google search, 即可發現搜尋結果的第一筆資料有標示著一個灰色的閃電符號, 這即是 AMP page, 不僅僅如此, google 亦針對當前頁面找出來的 AMP page 進行 prerender 的動作, 所以當我們點擊這類閃電符號的搜尋結果, 就會發現該頁面飛快地彈出, 讓使用者不需要再浪費時間等待 web page loading / render / init 等動作. 一整個搜尋體驗可以說超級順暢

 

 

雖然說有一派人馬認為設置了 AMP page 是種將流量分享給他人且不利己的做法

 

為什麼我要為他人作嫁衣呢? 

 

我想這類的論戰可以爭個三天三夜亦沒完沒了, 對我來說這完全端看自己對於 AMP 的初衷與態度, 想要從搜尋引擎獲得好處前, 不妨以互惠的角度來思考, 人家也是出了 CDN 來幫你 cache web content, 更直接在 search result page 幫你 enhance 使用者體驗, 還有效幫你解決跨瀏覽器差異, 對我來說其實利大於弊, 何樂而不為呢 ?

早期 AMP 所提供的 web components 其實不多, 用起來不僅綁手綁腳, 也很難在頁面上做出差異化, 不過今非昔比, 如今該社群的發展挺活躍, 更廣納建議, 新增了多元且豐富的 web components, 讓 web developers 可以向堆積木般輕輕鬆鬆、開開心心的推疊出心中所嚮往的 mobile page, 再加上國內導入 AMP 的服務其實不多, 現在真的是進場的最佳時機, 這也是筆者這一陣子一頭栽進去 AMP 的原因所在, 由於開發的路上難免踩到些坑坑洞洞, 所以希望藉由今天這篇文章的分享, 可以有效地幫助有新開發 AMP page 的朋友

 

淺談 AMP 的頁面結構

我們可以從 AMP template 或者是既有的頁面來進行 AMP page 的開發, 不管是重新開發或者是拿既有頁面調整, 都必須要嚴格遵守其限制

<!doctype html>
<html amp lang="en">
  <head>
    <meta charset="utf-8">
    <script async src="https://cdn.ampproject.org/v0.js"></script>
    <title>Hello, AMPs</title>
    <link rel="canonical" href="http://example.ampproject.org/article-metadata.html">
    <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
    <script type="application/ld+json">
      {
        "@context": "http://schema.org",
        "@type": "NewsArticle",
        "headline": "Open-source framework for publishing content",
        "datePublished": "2015-10-07T12:02:41Z",
        "image": [
          "logo.jpg"
        ]
      }
    </script>
    <style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
    <style amp-custom>
    ...
    ...
    ...
    </style>
    <script async custom-element="amp-bind" src="https://cdn.ampproject.org/v0/amp-bind-0.1.js"></script>
    <script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js"></script>
    ...
    ...
    ...
  </head>
  <body>
    <h1>Welcome to the mobile web</h1>
  </body>
</html>

簡單的說 AMP 不允許 developers 自己開發 JavaScript, 所以在頁面只要有任何外連 js file (非 AMP web component required js) 或者是 inline script, 均會明確地被認為 error, 不僅僅是 JavaScript, 就連 CSS 亦是如此, 至於要怎麼 style AMP page 呢? 其實 AMP 有挖了一個洞 – <style amp-custom> 給 developers, 只要是頁面上用到的 style, 均需要被明碼且完整的收錄到該 tag 中

無法 code JavaScript 難免會令人感到恐慌, 其實 AMP 提供的 web components 均完整的封裝了一些必要的 method, 所以我們可以藉由這些 method 的調用, 一樣可以 build 出豐富有趣的效果喔!

 

AMP page 出現 Error 又如何 ?

 

Google 在進行 search index 前, 均會透過 AMP Validate 來驗證該 page 的正確性, 所以一旦發生 error 時, 便會直接 drop, 無法進行 indexing, 所以確保頁面的正確性, 便成了 developers 的首要課題

以下簡單列出頁面結構必須要注意的幾個要點, 幾乎都是 <head> 本身需要特別注意

  • doctype 需要設置 HTML5 format, ex: <!doctype html>
  • 需要在 <head> 加入 ⚡ 符號或者是 amp 字樣的 attribute
  • 須具備 <head> 以及 <body> tag
  • <head> 中第一個子元素為 <meta charset=”utf-8″>
  • <head> 中第二個子元素為 <script async src=”https://cdn.ampproject.org/v0.js”></script>
  • <head> 中需要設置 <meta name=”viewport” content=”width=device-width,minimum-scale=1″>
  • <head> 中需要設置 <style amp-boilerplate> … </style>, 這個 style tag 明確定義了一些 AMP  web components 會使用到的 CSS, developers 應該要避免設置到同名的 CSS, 不然一樣會驗證失敗喔!

以上這些不成文的規定均需要明確遵守, 筆者對於 meta[viewport] 的設置其實是有存疑的, 尤其在 iX 問世且 iOS support viewport-fit 屬性後, 該值是否能有更明確或者靈活的設定, 均需要等待 AMP project team 釋出更近一步的消息

 

AMP Validation

維持 AMP page 正確性是每個 web deveopers 的首要任務, 那麼我們可以該怎麼驗證呢?! 方法大概可以細分以下兩種

  1. 直接在 AMP page 網址後方加上 #development=1, 藉此開啟開發者模式, 一旦頁面上如果有任何錯誤產生時, 便可以馬上從 console 這個 tab 得知, 不過筆者比較不建議這方式, 原因是因為開啟後, 它會把頁面上 amp-bind 的 attribute 設置認為錯誤, 一旦出現錯誤便會直接 throw error 出來, 不繼續往後跑, 造成開發上不必要的困擾
  2. 安裝 chrome extension – AMP Validator, 他會直接在 browser 網址功能區塊處有個閃電符號的呈現, 明確的告知當前 web page build-in with AMP or not. 由於內容非常詳細, 所以可以很明確的知道該去哪兒排除錯誤, 這亦是筆者推崇的驗證方法
    non build-in with AMP

    non build-in with AMP

     

    AMP page and pass validate

    AMP page and pass validate

     

    AMP page link (點擊後回到 AMP page)

    當出現錯誤時, 可以清楚看到 AMP Validator 最厲害的地方了, 它會指出頁面文件哪一行出現錯誤, 並請清楚指出主要出錯的原因, 讓 developers 可以快速地來進行問題排除, 雖然 Warning 現階段不會影響 google search index, 不過這種事情說不得準, 一個優秀的 developer 最好還是以 0 Error / 0 Warning 為終極目標去努力

 

與 <style amp-custom> 共舞

如上段所示, 頁面中所使用到的 style 均需要被集中於該 tag 中, 除此之外, className 的設置更需要特別注意不要跟 <style amp-boilerplate> 中的內容重疊, 除此之外, 還有另一個困擾筆者的問題存在, 即 – 50k 的內容大小限制, 也因此如何有效地reuse 以及移除不必要的 “贅 class”, 才不會隨隨便便就超過該約制

筆者列了幾點注意事項給大家

  • 避免使用包山包海的 CSS framework, 例: normalize, reset, grid …etc, 雖然說極為便利, 不過大多數的屬性可能都沒有使用到, 適量的從中挑選出頁面所需要的 class 即可
  • 雖然 dataURI 可以有效地減少頁面 request count, 不過總的來說他也會無形的增加了 total CSS size, 更無法有效的享受到 google CDN cache, 所以有用到圖片的部分, 請儘量使用外部連結
  • Skinny on CSS Attribute Selectors 用得好的話, 往往一個設定便可以快速的讓多個 html elements 受到作用, 雖然被認為會影響 page render, 不過卻可以有效地節省 total CSS size, 所以就大膽放心的用上吧!
  • 有效地使用 CSS 特性縮寫, 將同樣的屬性做一個有效的 grouping, 亦可有效地使用 CSS size, 除此之外,部分的 value 亦可透過不同屬性來進行詮釋喔!
<style>
.background {
	background-image: url(img/yau/ico-like-store.svg);
	background-repeat:  no-repeat;
	background-position:  center center;
	background-size: auto 100%;
	/* same with the following */
	background: url(img/yau/ico-like-store.svg) no-repeat center / auto 100%;
}

.font {
	font-style: italic;
	font-weight: bold;
	font-size: .8em;
	line-height: 1.2;
	font-family: Arial, sans-serif;
	/* same with the following */
	font: italic bold .8em/1.2 Arial, sans-serif;
}

.border {
	border-width: 1px;
	border-style: solid;
	border-color: #000;
	/* same with the following */
	border: 1px solid #000;
}

.text {
	font-weight: bold;
	/* same with the following */
	font-weight: 700;
}

.text2 {
	font-weight: normal;
	/* same with the following */
	font-weight: 400;
}

.padding {
	padding-top: 10px;
	padding-right: 10px;
	padding-bottom: 10px;
	padding-left: 10px;
	/* same with the following */
	padding: 10px;
}

.margin {
	margin-top: 10px;
	margin-right: 10px;
	margin-bottom: 10px;
	margin-left: 10px;
	/* same with the following */
	margin: 10px;
}

/* Skinny */
mark[class|='ico-paytype'] {
	width: 24px;
	height: 24px;
	display: block;
}
</style>

另外, 在發布之前, 亦可透過一些 CSS optimize tool 把一些不必要的空格以及斷行符號甚至是每個 className 最後一個分號清一清, 亦可達到瘦身的效果喔!

 

Web Components 的選用

AMP 提出了很多的 web components, <amp-*> 系列的均為其 web components, 依照功能屬性可以細分為

有興趣的朋友可以點擊上面連結觀看各 web components 的設定以及使用方法, 比較會令人感到困惑的就是其 layout 屬性, 不同 web component 支援的 layout 亦不相同, 所以在使用前務必詳細閱讀公開說明書, 避免不必要的誤會

接下來, 筆者列出幾個最常用的 web components, 讓大家知道 AMP page 與 normal page 的相似處, 在使用上可以做怎麼樣的轉換

amp-bind: 透過 amp-bind 可以讓 html element 的部分屬性變成可異動, 輕輕鬆鬆達到 module 狀態變化

<!-- Store complex nested JSON data in <amp-state> elements. -->
<amp-state id="myAnimals">
  <script type="application/json">
    {
      "dog": {
        "imageUrl": "/img/dog.jpg",
        "style": "greenBackground"
      },
      "cat": {
        "imageUrl": "/img/cat.jpg",
        "style": "redBackground"
      }
    }
  </script>
</amp-state>

<p class="content" [text]="'This is a ' + currentAnimal + '.'">This is a dog.</p>

<!-- CSS classes can also be added or removed with [class]. -->
<p class="greenBackground" [class]="myAnimals[currentAnimal].style">
  Each animal has a different background color.
</p>

<!-- Or change an image's src with the [src] binding. -->
<amp-img width="300" height="200" src="/img/dog.jpg"
    [src]="myAnimals[currentAnimal].imageUrl">
</amp-img>

<button on="tap:AMP.setState({currentAnimal: 'cat'})">Set to Cat</button>

從上面的 example, 我們可以清楚看見中括號包起來的屬性即表是可以變動的部分, [class], [src]…etc, 透過 event binding, 藉由 AMP.setState 來更改 page state, 類 react 作法, 一旦 data 有異動, 則會重新 render 那些用中括號包起來的屬性, 所以上面的範例其執行順序為

  1. button 被點擊, 觸發 on 的 AMP.setState 方法, 進行 currentAnimal 內容變更
  2. p.content 由於有設定 [text] 且與 currentAnimal 有所關聯, 所以其 textContent 會被 rerender
  3. p.greenBackground 由於有設定 [class] 且與 currentAnimal 有所關聯, 所以 class 會被 rerender
  4. amp-img 由於有設定 [src] 且與 currentAnimal 有所關聯, 所以 src 會被 rerender

amp-carousel: 頁面中如果有用到 carousel 來做圖片內容呈現, 便可以使用該 tag 來設置 carousel 或者是 slide 的效果

amp-list: 由於 AMP Cache 的機制, 只要 validate pass 的 AMP page, 均會被 google cache 至 CDN,  所以 user 看到的內容均是被 cache 起來的內容, 如果有部分區塊希望能成呈現最即時的內容, 便可以使用該 web component, 藉由 src 的設置, 動態擷取最新的內容

amp-form: AMP 針對 <form> 做了功能擴展, 不僅具備完整的 form 功能, 更新增了 xhr 這個屬性, 讓 developers 可以透過該 web components 來進行傳統 xmlHttpRequest 的功能

amp-iframe: 對於部分 html content 如果真的無法調整 (比方說 Rich Text Editor 所產生出來的 content), 那麼亦可透過這個 web component 將之包覆, 讓這些內容可以正常在頁面上呈現, 不過使用條件有點小嚴苛, 比方說必須要與頁面所屬 domain 不同, 也因此會多了些額外的設定才能正常呈現

amp-lightbox: 常常我們可能會需要一些 lightbox 的效果, 便可以透過這個 web components 來進行該效果

amp-sidebar: 很多 mobile web or APP 喜歡製作一些 content 從 page 左側 || 右側滑出的效果, 便可以透過這個 web component 來做, 它其實就是 amp-lightbox 的變形, 與 amp-light 主要的差異就是他有 max-width 80vw 的限制

amp-image-lightbox: 這個 web component 主要作用為讓圖片被點擊後可以進行 lightbox 呈現, 透過簡單的設置, 便可以輕輕鬆鬆擁有類 facebook 圖片瀏覽效果

amp-analytics: 如何有效的衡量 AMP page 成效是每個 PM 所關心的, 透過這個 web component 更是可以完美的跟 google analytics 結合, 讓這些 data 可以有效地滾在一起, 避免增加一些不必要的設置與運算. 另外由於先天架構的關係, 不同 domain 會產生不同的 clientId, 此舉有可能會造成 UU | bounce rate 的增加, 所以可以搭配 Google AMP Client ID API 使用, 讓不同 domain 可以使用同一個 clientId, 來有效解決該問題喔!

amp-access: 透過這個 web component, 我們可以讓 AMP page 與自家會員登入狀態進行一個 mapping, 讓 user 在 AMP page 可以行使一些 developers 精心設計的會員功能, 比方說: like, 加入購物車, 直接購買

 

發佈前的最後一哩路

完成開發後真是令人感到興奮, 不過, 如果想讓 AMP page 達到盡善盡美呈現於世人前, 有些事情你不得不注意, 以下便是我整理出來的一些心得分享

  • Google 會把我們開發好的 AMP page cache 到他們的 CDN, 我們可以透過 網址 mapping 的機制, 直接看到被 cache 後的樣子, 為了有效精簡化頁面文件內容, 再進行 cache 前, google 可能會 trim 掉一些不必要的資訊, 比方說 meta / json-ld, 外部連結的檔案也直接被 cache 起來, 可藉由 view page source 即可看到, 甚至還會針對 <amp-*> 進行優化, 不過呢? 有些時候這些美意可能會引發一些不正常現象, 比方說 amp-img[src] 的 data binding 可能就會因為新增的 srcset 屬性造成無法正常更換其內容, 所以囉! CDN 上檢查頁面行為的動作真的少不了, 如果真的有發現什麼異常現象, 也可以透過 ampproject github 發 issue, 來釐清主要原因
  • 為了能讓 search engine 可以更加的認識我們的頁面內容, 所以基本的 SEO 功夫亦要做齊, microdata / json-ld 的設置更可以讓 search result page 中的呈現更加多元且活潑, 更可以透過 structured data testing tool 來驗證其正確性
  • <head> 中 link[rel=”amphtml”] 的設置尤其重要, 因為這個設定, 可以讓 search parser 可以清楚知道這個 web page 其實是有設置 AMP version, 那麼我們該怎麼設定這個屬性呢? 主要分為兩個部分 non-AMP page & AMP page- non-AMP page
    <head>
    ...
    <link rel="amphtml" href="https://www.example.com/url/to/amp/document.html">
    ...
    </head>

    – AMP page

    <head>
    ...
    <link rel="canonical" href="https://www.example.com/url/to/full/document.html">
    ...
    </head>

    藉由這樣的互相指定, 讓 search parser 可以有效的驗證這些網址的有效以及正確性, 藉此建立其 search index, 讓我們精心設置的 AMP page 有機會呈現於世人面前

    如果你的 website 本來就因應 device 的差異, 獨立切開 desktop 以及 mobile site 的話, 那麼又該怎麼設定 link[rel=”amphtml”] 呢? 其實這是一個非常好的問題, 且在 Webmaster Central Help Forum 已經有了確切的解答, 有興趣的朋友可以前往一覽喔!

 

AMP Cache

我想大家不免會有些疑問, AMP page 既然會被 google cahce 至 CDN, 那麼他更新機制是什麼呢 ? 如果我有資料需要更新, 又該怎麼觸發它來進行更新呢 ? 總的來說, AMP Cache 的更新會有三種方式如下所示:

  1. 如果都不做額外處理的話, AMP Cache 會隨著一般搜尋引擎更新機制一起更新, 搜尋引擎在重建頁面 index 的時候, 只要發現有 inlk[rel=”amphtml”] 的存在, 經驗證正確後, 便會一起更新 AMP Cache 的內容
  2. 一般 user 從 google search result page 所看到的 AMP page 內容其實就是 AMP Cache 至 CDN 的內容, 它存有一個機制, 只要有人 visit 該 cdnAmpUrl, 則會 trigger AMP Cache 進行 update, 該機制會在四分鐘以內把 AMP page 的內容進行完整 cache, 所以我們可以利用這樣的特性, 只要 curl 一下 cdnAmpUrl, 便可以輕輕鬆鬆完成 AMP Cache content update, cdnAmpUrl 與原有 ampUrl 之前的網址換算可以經由  網址 mapping 的機制進行轉換喔!
  3. 當然 Google 也有準備 Web Service 給 developer 來進行, 不過需要一些事前的準備, 有興趣的朋友可以點擊 Update AMP Content  一覽

對筆者來說, 這樣的更新機制和搜尋引擎來比可以說友善許多, 因為我們隨時隨地都可以透過上述的 2 or 3 點來進行更新, 化被動為主動, 不再是癡癡的等著被更新了, 筆者個人比較親賴使用方法2, 因為該方法可以說是最容易達成且最不需要花費額外的工

 

Reference

mei

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *