【Tumblr Tips】Photosetからアイキャッチを指定するカスタマイズ
複数枚の写真を組写真として投稿できるTumblrのPhotoset。その中から任意の1枚をアイキャッチとしてIndexページ表示させるため、当サイトに実装しているカスタマイズ手法をサンプルコードを交えながら紹介してみる。
2023/8/17追記
このエントリは、tumblrの旧投稿形式 Legacy Post Format(LPF)向けとなります。2023/8現在 LPFが廃止されNeue Post Format(NPF)に順次切り替わっているようですので、NPF対応版を記載しました。こちらも併せてご覧いただけますと幸いです。
Photoset大好き
PhotosetはTumblr上の同一記事内に複数画像を投稿する組写真機能。投稿時、画像を縦横 自由なレイアウトに配置できる点が便利で気に入っているため、Tumblrに記事を投稿する際、このPhotosetを多用している。
欠点を挙げるとすれば、Photosetに限らず、画像付の記事にはTumblr標準機能の制約としてタイトルリンクを付けることができない点と、レンダリングが若干遅くページ描画がもっさりしてしまう点。前者については、疑似的なタイトルリンクを付与するJavaScriptのカスタマイズロジックをテンプレート上に組み込みことで補う旨を以前 紹介した。
ページデザイン変更に合わせて
さて、昨年12月にサイトのIndexページのデザインを刷新。(考えが稚拙だが)今どきのブログっぽくレスポンシブなタイル調のデザインを採用してみた。この際に3×2、または2×3のタイルレイアウトを実現するため、1ページ辺りの記事数を6件に増やしたが、結果 顕著化してしまったのがPhotosetの描画の遅さ。
Tumblr標準の動き(テンプレート開発用の独自タグを使った動き)として、Photosetは画面上に直接 画像が描画されるのではなく、別に定義された組写真ページを画面上のインフレームに読み込み、表示するよう実装されている。このインフレームへの読み込みがお世辞にも速いとは言えず、ページがもたつく原因となっていた。1件だけでももたつくこの処理が、Indexページ(6件の記事を表示)では、最大6回 走るため…
他、技術的な問題として、
- インフレームで挿入されるが故に、細かな表示制御がし辛い
- モバイルブラウザによってインフレームの解釈がまちまちな部分がありページ崩れが頻発する
見栄えという観点からは、
- タイル状に縮小表示した際、画像1枚1枚が小さくなりすぎて見にくい
- Photosetに含まれる画像の枚数・レイアウトが記事ごとにバラバラなので高さを統一が難しく、ガタガタになってしまう
などなど、Photosetにまつわる様々な課題が浮上してしまった。
ブログの記事としてPhotosetの利用を維持したまま、Indexページに関わるこれらの課題を解消したい。そこで、問題の元凶であるPhotoset表示をIndexページから取り除き、代わりにPhotosetから任意の1枚の画像を抜き出し、アイキャッチとして表示する方法を模索した(個別パーマリンクページ上ではこれまで通りPhotosetの形で表示させる)。模索した結果、前回同様 Tumblr標準の独自タグとJavaScriptのカスタマイズロジックの組み合わせで、これを実現することに成功した。
実現方法
Photoset出力用独自タグ {Photoset}
を使用せず、{block:Photos}{/block:Photos}
タグを使用する。このblock内では単一画像出力用の {block:Photo}
と同一のタグを使用可能。そのため、Photosetに含まれる画像を単一画像同様の形(インフレームではなく、直接画面上にimgタグとして記述される形)で連続して出力させることができる。
このままでは、すべての画像が縦一列に並んでしまうため、アイキャッチとして使用する1枚を除き、残りを非表示(display:none
)に切替える。
この際、どの画像をアイキャッチに使用するか、エントリのフレンドリーURLで指定するようにしている。具体的には投稿時に設定するフレンドリーURLの末尾に何枚目の画像をアイキャッチに使用するかを表す識別子 pnX
を付与する。
- 例) 高幡不動尊2018の2枚の画像をアイキャッチとする場合、フレンドURLに「高幡不動尊2018pn2」と指定
画面描画時、JavaScriptのロジックは、URL末尾の識別子を拾い、指定されたインデックス番号(Xの部分)以外の画像のプロパティを非表示に書き換える。これで指定したアイキャッチのみが表示されるようになる。
サンプルコード
サンプルコードとしてPhotosetの出力部分(HTML)とアイキャッチ以外を非表示化するFunction(JavaScript)を記載する。
HTML
<!-- Start of Photoset Entry -->
{block:Photoset}
{block:Photos}
<!-- 画像単位で繰り返し出力されるブロック -->
<div class="item_cnt1" name="{PostID}">
<img src="%7BPhotoURL-250%7D" border="0" alt="{PhotoAlt}">
</div>
<!-- 画像単位で繰り返し出力されるブロック -->
{/block:Photos}
<!-- アイキャッチ画像以外を非表示化するロジック呼出 -->
<script language="JavaScript">
hideIndexImage("{PostID}", "{Permalink}", "{PhotoCount}");
</script>
{/block:Photoset}
<!-- End of Photoset Entry -->
JavaScript
<script language="JavaScript">
// -----------------------------------------
// HideIndexImage
//
// name:画像が出力されるdivブロックのname
// url:アイキャッチ画像が指定されたURL
// count:Photosetに含まれる画像枚数
// -----------------------------------------
function hideIndexImage(name, url, count)
{
// URLからアイキャッチに使用する画像のインデックス番号を取得
var splitStr = "pn";
var params = url.split(splitStr);
photoNo = Number(params[params.length-1]);
// URLで指定されたインデックス番号の整合性チェック
if(!photoNo > 0 || photoNo > count)
{
// 指定されたインデックス番号が不正値の場合、1枚目の指定する
photoNo = 1;
}
// 画像が設定されているブロックのArrayを取得
var cnts = document.getElementsByName(name);
// 画像が設定されているブロックArrayをループ
for(var i = 0; i < cnts.length; i++)
{
// インデックスがアイキャッチ使用画像のインデックスと一致する場合
if(i == photoNo - 1 )
{
continue;
}
// 上記以外の場合は、ブロックごと非表示にする
cnts[i].setAttribute('style', 'display:none');
}
}
</script>
終わりに
Photosetに含まれる画像の展開後、指定されたもの以外を非表示にして、アイキャッチ画像画像のみをIndexページに表示する機能をJavaScriptロジックで実現した。一度画像をすべて展開した後に非表示化しているため、表示しない画像まで一度読み込むという無駄があるものの、インフレームでPhotosetを読み込むよりは負荷が小さいように感じる。
最後に、例によってこの実装はあくまでWEBブラウザの画面上に描画された内容をテーマ上のJavaScriptロジックで書き換えているだけなので、カスタマイズしたテーマが適用されないTumblrアプリや標準モバイルテーマ上では機能しないのでご注意。