ちょっとタイトルだと何言ってんのかわからないと思いますが......
この Blog で出力している AMP (Accelerated Mobile Pages) に、新デザイン (参考エントリー) を適用しているとき、記事の下部に一覧として表示している 「関連記事」 部分にある画像のサムネイルに、width
属性と height
属性をつける必要がありました (AMP では、amp-img
要素にこの 2つの属性が必須です)。
この部分の画像は、Movable Type (この Blog は Movable Type で構築されています) のカスタムフィールドで各記事に登録できるようにしてある OGP 画像を引っ張るようにしてあります。Movable Type では、<$mt:AssetProperty property="image_width"$>
などで、登録した元画像のサイズを取得することは簡単にできますが、当然、この部分の width
属性と height
属性に入れたいのは、元のでかい画像のサイズではなく、この場所に合わせて縮小した画像のサイズになりますね。
で、Movable Type ちょっとわかる人なら、サムネイル画像を AssetThumbnailLink
テンプレートタグで書き出せば width
属性と height
属性も自動で付くじゃん、ってなると思うんですが、AssetThumbnailLink
はオリジナルファイルへのリンク付きのサムネイルを丸ごと (つまり、a
要素と img
要素をセットで) 出力するので、当 Blog の記事リストのように、img
要素だけが欲しいという場所では使いにくかったり (regex_replace
グローバルモディファイアを使って a
要素を削除するみたいな力技もありますけども)、そもそも、CDN 使って画像処理をしてたりする関係で AssetThumbnailLink
だと使い勝手が悪かったので、少しトリッキーな手法で解決しましたよというお話。
何がしたかったのか
この Blog の 「AMP ではない、通常ページ」 で、各記事下に配置している、関連エントリーは、基本的に下記のような HTML と Movable Type テンプレートタグによって書き出しています (一部説明に不要なコードは省いています)。なお、EntryDataOgpimageSet
は、カスタムフィールドで設定しているテンプレートタグなので標準のテンプレートタグではありません。
<div class="block-related-entries">
<div class="module-related-entries-inner">
<aside>
<div class="module-related-entries-header">
<h2>関連記事</h2>
</div>
<div class="block-list-entry-2nd">
<$mt:EntryCategory setvar="cate"$>
<$mt:EntryID setvar="id"$><mt:Entries id="$id"></mt:Entries>
<mt:Entries category="$cate" limit="10" unique="1">
<div class="module-list-entry-item">
<article id="article-no-<$mt:EntryID$>">
<a href="<$mt:EntryPermalink abs2rel="1"$>" rel="bookmark">
<div class="module-entry-item-title">
<h3 class="module-normalize"><$mt:EntryTitle encode_html="1"$></h3>
</div>
<div class="module-entry-item-img">
<mt:Unless strip_linefeeds="1">
<img src="
<mt:If tag="EntryDataOgpimageSet">
https://burnworks.imgix.net
<mt:EntryDataOgpimageSetAsset><$mt:AssetURL abs2rel="1"$></mt:EntryDataOgpimageSetAsset>
?[...imgix_parameter...]
<mt:Else>
...略...
</mt:If>" alt="" />
</mt:Unless>
</div>
</a>
</article>
</div>
</mt:Entries>
</div>
</aside>
</div>
</div>
見ての通り、img
要素に width
属性も height
属性も付けていません。装飾的に使われている小さい画像なので、CSS でサイズを指定するだけで十分という判断からです。
しかし、AMP だと前述の通り、width
属性と height
属性が必須なので付けないといけないとわけです。つまり、img
要素の部分が下記のように amp-img
要素にならないといけないわけですね。
<div class="module-entry-item-img">
<amp-img layout="responsive"
src="[...略...]"
width="120"
height="[ここの値は画像ごとに違うの]"
alt="">
</amp-img>
</div>
width
属性の値は固定 (120px) なので、テンプレートに width="120"
とハードコーディングしてしまえばよいとして、登録される画像サイズが固定ではない関係から、height
属性の値はそれぞれの画像ごとに、横幅の 120px に対して縦横比 (アスペクト比) が合うように算出してあげないといけません。
テンプレートタグと演算関数を使って画像の高さを算出する
ある画像の横幅が 120px まで縮小されたとして、その時、アスペクト比が変わらない高さの値を算出すること自体は簡単です。つまり、元画像の横幅に対する、120px の比率を調べて、同じ比率を元画像の高さにかけてあげればいいわけです。
例えば、1200px × 800px の元画像が、横幅が 120px になるまで縮小された場合、横幅は元サイズの 1/10 になっているわけですから、元画像の高さも同じく 1/10 してあげれば、80px という高さが算出できます。
そこまでは別に難しい話ではないのですが、実際にテンプレートタグでどう実装するか...... と考えたときに、そういえば (一部) テンプレートタグって op
モディファイアを使って簡単な計算ならできるじゃん、ということで解決策が出ましたよと。
実際のソースコード
ということで、下記のようになりました (説明に不要なコードは省略しています)。
<amp-img layout="responsive" src="
<mt:If tag="EntryDataOgpimageSet">
https://burnworks.imgix.net
<mt:EntryDataOgpimageSetAsset>
<$mt:AssetProperty property="image_width" setvar="width"$>
<$mt:AssetProperty property="image_height" setvar="height"$>
<$mt:SetVar name="width" value="120" op="/"$>
<$mt:SetVar name="height" value="$width" op="/"$>
<$mt:SetVar name="height" value="0.5" op="+"$>
<$mt:Var name="height" regex_replace="/(\d*)\.(\d*)/","$1" setvar="height"$>
<$mt:AssetURL abs2rel="1"$></mt:EntryDataOgpimageSetAsset>
?[...imgix_parameter...]
<mt:Else>
...略...
</mt:If>" alt="" width="120" height="<$mt:Var name="height"$>">
</amp-img>
高さの計算に関係する記述を抜き出してみます。
<mt:EntryDataOgpimageSetAsset>
<$mt:AssetProperty property="image_width" setvar="width"$>
<$mt:AssetProperty property="image_height" setvar="height"$>
<$mt:SetVar name="width" value="120" op="/"$>
<$mt:SetVar name="height" value="$width" op="/"$>
<$mt:SetVar name="height" value="0.5" op="+"$>
<$mt:Var name="height" regex_replace="/(\d*)\.(\d*)/","$1" setvar="height"$>
</mt:EntryDataOgpimageSetAsset>
height="<$mt:Var name="height"$>"
まず、元の画像の横幅、高さを取得し、それぞれ、width
、height
変数にセットします。
<$mt:AssetProperty property="image_width" setvar="width"$>
<$mt:AssetProperty property="image_height" setvar="height"$>
次に、元画像の横幅 (変数 width
にセットした値) を 「120」 で割ります (変数 width
には、計算結果がセットされます)。
<$mt:SetVar name="width" value="120" op="/"$>
次に、元画像の高さを、先ほどの変数 width
の値で割ります (変数 height
には、計算結果がセットされます)。
<$mt:SetVar name="height" value="$width" op="/"$>
このままだとサイズによっては小数点以下の数値が出てしまいますので、変数 height
の値を四捨五入します。四捨五入は 0.5 を足してから小数点以下を削除すればよいので、
<$mt:SetVar name="height" value="0.5" op="+"$>
<$mt:Var name="height" regex_replace="/(\d*)\.(\d*)/","$1" setvar="height"$>
op
モディファイアで変数 height
の値に 0.5 を足してから、regex_replace
グローバルモディファイアで小数点以下を消してやります。
あとは、この変数 height
の値を、height
属性値に入れてあげれば完成です。
height="<$mt:Var name="height"$>"
ひと手間かかりましたが、これで AMP に関しても問題なく記事下の関連エントリー部分を実装することができました。