amp-listで高さを可変にする裏技 (amp-list with dynamic height)【AMP】

> 2004142326360のリリース以降、こちらの裏技は塞がれてしまった可能性があります
> https://github.com/ampproject/amphtml/releases/tag/2004142326360

# <strong>amp-list で高さを可変</strong>にする裏技

<strong>`amp-list`</strong> は、<b>高さを事前に指定</b>する必要があります。
しかし、高さを固定すると自由度が下がってしまうため、JSON のコンテンツに応じて高さを可変で利用するための裏技を紹介します。


## amp-list とは

> Fetches content dynamically from a CORS JSON endpoint and renders it using a supplied template
[Documentation: &lt;amp-list&gt; - amp.dev](https://amp.dev/documentation/components/amp-list/)

JSON のエンドポイントからコンテンツを取得し、テンプレートからクライアントサイドで DOM を生成できるコンポーネント


## amp-list の特徴

- JSON から非同期にデータを取得して DOM を生成できる
  - `amp-mustache` による mustache 構文のテンプレートベース

- placeholder の付与だけで JSON 取得中に表示する要素を指定できる
  - skeleton も簡単に実現できる

- fallback の付与だけで JSON 取得失敗時に表示する要素を指定できる

- レスポンスの JSON で次のエンドポイントも指定することで、無限スクロールも実現可能

など


## amp-list の問題

<b>`amp-list` では事前に高さを指定しなければならない</b>
そのため高さが可変になる UI の実現が難しい


## amp-list で高さを可変にする裏技

`amp-list` に対して以下の4つの指定を行う

1. クラス名を付与する (ここでは `.DynamicList`)
2. layout を `flex-item` にする
3. 自身に `min-height: 1px;` を指定 (※1)
4. 自身の直下に自動生成される `role="lis"` が付与されたDOMに対して以下のスタイルを指定

CSSを書き出すと以下のようになります

```css
.DynamicList {
  min-height: 1px;
}

.DynamicList [role=list] {
  position: relative;
  width: auto;
  height: auto;
}
```

※1: 1px 以上の指定がない場合、`amp-list` が動作しないため必ず 1px 以上で指定してください


## サンプル

以下のような構造の JSON に対して高さ可変でリストを表示


### JSON

```JSON
{
  "items": [
    {
      "text": "Yahoo! JAPAN",
      "href": "https://www.yahoo.co.jp/"
    },
    {
      "text": "Yahoo!ショッピング",
      "href": "https://shopping.yahoo.co.jp/"
    },
    {
      "text": "ヤフオク!",
      "href": "https://auctions.yahoo.co.jp/"
    },
    {
      "text": "Yahoo!トラベル",
      "href": "https://travel.yahoo.co.jp/"
    }
  ]
}
```

### HTML
`amp-list` の `src` に JSON のエンドポイントを指定してください
（HTMLは一部省略しています)

```HTML
<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>
  <style amp-custom></style>

  <script async src="https://cdn.ampproject.org/v0.js"></script>
  <script async custom-element="amp-list" src="https://cdn.ampproject.org/v0/amp-list-0.1.js"></script>
  <script async custom-template="amp-mustache" src="https://cdn.ampproject.org/v0/amp-mustache-0.2.js"></script>
</head>

<body>
  <template id="yahoo-list" type="amp-mustache">
    <ul>
      <li><a href="{{href}}">{{text}}</a></li>
    </ul>
  </template>

  <amp-list layout="flex-item" template="yahoo-list" src="JSON_END_POINT" class="DynamicList"></amp-list>
</body>
```

### CSS

本来はインラインで上記 HTML の `<style amp-custom>` 内に書く

```CSS
.DynamicList {
  min-height: 1px;
}

.DynamicList [role=list] {
  position: relative;
  width: auto;
  height: auto;
}
```

### 動作確認

JSON の `items` の中身の個数に応じて、可変の高さになっているか確認

#### 4つの時

<img width="780" alt="JSONのitemsの中身が4つの時" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130952/f8fb763d-e498-d9b3-f831-4eec5e360701.png">

#### 1つの時

<img width="780" alt="JSONのitemsの中身が1つの時" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130952/907964ff-ab6d-2dc5-67ee-63b06b512993.png">

#### 0の時 (カラの時)

<img width="778" alt="JSONのitemsの中身がカラの時" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130952/02a62ca0-9c17-b1b7-e08e-a4a7349d38b7.png">


## まとめ

`amp-list` で JSON のコンテンツに応じて高さを可変で利用するための裏技でした。

<b>注意しておくべき点</b>
非同期で初期レンダリング後に高さ可変の DOM が追加されため、<b>ガタ</b>っと要素が表示されてしまう問題があります。
この手法を用いる場合は、このようなマイナスなユーザー体験とトレードオフで使うことが好ましいと思います。

---

AMP の知見を引き続き記事にしていこうと思います。
<b>いいね</b>をしていただけるとモチベーションに繋がりますので押していただけると嬉しいです。