2016年9月6日火曜日

テンプレートの仕組みと機能 ~Blogger テンプレートを作るよ! (3)~

こんにちはー!

前回は、テンプレートの正体が HTML を拡張した XML だということが分かりました。

( 前回: 『テンプレートの正体 ~Blogger テンプレートを作るよ! (2)~』 )

テンプレートの中身について詳しいことは、 Blogger ヘルプに書いてありました。数日かけてじっくり研究してみたので、分かったことを書いていきますね。

今回の記事はとても長いので、ご注意ください。

リンク: 『ブログの外観の変更』 Blogger ヘルプ
< https://support.google.com/blogger/topic/6321969?hl=ja&amp;ref_topic=3369773 >




テンプレートの仕組み


テンプレートの実体は、 Blogger 独自の要素を省けば内容が無い HTML ファイルだと言えます。

本文などの内容はテンプレートとは別にサーバーに保管されていて、閲覧者が HTML ファイルにアクセスしたときにテンプレートの中に内容を差し込んでくれます。 これでようやく中身のある HTML になって、閲覧者の端末に送られます。

トップページも各記事のページも、検索結果のページもアーカイブのページも、ブログ内のあらゆるページは1つのテンプレートに対して適用するデータを変えただけで作られています。

それを実現するために、HTML 内のどこに何のデータを差し込むかや、このデータをどんな文書構造にするかなどを指定するのが、 Blogger 独自の要素というわけです。

<b:~~> と要素名の先頭に b: や data: がついているものがそれです。また、普通の HTML 要素でも属性名の先頭に expr: を付けることができる、という独自の拡張がされています。
Blogger の仕組み
ブログのページにアクセスすると、Blogger テンプレートにデータを適用して HTML を作る

テンプレートの機能


Blogger テンプレートの独自の要素には、それぞれ機能があります。それを順に解説していこうと思います。

<b:skin> 外観のカスタマイズをする場所


<head> 要素の中に <b:skin> という要素があります。

この中には、ページの見た目を決める css を記入します。実際に中をのぞいてみると、以下のように css の前に <Group> 要素や <Variable> 要素という独自の要素も含まれていたりします。

<Group description="Links" selector=".main-inner">
  <Variable name="link.color" description="Link Color" type="color" default="#888888" value="#3778cd"/>
  <Variable name="link.visited.color" description="Visited Color" type="color" default="#444444" value="#4d469c"/>
  <Variable name="link.hover.color" description="Hover Color" type="color" default="#cccccc" value="#3778cd"/>
</Group>
a:link {
 color: $(link.color);
}
a:visited {
 color: $(link.visited.color);
}
a:hover {
 color: $(link.hover.color);
}

<Variable> 要素は変数 (データに名前を付けたもの) です。 name 属性に書いた内容を css の $() の中に入れると、テンプレートを HTML 化する時に、その部分が変数の value 属性の値 (無ければ default 属性の値) に置き換わります。この要素自体は HTML には出力されません。

ここは <![CDATA[ ]]> の中だからか、<Variable> にも <Group> にも b: が付いていませんね。

a:link {
 color: #3778cd;
}
a:visited {
 color: #4d469c;
}
a:hover {
 color: #3778cd;
}

なぜわざわざ変数を使うのかというと、おそらく一番大きな理由は、テンプレートデザイナーで簡単に値を変更することができるようになるからです。

[上級者向け] タブを選択するとテンプレート内の <Group> がリスト化され、
それを選択するとそのグループ内の <Variable> の値を変更できるようになる。
[ブログに適用] ボタンを押すと、変更した値がテンプレートの value 属性に記入される。

ただし、ここで設定できるのは色とフォントのみで、長さ等の変数はテンプレートデザイナーでは表示されません。そういうのも設定できるようになると嬉しいんですけどね。

上記以外に変数を使う理由は、たぶんですが
  • css を直接書き換えると表示が崩れる可能性があるため、変更しても表示が崩れなさそうな値を変数にして、 「この値は変更しても大丈夫だよ」 という意思表示のつもり
  • 将来、長さなどもテンプレートデザイナーで変更できるようになった時のことを見越して、今のうちに変数にしておいた
  • 同じ値を複数個所に使う時に、一か所変更すれば全てに適用するようにするため
とか、そういうことだと思います。

変数を使わない css も、特に理由がなければ <b:skin> の中に書いておこうと思います。

なお、モバイル表示のデザインだけを変更したいときは .mobile .main-inner のように mobile クラスの子孫要素として指定するようです。

<b:template-skin> Blogger の基本的な機能と連携する css


<b:skin> 要素に続いて <b:template-skin> という要素もあります。

<b:skin> が変数をユーザーが好きに定義することができて、ブログの外観を記述する場所であるのに対し、 <b:template-skin> は Blogger の機能と密接に関わる情報を記述する場所なようです。

<b:skin> の時とは違い、変数の定義には <b:variable> という要素を使用します。<b:skin> の時とは違い、ここに変数を追加したりしてもテンプレートデザイナーで設定できる項目が増えたりすることはありません。予め Blogger が定めている変数だけが使用されます。

テンプレートデザイナーの [幅を調整] タブを開くと、ブログ全体の幅とサイドバーの幅を指定できます。 この変更した値が <b:variable> の各変数に格納されます。

変数の使用方法は <b:skin> と同じで、 $() の中に変数名を入れます。

また、この中ではレイアウト設定画面での表示についての調整も行います。

レイアウトを調整したい場合は、変えたい要素を #layout .content-outer のように layout の下位要素として指定します。

例えば
#layout .content-outer {
  display: none;
}
と content-outer 要素を見えなくするような記述すると、ブログの表示ではきちんと存在しているコンテンツ部分が、レイアウト設定画面では見えなくなりました。

コンテンツ部分が消えたレイアウト設定画面
あるはずの cross-column などが見えなくなった

レイアウト設定画面は何もしなければブログの実際の表示に近いレイアウトになってくれますのであまり使用することはないかと思います。どうしても必要なときにはここでレイアウト設定画面を調整できる、と覚えておくと良さそうです。

<data:~~ /> データを差し込む


ブログの情報、記事の本文、ガジェットのデータなどは、全て変数の形でテンプレートからアクセスすることができます。

例えばブログのタイトルであれば、 "blog.title" という名前の変数が用意されています。

その変数の中身をそのまま HTML の中に表示したいときに、<data:変数名 /> というタグを使用します。

参考:『レイアウト データ タグ』 Blogger ヘルプ
https://support.google.com/blogger/answer/47270 >

例えば、テンプレート内に
<h1>
<data:blog.title/>へようこそ!!
</h1>
と書かれていたとします。

このテンプレートが使用された当ブログにアクセスすると、
<h1>
まどうぐ工房へようこそ!!
</h1>
という HTML に変形しています。

また、<data:skin.vars.link_color/> のように、skin.vars. を使うと <b:skin> 要素にある <Variable> 要素の値を使用することもできます。使用したい変数の、 name 属性の値に含まれているドットを全てアンダースコアに置き換えた名前を指定します。

<b:eval> 計算結果を差し込む


時には、データをそのまま出力するのではなく、計算した結果を出力したくなることもあります。

その場合には <b:eval expr="" /> 要素を使います。 expr 属性に計算したい式を書いておくと、計算結果が出力されます。

これを使って、上記の例は以下のようにも表現することができます。
<h1>
<b:eval expr='data:blog.title + "へようこそ!!"'/>
</h1>
この方法では、ブログのタイトルと 「へようこそ」 という文字列を結合して、それを出力しています。

式の中で変数を使用する際も、変数名の前に data: を付ける必要があります。また、式の中で文字列を表現する際はダブルクォーテーションで囲う必要があります。試しにシングルクォーテーションで囲ったらエラーになりました。

属性値をダブルクォーテーションで囲っている場合は文字列のダブルクォーテーションと混同してしまいますが、その場合は代わりに &quot; を使って以下のようにすると対策できます。

<h1>
<b:eval expr="data:blog.title + &quot;へようこそ!!&quot;"/>
</h1>

<b:if> <b:switch> 内容を切り替える


ブログのトップページだけちょっと特殊なレイアウトにしたりなど、特定の条件でだけレイアウトを変えたいと思うこともあるかと思います。

そういうときに使用するのが <b:if> や <b:switch> です。

例として、以下のように使用します。

<b:switch var='data:blog.pageType'>
  <b:case value='static_page' />
  このページはブログのページです。
  <b:case value='item' />
  このページはブログの記事です。
  <b:case value='archive' />
  このページはブログのアーカイブです。
  <b:case value='index' />
  <b:if cond='data:blog.url == data:blog.homepageUrl'>
    このページはブログのトップページです。
    <b:else />
    このページはブログの索引です。
  </b:if>
  <b:default />
  このページは <data:blog.pageType/> です。
</b:switch>

<b:switch> 値によって内容を切り替える


<b:switch> は、指定した変数にどんな値が入っているかによって内容を切り替える機能を持った要素です。 <b:case> や <b:default> と共に使用します。

変数の指定には var 属性を使用します。

<b:case> は、 『値が○○の場合、この内容を出力する』 という意味で使用します。自分の要素の直後から、次の <b:case> か <b:default> が来るまで、来なければ </b:switch> の直前までが出力する内容になります。

値の指定には value 属性を使用します。

<b:default> は、 『いずれでもない場合、この内容を出力する』 という意味で使用します。一般的には全ての <b:case> を列挙した後に付けるようで、 </b:switch> の直前までが出力する内容になります。

上記の例では、 blog.pageType という変数の中身が何かによって、出力される言葉が変わるようになっています。私が調べた限りでは、この変数には static_page 、 item 、 archive 、 index のどれかが入っているようです。もし私の知らない値が入っていたときのための保険として <b:default> も入れています。

<b:if> 条件によって内容を切り替える


<b:if> は条件式が真か偽かで内容を切り替える機能を持った要素です。単独で使用するか、<b:elseif> や <b:else> と組み合わせて使用します。

条件式は cond 属性で指定します。

基本的には 『この条件式が真の場合、この内容を出力する』 という意味で使われます。 ただし、<b:elseif> や <b:else> と組み合わせて使用する際は、最初の <b:elseif> か <b:else> が来るまでが真の場合に出力する内容になり、それ以降は偽の場合となります。

<b:elseif> は、 『そうではなくて、かつこの条件式が真の場合、この内容を出力する』 という意味で使用します。自分の要素の直後から、次の <b:elseif> か <b:else> が来るまで、来なければ </b:if> の直前までが出力する内容になります。

条件式は cond 属性で指定します。

<b:else> は 『そうでなければ、この内容を出力する』 という意味で使用されます。一般的には全ての <b:elseif> を列挙した後に付けるようで、 </b:if> の直前までが出力する内容になります。

上記の例では、今の URL がブログのトップページの URL かどうかを調べ、 「このページはブログのトップページです」 と表示するか 「このページはブログの索引です」 と表示するかを変えています。

<b:includable> <b:include> 部品の定義と使用


テンプレートを作るとき、同じ部品を複数個所に使いまわしたいことがあります。そういう時のために、予め部品を定義する機能と、定義した部品を差し込む機能があります。

部品の定義に使うのが <b:includable id="~~"> 要素です。id 属性の値が main のものだけは特殊な意味がありますが、それ以外のものは部品の定義として扱われ、後述する <b:include> を使わない限り出力されません。

部品を使用したい場所に使うのが <b:include name="~~"> 要素です。紛らわしいですが、使いたい部品の id 属性の値を name 属性に指定します。

これによって、<b:include> がある場所に <b:includable> で定義した部品が差し込まれます。

このとき <b:include> から <b:includable> にデータを渡すこともできます。データを受け取って表示する部品を定義しておいて、部品を差し込む時にそのデータを渡せば、一つの部品を使いまわしていろんなデータを表示することができます。

受け取ったデータを入れる変数を <b:includable> の var 属性で名付けます。受け取ったデータを内部で使う時は、他の変数と同様に <data:~~ /> タグなどを使用します。

そして、渡すデータを <b:include> の data 属性に指定します。

また、特定の条件の時だけ部品を差し込みたい時に、 <b:if> を省略できる機能もあります。 cond 属性に条件式を入れると、条件が真のときだけ部品を差し込みます。

さて、先程 <b:includable id="main"> は特殊な意味があると書きました。これは、後述するガジェットのテンプレートを書く際に利用します。この要素の中身は部品として使用できず、その場に出力されます。

ガジェットの直下には <b:includable> 要素しか使えませんので、ガジェットの中身を定義するためには必ず <b:includable> を使用し、そのうちの一つは id 属性の値が "main" でなければいけません。

<b:loop> 内容を繰り返す


リスト形式のガジェットなど、複数個の同じ形式のデータが連続している場面では <b:loop> が使われます。

例えば、以下のようなテンプレートがあったとします。
<ul>
<b:loop var="post" values="data:posts" index="i">
<li>第<b:eval expr="data:i + 1"/>回:『<data:post.title/>』</li>
</b:loop>
</ul>

<b:loop> は 『データリストの中身の数だけ、内容を繰り返す』 という意味です。ただ、全く同じ HTML を繰り返すだけではありません。

上記のテンプレートで、 data:posts の中身が当ブログの制作日誌のリストだったら、 HTML は以下のようになります。
<ul>
<li>第1回:『Blogger テンプレートを作るよ!』</li>
<li>第2回:『テンプレートの正体 ~Blogger テンプレートを作るよ! (2)~』</li>
</ul>
内容を差し込むとき、繰り返した回数がカウントされていきます。そして、 values 属性で指定したデータリストの 『カウントされた回数』 番目のデータが var 属性で名付けた変数に入っているのです。

ですので、ループは 『データを順番に入れ替えながら1つのテンプレートを繰り返す』 ということです。

index 属性はループした回数をテンプレート内で使用する場合に、その回数を入れる変数名を指定する時に使います。使わないのであれば、省略することができます。

<b:section> ガジェットを設置するスペースを確保する


もう一つの大きな仕組みとして、レイアウトを決める <b:section> という要素があります。HTMLのセクション要素とは違い、これはレイアウト設定画面でガジェットを設置するためのスペースという機能を持っていて、レイアウト設定画面で表示される 「cross-column」 とかが <b:section> です。

テンプレート内で <b:section> を追加したり移動させたりすると、レイアウト設定画面も変わります。 ( [F5] で更新しないと反映されない )

この時に表示される枠の名前は id 属性の値です。また、この要素は HTML 化すると <div> 要素に変化し、 <div> の時の id 属性と class 属性には <b:section> の時のそれぞれの属性の値が使用されます。また、 class 属性には 'section' というクラス名も追加されます。

レイアウトの都合上、追加できるガジェットの数を限定したい場合には maxwidgets 属性に上限を指定することができます。また、新たにガジェットの追加して欲しくないときは showaddelement 属性に 'no' と記入します。

growth 属性というものもあり、通常は vertical でガジェットが縦に並ぶのですが、 horizontal を指定すると横に並ぶらしいです。

<b:widget> 追加されたガジェットのテンプレート(ウィジェット)


レイアウト設定画面で追加することができるガジェットも、本文と同様にテンプレートとデータに分かれて保存されています。レイアウト設定画面で追加したガジェットのテンプレートは、先程説明した <b:section> 内に追加されます。それが <b:widget> 要素です。

Blogger ヘルプ内では名前がガジェットだったりウィジェットだったりして紛らわしいですが、とりあえずは同じものと思って差し支えなさそうです。

どう使い分けてよいかわかりにくいので、このブログでは、とりあえずレイアウト設定画面で追加する 『データとテンプレートのセット』 をガジェットと呼び、ガジェットのテンプレート部分である 『<b:widget> 要素』 をウィジェットもしくは <b:widget> と呼ぶことにします。

レイアウト設定画面で表示される時の名前は title 属性の値です。 title 属性が無ければ id 属性の値が表示されます。 id 属性は変更してはいけないらしいので、名前を変えたければ title 属性を使用しましょう。

また、この要素は HTML 化すると <div> 要素に変化し、 <div> の id 属性には <b:widget> の id 属性の値がそのまま使用されます。<div> の class 属性には <b:widget> の type 属性の値と 'widget' というクラス名が使用されます。

<b:widget> には type 属性が必須となっていて、これは Blogger に登録されている値以外は指定できないようです。id 同様、直接書き換えることはないと思いますので、これはそんなに気にしなくて良さそうですね。

レイアウト設定画面で他のセクションに移動させたくない、削除されたくないガジェットは locked 属性の値を yes にすると移動も削除もできなくなります。

特定のページ種別でだけウィジェットを表示したければ、 pageType 属性を使います。指定できる値は以下の通りです。

  • 'all' : 全てのページ種別で表示される (標準)
  • 'archive' : アーカイブページでのみ表示される
  • 'main' : トップページや検索結果ページでのみ表示される
  • 'item' : 記事のページでのみ表示される


モバイル表示の時に表示するか否かを指定する mobile 属性もあります。指定できる値は以下の通りです。

  • 'default' : Header, Blog, Profile, PageList, AdSense, Attribution のウィジェットだけ表示する
  • 'yes' : モバイルでも表示する
  • 'no' : モバイルでは表示しない
  • 'only' : モバイルでのみ表示する

<b:section-contents> セクションのガジェット (ウィジェット) を定義する


※ これはヘルプにも書かれていない機能なので、あまり積極的に使わない方が無難かもしれないです。

サイドバーやフッターの <b:section> は、テンプレート内部に直接存在していません。これらのセクションは、後述する <macro:~~> によって、HTML化する時に新たに追加されます。

しかし、テンプレート内に <b:section> が存在しないのなら、その中にあるはずのウィジェットをどこに記述すればいいか……という問題に対して使用されるのが、この <b:section-contents> 要素です。

<b:section> に直接 <widget> を追加せずに、別の場所に記述することができる機能です。デフォルトのテンプレートでは、サイドバーやフッターに追加されたウィジェットがこの要素に入っています。

id 属性に、ウィジェットを挿入する先の <b:section> の id 属性の値を記入すると、HTML 解釈時にそこにウィジェットが挿入されるようです。

<macro:~~> テンプレートのマクロ


※ これはヘルプにも書かれていない機能なので、あまり積極的に使わない方が無難かもしれないです。

先ほども書きましたが、サイドバーやフッターの <b:section> は、テンプレート内部に直接存在しているわけではありません。しかし、HTML 化して表示する際には存在しています。

どういうことかというと、テンプレートを HTML 化するときになって、今まで説明した Blogger テンプレートの各機能が実行されるよりも前に、セクションが自動的に作成される仕組みになっているからです。

各要素を解釈する前に実行される、もう一つのテンプレートをマクロと言い、 macro: で始まる要素で指定されます。見た目も機能も今まで紹介したものに似ていて、大体は b: を macro: に変えただけのようにも見えます。

テンプレートとマクロの対応表
テンプレートマクロ
<b:includable><macro:includable>
<b:include><macro:include>
<b:if><macro:if>
expr:~~mexpr:~~
<macro:param>

使用されている中で前例のないものは <macro:param> 要素ですね。

これはどうやら、<b:include> でいう data 属性に相当するもののようです。 <b:include> では一つしかデータを渡せませんでしたが、 <macro:include> の時は要素の中に <macro:param> を複数並べることで複数のデータを渡すことができるようになっているようです。

<macro:includable> の var 属性で受け取ったそのデータを使う時は、「data:var名.param名」 と指名します。

以上で、調べたテンプレートの機能は全部です。むう、つかれた。

0 件のコメント :

コメントを投稿