Bloggerテンプレート自作 #8:記事リストを作る
前回の「メイン部分をページタイプで条件分岐させる」に引き続き、今回は「記事リストを作る」を実践してみようと思う。
記事リストは、トップページ、ラベルページ、アーカイブページで表示される投稿のリストのこと。このデザインは完成しているので、HTMLとCSSでデザイン通りに再現すればいいだけ。というわけで、今回は記事リストの HTML、CSS、レスポンシブ設定までの制作過程をまとめることにする。
作業工程
Font Awesome アイコン をつかえるようにする
<head>
<!-- Font Awesome CDN -->
<link href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" rel="stylesheet" />
<!-- Font Awesome CDN 旧バージョン -->
<link href='//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css' rel='stylesheet' />
</head>
<!-- Font Awesome CDN -->
<link href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" rel="stylesheet" />
<!-- Font Awesome CDN 旧バージョン -->
<link href='//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css' rel='stylesheet' />
</head>
結論から言えば、<head>タグのどこかに上記のコードのいずれかを貼り付ければ使えるようになる。
色んなサイトで使われているアイコンは、Font Awesome というフォントのもの。HTMLに標準搭載しているわけではないので、Bloggerの場合はCDN(Content Delivery Network)経由でファイルを読み込まなければならない。
アイコンの使い方は、HTMLの場合は <i class="fa アイコン名"></i> と記述し、CSSのcontentで使う場合は font-family: "Font Awesome 5 Free"; content: 'アイコンコード'; font-weight: 数値; とセレクタ内に記述する。アイコンは回転させたり、重ねて表示したりできるので、色々と面白い使い方もできる。
詳しい使い方やアイコンの種類は下記のサイトが参考にすると分かりやすい。
メイン部分にHTMLを記述する
<!-- ページタイプの条件分岐 -->
<b:switch var='data:blog.pageType'>
<!-- 個別記事の時 -->
<b:case value="item" />
<div>個別記事</div>
<!-- 固定ページの時 -->
<b:case value="static_page" />
<div>固定ページ</div>
<!-- それ以外 -->
<b:default />
<b:loop var='post' values='data:posts'>
<!-- 記事リストを読み込む -->
<b:include name='articles' />
</b:loop>
</b:switch>
</b:includable>
<!-- 記事リスト -->
<b:includable id='articles'>
<div class="articles-area">
<h2>
<a expr:href='data:post.url'>
<data:post.title /></a>
</h2>
<div class="article-post-wrap">
<!-- サムネイル -->
<div class='article-thumbnail'>
<!-- 記事に画像がある場合 -->
<b:if cond='data:post.firstImageUrl'>
<a expr:href='data:post.url'><img expr:src='data:post.firstImageUrl' /></a>
<!-- 記事に画像が無い場合 -->
<b:else />
<a expr:href='data:post.url'><img
src="代替サムネイルのURL" /></a>
</b:if>
</div>
<div class="article-post-area">
<div class="article-info-area">
<i class="fa fa-calendar" aria-hidden="true"></i>
<div class="article-post-date">
<data:post.date />
</div>
<div class="article-post-tag">
<b:if cond='data:post.labels'>
<i class="fa fa-tag" aria-hidden="true"></i>
<b:loop values='data:post.labels' var='label'>
<a expr:href='data:label.url + "_comment-editor-toggle-link"' property='v:title' rel='v:url'>
<data:label.name /></a>
</b:loop>
<b:else/>
</b:if>
</div>
</div>
<!-- 記事の要約 -->
<div class='post-snippet'>
<b:eval expr='data:post.body snippet {length: 110, links: false, linebreaks: false, ellipsis: true}' />
</div>
<div class="read-more">
<a expr:href='data:post.url'>続きを読む</a>
</div>
</div>
</div>
</div>
</b:includable>
<b:switch var='data:blog.pageType'>
<!-- 個別記事の時 -->
<b:case value="item" />
<div>個別記事</div>
<!-- 固定ページの時 -->
<b:case value="static_page" />
<div>固定ページ</div>
<!-- それ以外 -->
<b:default />
<b:loop var='post' values='data:posts'>
<!-- 記事リストを読み込む -->
<b:include name='articles' />
</b:loop>
</b:switch>
</b:includable>
<!-- 記事リスト -->
<b:includable id='articles'>
<div class="articles-area">
<h2>
<a expr:href='data:post.url'>
<data:post.title /></a>
</h2>
<div class="article-post-wrap">
<!-- サムネイル -->
<div class='article-thumbnail'>
<!-- 記事に画像がある場合 -->
<b:if cond='data:post.firstImageUrl'>
<a expr:href='data:post.url'><img expr:src='data:post.firstImageUrl' /></a>
<!-- 記事に画像が無い場合 -->
<b:else />
<a expr:href='data:post.url'><img
src="代替サムネイルのURL" /></a>
</b:if>
</div>
<div class="article-post-area">
<div class="article-info-area">
<i class="fa fa-calendar" aria-hidden="true"></i>
<div class="article-post-date">
<data:post.date />
</div>
<div class="article-post-tag">
<b:if cond='data:post.labels'>
<i class="fa fa-tag" aria-hidden="true"></i>
<b:loop values='data:post.labels' var='label'>
<a expr:href='data:label.url + "_comment-editor-toggle-link"' property='v:title' rel='v:url'>
<data:label.name /></a>
</b:loop>
<b:else/>
</b:if>
</div>
</div>
<!-- 記事の要約 -->
<div class='post-snippet'>
<b:eval expr='data:post.body snippet {length: 110, links: false, linebreaks: false, ellipsis: true}' />
</div>
<div class="read-more">
<a expr:href='data:post.url'>続きを読む</a>
</div>
</div>
</div>
</div>
</b:includable>
記事リストの表示位置は、前回の条件分岐の「それ以外」に該当するので、その位置に読み込ませるようにする。Bloggerは <b:includable> を関数のように使えるので、<b:includable id='articles'> に記事リストのHTMLを整えて、条件分岐の「それ以外」の位置に <b:include name='articles' /> で呼び出すように設定する。
CSSでデザインを整える
/* 記事リスト
---------------------------------------------------------------------------- */
/* 記事リスト全体 */
.articles-area {
background: #fff;
margin-bottom: 20px;
}
/* 投稿タイトル */
.articles-area h2 {
font-size: 18px;
letter-spacing: 2px;
margin: 0;
}
.articles-area h2 a {
display: block;
text-decoration: none;
font-weight: bold;
background: #333;
color: #fff;
padding: 5px 15px;
}
.articles-area a:hover {
opacity: 0.6;
}
.article-post-wrap {
display: flex;
position: relative;
height: 200px;
padding: 10px;
}
/* サムネイル */
.article-thumbnail {
width: 70%;
margin-right: 15px;
overflow: hidden;
}
.article-thumbnail img {
width: 99%; /* 境界線を表示するため */
height: 99%;
border: solid 1px #ddd;
object-fit: cover;
}
/* サムネイル右のエリア */
.article-post-area {
width: 100%;
height: 100%;
}
.article-info-area {
display: flex;
flex-wrap: wrap;
align-items: baseline;
font-size: 13px;
color: #666;
height: 24px;
overflow: hidden; /* タグがはみ出ると消えるようにする */
}
.article-info-area a {
text-decoration: none;
color: #666;
}
.article-post-date {
display: inline-block;
margin-right: 1em;
border-bottom: dashed 1px #666;
margin-bottom: 2px;
}
.article-post-tag a {
display: inline-block;
border-bottom: dashed 1px #666;
padding: 2px 0;
margin-right: 2px;
}
.article-post-tag a:hover {
opacity: 0.6;
}
.fa-calendar {
margin-right: 6px;
}
.fa-tag {
margin-right: 3px;
}
/* 要約文 */
.post-snippet {
font-size: 14px;
line-height: 1.7em;
margin: 15px 0;
height: 108px;
overflow: hidden;
}
.read-more {
font-size: 14px;
}
.read-more a {
display: block;
text-decoration: none;
background: #fbfbfb;
color: #666;
padding: 10px;
text-align: center;
}
.read-more a:hover {
background: #eee;
color: #000;
}
/* レスポンシブ(タブレット縦) */
@media screen and (max-width: 960px) {
.article-post-wrap {
flex-direction: column;
height: auto;
padding: 15px;
}
.article-thumbnail {
width: 100%;
margin-right: 0;
margin-bottom: 5px;
overflow: visible;
}
.article-thumbnail img {
width: 100%;
height: 300px;
}
.article-info-area {
height: auto;
}
.post-snippet {
height: auto;
}
}
---------------------------------------------------------------------------- */
/* 記事リスト全体 */
.articles-area {
background: #fff;
margin-bottom: 20px;
}
/* 投稿タイトル */
.articles-area h2 {
font-size: 18px;
letter-spacing: 2px;
margin: 0;
}
.articles-area h2 a {
display: block;
text-decoration: none;
font-weight: bold;
background: #333;
color: #fff;
padding: 5px 15px;
}
.articles-area a:hover {
opacity: 0.6;
}
.article-post-wrap {
display: flex;
position: relative;
height: 200px;
padding: 10px;
}
/* サムネイル */
.article-thumbnail {
width: 70%;
margin-right: 15px;
overflow: hidden;
}
.article-thumbnail img {
width: 99%; /* 境界線を表示するため */
height: 99%;
border: solid 1px #ddd;
object-fit: cover;
}
/* サムネイル右のエリア */
.article-post-area {
width: 100%;
height: 100%;
}
.article-info-area {
display: flex;
flex-wrap: wrap;
align-items: baseline;
font-size: 13px;
color: #666;
height: 24px;
overflow: hidden; /* タグがはみ出ると消えるようにする */
}
.article-info-area a {
text-decoration: none;
color: #666;
}
.article-post-date {
display: inline-block;
margin-right: 1em;
border-bottom: dashed 1px #666;
margin-bottom: 2px;
}
.article-post-tag a {
display: inline-block;
border-bottom: dashed 1px #666;
padding: 2px 0;
margin-right: 2px;
}
.article-post-tag a:hover {
opacity: 0.6;
}
.fa-calendar {
margin-right: 6px;
}
.fa-tag {
margin-right: 3px;
}
/* 要約文 */
.post-snippet {
font-size: 14px;
line-height: 1.7em;
margin: 15px 0;
height: 108px;
overflow: hidden;
}
.read-more {
font-size: 14px;
}
.read-more a {
display: block;
text-decoration: none;
background: #fbfbfb;
color: #666;
padding: 10px;
text-align: center;
}
.read-more a:hover {
background: #eee;
color: #000;
}
/* レスポンシブ(タブレット縦) */
@media screen and (max-width: 960px) {
.article-post-wrap {
flex-direction: column;
height: auto;
padding: 15px;
}
.article-thumbnail {
width: 100%;
margin-right: 0;
margin-bottom: 5px;
overflow: visible;
}
.article-thumbnail img {
width: 100%;
height: 300px;
}
.article-info-area {
height: auto;
}
.post-snippet {
height: auto;
}
}
上記のようなCSSでデザインを整えると、画像のようなデザインになる。
基本的には投稿タイトル、サムネイル、続きを読むボタンが該当記事へのリンクとなっており、PCでは画像と要約文がヨコ並びに、タブレット縦(スマホ縦)の時に画像と要約文がタテ並びになるような設定になっている。
また、タグ(ラベル)もリンクになっており、クリックすることで該当の記事リストが見られるようになっている。CSSは一応テストはしているものの結構適当に記述したので誤りに注意。
問題点
<data:post.snippet />が読み込めない
記事リスト作成中に最初にぶち当たった壁が <data:post.snippet /> が読み込めないという問題だった。数時間悩みに悩んでやっとたどり着いた原因が「Blogガジェットのバージョン」だった。
この問題の解決方法は <b:widget id='Blog1' type='Blog' ~ version='1'> とすること。省略した場合は version='2' になり、<data:post.snippet /> が非対応になるっぽい。ちなみに version='2' では <data:post.snippets.short /> が同様の動きをするコードになる。
Bloggerはバージョンアップの際に関数が非対応になることがよくあるみたいだが、公式ドキュメントに説明がない。なので、有志のまとめた情報を頼りに理解しなければならないのがマジで腹立つ、本当にこういうのは止めてほしい。なお、バージョンアップによって文法が変わった関数については下記の記事が参考になる。
・BloggerのBlogウィジェットをバージョン2にする(バグ取りの日々)
snippet()関数を使ってスニペットを自作する
snippet()関数は、要するに読み込んだ文章を要約できる関数のこと。
ざっくり説明すると、以下のような文法で使用することができる。
<b:eval expr='data:post.body snippet {length: 文字数, links: リンクの可否, linebreaks: 改行の可否, ellipsis: …表示の可否}'/>
用例は以下の通り。
<b:eval expr='data:post.body snippet {length: 140, links: false, linebreaks: false, ellipsis: true}'/>
Blogガジェットがversion2で正常に表示されない問題
Blogガジェットは投稿ページを司るガジェットなのだが、version2にすることで最終更新日をJSなしで取得できるなどの利点がある。その一方でversion1で使えていたテンプレートタグが使えなくなるという不具合もある(例えば上記の<data:post.snippet />なんかが該当)。
自分は <data:post.snippet /> の問題解決の過程でversion1で設定したまま制作を続けていたのだが、最終更新日を表示させようと思ってversion2を当てたところ、version1で上手く表示されていたものが読み込み不具合で全く読み込めなくなった。理由はおそらくversion1でのみ対応しているコードを使ってしまっているからだろう。
これを解決すべく奮闘したのだが、version別のテンプレートタグ対応表が公式ドキュメントで公開されていないことや、日本語サイトのversion2の情報の少なさなんかから、公式テンプレートを使わない限り国内ではversion1が主流となっていると判断したことから、テンプレート自体はガジェットのデフォルトバージョンがversion2になるよう指定しているものの、version1での制作を続行することに決めた。
というわけで、Blogガジェットについては今後もversion1での説明になります。
version違いによるテンプレートの更新エラーについて
結論から言えば「設定ファイルのバージョン違い」が原因である可能性が高い。
自分は「VS CodeでBloggerテンプレートを編集すると楽かも!?」で示したように、表示させるコンテンツを指定したコードのみを記述したxmlファイルをアップロード、もしくはテンプレートエディタに直接貼り付ける方法で自作テンプレートの制作を行っている。
しかし、この方法で作成したコードは、実際にテンプレートを当てた後に作成されるコードとは内容が異なる。というのも、Bloggerでは指定したガジェットのバージョンによって適切な設定コードが読み込まれる仕様になっている。よって、作成したxmlとテンプレートのバックアップから取得したxmlでは "読み込まれた設定コード分" の違いが出ていることが分かる(テンプレートのバックアップで保存したxmlの中身が異様に複雑なのはそのため)。
また、Bloggerは "テンプレート変更以前の設定を保持する" といった特性があるので、Bloggerのテンプレートエディタ上でversionの指定をversion1からversion2に書き換えたとしても、読み込まれた設定コードがversion1のままなら、データ更新後に自動的にversion1に書き換えられてしまう。
つまり、Blogガジェットをversion1からversion2に書き換えたい場合は "設定コードごと" 書き換えなければ上手く行かないということ。そのため、既にBlogガジェットがversion2で読み込まれたブログに対して、version1で作成されたBlogガジェットを持つテンプレートを当てると、読み込みエラーで何も表示されないという不具合が起こったりする。
そういうときは、一旦 Blogガジェットがversion1で作成された完成品のテンプレートを当ててから、再度version1で作成したテンプレートを当てると上手く読み込むことができる。その理由は、Blogガジェットの設定ファイルがversion1だから。逆に上手く行かないときは設定ファイルがversion違いであることを疑うべき。
課題
検索向け説明を表示させたい
Bloggerにはメタタグで検索向け説明を設定することができる。色々調べてみたところ、これは data:blog.metaDescription に格納されるらしいのだが、これを呼び出す方法がどうしても見つからない。
WordPressでは、検索向け説明が設定されている場合はこれを表示し、そうでない場合は記事の要約文が表示される設定になっている。そっちの方が何かと便利なので、Bloggerでも条件分岐で同様の設定を再現したかったのだが、これに関する情報がなかなか見つからない。なので、分かる人はぜひコメントで教えてほしい。
スポンサーリンク
スポンサーリンク
コメント
0 件のコメント :
コメントを投稿