アクトインディ開発者ブログ

子供とお出かけ情報「いこーよ」を運営する、アクトインディ株式会社の開発者ブログです

いこーよの記事をAMP化しました

こんにちは、akiyamaです。

先日、いこーよの記事をAMP(Accelerated Mobile Pages)化しました。 AMP化にあたりいくつか知見が得られましたのでご紹介します。

AMPとは

AMPはAMP Projectで策定されているモバイルページ高速化の仕組みです。 AMP HTML仕様に沿ったページを作成することによって、モバイル端末での表示パフォーマンスの高速化が期待できます。

AMPの仕様は日本語の情報がSEO関係のページに出回っています。 わりと古めの情報などもありますので、ちゃんとampprojectの一次情報を参照するほうが確実です。

ampbyexampleは実際に動くものが書かれているので便利でした。

AMP化

通常のHTMLをAMP化するためには、次のものが必要です。

  1. <!doctype html>で開始
  2. htmlタグを<html amp>にする
  3. headタグの最初の子タグに <meta charset="utf-8">を書く
  4. <link rel="canonical" href="" />で元記事のURLを指定する
  5. viewportを定義: <meta name="viewport" content="width=device-width,minimum-scale=1">
  6. AMP用JSを読み込み: <script async src="https://cdn.ampproject.org/v0.js"></script>
  7. head内にスタイルを定義
<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>

また、AMP規格ではありませんが、google用に構造化データをhead内に書くことが多いと思います。 いこーよの記事ではJSON-LDで記載しています。この内容はページに合わせて変える必要があります。

<script type="application/ld+json">
  {
    "@context":"http://schema.org",
    "@type":"NewsArticle",
    "mainEntityOfPage":"http://iko-yo.net/articles/1671",
    "headline":"親子向け体験コンサート",
    "datePublished":"2016-09-12T03:24:24Z",
    "dateModified":"2016-09-12T03:24:24Z",
    "description":"開館30周年を迎えた...",
    "author":{"@type":"Person","name":"坪内 智子"},
    "publisher":{"@type":"Organization","name":"子供とお出かけ情報「いこーよ」",
    "logo":{
      "@type":"ImageObject",
      "url":"http://iko-yo.net/images/iko-yo_logo_290_50.png",
      "width":290,
      "height":50
    }
  },
  "image":{
    "@type":"ImageObject",
    "url":"http://d2goguvysdoarq.cloudfront.net/system/article_assets/attachments/1812/original.jpg?1473650664",
    "width":640,
    "height":426
  }
}
</script>

JSON-LDで指定するlogoimage(サムネイル画像)にはガイドラインがあります。これについては次の画像の説明で触れます。

これでAMPの枠組みが出来ましたので、body内で通常HTMLから変更が必要な箇所についてやったことなどを書いていきます。

(AMP拡張タグに必要なjavascriptファイルの読み込みなどは冗長なので省略しています)

画像

AMPではimgタグをamp-imgに置き換えたうえ、属性に画像サイズを必ず指定しなければなりません。

いこーよの記事画像はサイズを持っていないため、そのままではAMP化できませんでした。

AMPページをレンダリングするたびに画像サイズを取得するのは、 サイトの負荷を考えると避けたいと考えたため、 今回は記事作成時に画像サイズを保存するように改修しました。

(そのため、過去に作成された記事のAMP化は見送っています)

記事に使われる画像は、内部でアップロードされるものと、外部画像をそのまま使用するものがあります。

外部画像サイズの取得は、アップロード時にJavaScript(CoffeeScript)からImageオブジェクトを作成して取得、

geometry: (src)->
  img = new Image
  img.src = src
  width = img.width
  height = img.height
  ...

内部画像はpaperclipでリサイズされるため、paperclip-metaを使用しています。

サムネイル

AMP化したページはgoogleの検索結果に表示されることがあります。 サムネイルとして表示される画像は、JSON-LDで指定するimageが対応します。

"image": {
  "@type": "ImageObject",
  "url": "https://example.com/thumbnail1.jpg",
  "height": 800,
  "width": 800
},

その際表示される画像は横幅696px以上でなければならないとあります。

The representative image of the article. Only a marked-up image that directly belongs to the article should be specified.

Images should be at least 696 pixels wide. Images should be in .jpg, .png, or. gif format. Image URLs should be crawlable and indexable.

https://developers.google.com/search/docs/data-types/articles#type_definitions

いこーよの場合、サムネイル画像がサイズ要件を満たさないことがあるため、そのような記事ではgoogle検索結果への表示は期待できないかもしれません。

またロゴについても上記ページ内でガイドラインがあります。これは長くなりますのでガイドラインを参照ください。

iframe

いこーよの記事では埋め込みコンテンツとして、google map, youtube, instagramを使用しています。 (instagramiframe src='http://instagram.com/p/.../embed'形式)

このうち、google map, youtubeiframeをそのままamp-iframeに置き換えています。 amp-youtubeなどの専用の拡張タグがありますが、実装上AMPではない記事本文を流用しやすいamp-iframeを採用しました。

ただし、google map, youtubeを正常動作させるためには、sandbox="allow-scripts allow-same-origin"の指定が必要でした。 この指定ではsandboxがあまり意味を成さないため、専用タグの方がやはり適切かもしれません。

また、amp-iframeはplaceholderとしてamp-imgを子要素にもつ必要があります。

instagram

当初はinstagramiframeの使用を考えていましたが、amp-iframeで埋め込んだ場合、一部リンクが開けなくなってしまいました。 そのためinstagramamp-instagram拡張タグを使用して埋め込んでいます。

instagramのframeサイズは画像サイズに依存するため、正方形と長方形の画像で異なります。 正方形ならwidth="1" height="1"と適当な固定サイズの指定が可能ですが、正方形以外はきちんとサイズを指定しないといけません。

https://ampbyexample.com/components/amp-instagram/

SNS

twitter, facebookなどSNSの共有ボタンはamp-social-shareで作成可能です。

他のAMPサイトを見るとamp-social-shareを使用しているケースはあまりなく、aタグを使っていることが多かったです。 今回はAMPらしくamp-social-shareを使用して実装しました。

twitter, facebookはpre-configured providersに含まれるので、そのまま使用できます。 (facebookdata-param-app_idの設定が必要です)

設定されていないSNSを使用する場合は、data-share-endpointを使用して設定します。

lineの場合、data-share-endpoint='http://line.me/R/msg/text/?{パーセントエンコードされたテキスト}'と指定することでシェアボタンが使えるようになります。

endpointにline://msg/text/のようなプロトコルを指定すると、後述するバリデーターに怒られます。 使用できるプロトコルホワイトリスト化されているものだけになります。

name: "data-share-endpoint"
value_url: {
  allowed_protocol: "ftp"
  allowed_protocol: "http"
  allowed_protocol: "https"
  allowed_protocol: "mailto"
  # Whitelisting additional commonly observed third party
  # protocols which should be safe
  allowed_protocol: "fb-messenger"
  allowed_protocol: "skype"
  allowed_protocol: "snapchat"
  allowed_protocol: "sms"
  allowed_protocol: "tel"
  allowed_protocol: "viber"
  allowed_protocol: "whatsapp"
  allow_relative: false
}

https://github.com/ampproject/amphtml/blob/master/extensions/amp-social-share/0.1/validator-amp-social-share.protoascii

広告

いまいち安定せず、出なかったりすることがあります。 広告業者によっても違うようです。 これについてはまだ調査中です。

javascript

AMPページ内では基本的にjavascriptが使用できません。 いこーよの記事内ではそれほどjavascriptを使用していなかったため大きな問題にはなりませんでした。

動的なコンテンツに対応する場合はamp-listなどの拡張タグを使用する必要があります。 現時点では動的なAMPページをつくるメリットはあまり無いと思います。

バリデーション

作ったAMPページが正しいかチェックするためのバリデーションには https://www.ampproject.org/ja/docs/guides/validate.html で紹介されているブラウザ拡張が便利でした。 バリデーションだけでなく、<link href="/articles/1666/amp" rel="amphtml">とAMPページヘのリンクがあるページでは、機能拡張ボタンからAMPページヘ移動できます。

まとめ

いこーよの記事ページのAMP化を行いました。

特に画像やiframeのサイズ周りの対応に気を使う必要がありました。

それ以外の部分ではあまり手もかからず通常HTMから変換が可能でした。

AMPページの制限は大きいので、あまり凝ったことはせずに、 まずはシンプルなAMPページ化していくのが良いのではないかと思います。