amp-listで高さ(height)を可変にして表示する
AMP用のコンポーネント「amp-list」を使う場合、デフォルトでは高さを指定しないとsrc属性に設定したURLからJSONを読み込んでくれないのですが、個人的にamp-listを使う場合、高さは可変で表示したいことが多かったのでその方法です。
AMPを学んでいる真っ最中なので、正しい作法かどうかは分からないのであしからず。
正直なところ、AMPコンポーネントの挙動がイマイチ掴めません。
目次
- 準備
- データ
- コード
- 出力されたHTMLの確認
- CSSの設定
- CSS設定後のHTML出力
- 備考
- 参考リンク
準備
amp-listを利用する場合、以下の二つのライブラリを読み込みます。
<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.1.js"></script>
amp-mustacheはamp-listの出力時に利用するテンプレートです。
データ
amp-listのsrc属性で読み込むデータは以下の通り。
{
"items":[
{
"id" : 1,
"name" : "データ1"
},
{
"id" : 2,
"name" : "データ2"
},
{
"id" : 3,
"name" : "データ3"
}
]
}
amp-listはデフォルトで「items」にセットされたデータが出力対象になります。
コード
上記データ(URLは仮にhttp://localhost/data/example.json)を読み込んで出力するamp-listのHTMLコード。
<amp-list layout="flex-item"
src="http://localhost/data/example.json"
noloading>
<template type="amp-mustache">
<div>{{id}}:{{name}}</div>
</template>
</amp-list>
高さを可変で表示したかったのでlayoutに「flex-item」を指定しています。
「noloading」はローディング中の状態を表示したくなかったので設定しています。
amp-listの親要素のクラスとamp-list自体のクラスは後々説明しますが必要でした。
上記コードでちゃんとデータを読み込んで表示してくれるのかというと、このままではしてくれません。
layoutに「fixed-height」を指定する場合は問題なく動作するのですが、「flex-item」を指定するとsrcにセットしたhttp://localhost/data/example.jsonを読み込んでくれませんでした。
原因はデータロード時の表示エリア高さ(height)が0なので、データを読み込む必要がないと判断されているようで、以下はその辺りを解決して表示する方法になります。
出力されたHTMLの確認
上記のコードで出力されたHTMLは以下の通り。
<amp-list layout="flex-item" src="http://localhost/data/example.json" noloading class="i-amphtml-element i-amphtml-layout-flex-item i-amphtml-layout-size-defined i-amphtml-layout" aria-live="polite">
<div class="i-amphtml-fill-content i-amphtml-replaced-content" role="list">
</div>
</amp-list>
本来はamp-list直下の<div role="list">配下に読み込んだデータが出力されるはずなのですが、されていないことが分かります。また、ChromeのデベロッパーツールのNetworkで読み込まれたファイルを確認すると、srcに指定したファイルはアクセスすらされていないことが分かります。
こうなる原因は前述しように初期値の高さ(height)が0なのが問題です。
CSSの設定
初期値の高さ(height)が0だから読み込んでくれないのだから、スタイルで設定すればいいじゃないか、と思って追加したCSSが以下。
amp-list {
min-height: 1px;
}
amp-list > div[role=list]{
position: relative;
height: auto;
}
ポイントはamp-listの「min-height」に1以上の値をセットして、amp-list直下のdiv[role=list]に「position:relative」と「height:auto」を指定することです。
amp-listの「min-height」を設定することでファイルはロードしてくれますが、amp-list直下のdivに上記のようなスタイルを設定しないと、表示エリアの要素の高さが1しかないので、画面に表示されません。
なお、roleで指定(div[role=list])しないと、AMPコンポーネントのスタイルが優先されて、こちらで設定したスタイルが反映されません。
CSS設定後のHTML出力
上記のCSS設定後、出力されたHTMLは以下の通りです。
<div class="amplist-area">
<amp-list layout="flex-item" src="http://localhost/data/example.json" noloading class="i-amphtml-element i-amphtml-layout-flex-item i-amphtml-layout-size-defined i-amphtml-layout" aria-live="polite">
<div class="i-amphtml-fill-content i-amphtml-replaced-content" role="list">
<div>1:データ1</div>
<div>2:データ2</div>
<div>3:データ3</div>
</div>
</amp-list>
</div>
画面にもちゃんと表示されました。
備考
高さの可変対応をやってみて思いましたが、amp-listに関してはheight値固定が前提のコンポーネントになっているようです。それはAMPに対応したページを作成する場合、スタイルで「!important」が使えなかったり、コンポーネントで出力された「i-amphtml-~」といったクラスを指定してスタイルを設定しようとするとNGだったりといったことからも明らかで、こちら側でコンポーネントのスタイルを変更させたくないような仕様になっています。
おそらくamp-listで一定数ではない複数のアイテムを表示する場合、エリア内に収まらないアイテムは「Show More」で表示するのが正しい作法のようで、その方法が公式のサイトにも掲載されています。
ただ、私が試した限りでは、「Show More」の挙動が安定しなかったので、上記のような形で対応しました。
最終的にはこの方法もNGになったりしたら色々と面倒なので、一度、AMP関連の書物に目を通した方が良さそうです。