カテゴリー別アーカイブ: 汎用テク覚え書き

Search RegexプラグインでWordPress投稿を正規表現検索置換

※今回の記事の内容、特に自己責任で試してね。投稿記事の破損についてなど一切の責任は負いません。

そもそもの問題

過去にこのような投稿を上げていた。

小ネタ:WordPressがHTML5に対応して、過去記事の見出しに困る

WordPressがHTML5に対応した際、それまで記事部分での見出しレベルトップはh3であったのが、h2に繰り上げとなった。その影響で過去投稿をいちいち引っ張り出してきて、手動で修正するのが面倒だよねという話。
それに対して、見出しレベルを変更するこんなプラグインもありますよと紹介していたのがこの投稿。

WordPressテーマ変更に伴う記事のルート見出しレベルの変動を吸収するプラグイン WP hn Convert

記事内でも書いている通り、このプラグインを使ってWordPress関数the_content()をリプレースする形だと、以降も見出しトップレベルをh3にして投稿をし続けなければならず、この時は採用を断念していた。結局、見出しトップレベルの問題は全投稿の見出しを手動で書き換えることで解決した。

そんな貴方にオススメ。Search Regexプラグイン!

3年くらい経って、解決法に気付いた。全投稿を正規表現を用いて検索・置換するプラグインがあれば、この問題は容易に解決することが出来たのではないだろうか。そういう痒いところに手が届くプラグイン、きっとあるはず。
ありました。それがSearch Regexプラグイン。早速インストールして、具体的な指定方法を考えてみよう。

こんな感じで、インストール後は"ツール"メニューに出現

こんな感じで、インストール後は”ツール”メニューに出現

まず何より、左下にあるRegexチェックボックスにチェックを入れよう。これに気付かず、しばらく格闘してしまった(ココの表示がボールドになっているの、おかしくない?)。Search patternフィールドに検索文字列を、Replace patternフィールドに置換文字列を入力する。Replaceボタンを押すと、置換例を表示してくれるけれどデータベースに反映はしない。Replace & Saveボタンは押すと取り返しのつかないボタン。データベースに即時反映するヤツなので、前者のボタンで置換例を見て微調整しつつ、上手くいっているようだったら後者のボタンを押すようにしよう。

正規表現を使って見出しレベルを一段ずつ上げる

では実際にやってみよう。見出しレベルが一段ずつ上がるので、たとえば先にh6を置換してh5にして…というように下からやっていってしまうと、最終的に全部h2になってしまう(笑)。h3をh2に、その次にh4をh3に…という順序で手をつけよう。

 
Search pattern:/<h3>(.*?)<\/h3>/
Replace pattern:<h2>$1</h2>

このようなパターンで、h3の見出しが見出し語そのままh2に昇格する。Replace pattern側の$1というのが参照文字(preg_replaceの解説なども参照)で、h3タグに挟まれた文字を一旦預かり、置換パターン側に展開してくれる。もし預かる箇所が2ヶ所以上だったら、$2、$3…という形で指定が出来る。ちなみに$0にはh3タグも含んだ文字列全体が格納されている。

Search Regexによる置換イメージ

Search Regexによる置換イメージ

この置換を、次はh4…とどんどんやっていけば良い。

自サイトの内部リンクからtarget=”_blank”を外す

次の課題。昔のWEB制作ではひたすらリンクにtarget=”_blank”を付与していたものである。とりあえず付けられるなら付けておくか、といった感覚で、WordPressのエディタでもチェックボックス1つで付けられてしまうものだからかかさず付けていた。
それが時代の変遷とともに訪問者の閲覧環境がモバイルデバイス中心になると、モバイルブラウザ上でウィンドウやタブを何枚も開くことは難しく、即ユーザビリティの低下となるため、頻繁にtarget=”_blank”を使うサイトは忌避されユーザの離脱率が高くなるという問題が顕在化した。そのため、最近は内部リンクについてはtarget=”_blank”をつけないページ作りが正解になっているらしい。
では、過去の投稿の内部リンクからtarget=”_blank”をはがすパターンについて考えてみよう。

 
Search pattern:/<a\shref="http:\/\/akisi\.tabiyaku\.net([^>]*?)\starget="_blank">/
Replace pattern:<a href="http://akisi.tabiyaku.net$1>

このサイトのアドレスがhttp://akisi.tabiyaku.netから始まるので前方一致に入れているわけで、自身のサイトで流用する場合は適宜自サイトのアドレスに変えて欲しい。また、このパターンはtarget=”_blank”がaタグの最後に来るという性善説で考えているので、流用の際にはそこも注意である。

その他Search Regexの応用例として、Tabnabbing防止にtarget=”_blank”付の外部リンクに自動的にrel=”noopener”を付ける処理を出そうかとも思ったのだけれども、なんだか分岐の可能性が多そうなのでやめました(元々rel属性に何かの値が指定されていた場合など)。我こそはと思う方はやってみて、上手いやり方を教えて下さいな。


W3CのHTML5.1勧告でsection直下h1の見出しレベル自動解釈が無効に?

一応結論だけ先に書いておくと、WEB制作上の影響はほぼ無いのでは?という話。

HTML5と見出しレベルの解釈

HTML5が世に放たれた際に、それまでのHTML4.01ないしXHTML1.0の宣言を行ったページでは不可能であったアウトラインの作り方として、セクション毎にh1を頂点とした独立した見出し階層を作り上げても、ページ全体で自動的に適切な見出しレベルに調整して解釈してくれるというものがあった。
たとえば、下のようなコード。

<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="css/base.css" type="text/css">
<meta name="description" content="サンプル株式会社の商品一覧ページです。">
<meta name="keywords" content="サンプル株式会社,ネットショップ">
<title>当社商品の一覧 | サンプル株式会社</title>
</head>
<body>
<div id="wrapper">
<header>
<h1>サンプル株式会社</h1>
</header>
<div id="main">
<article>
<h1>サンプル株式会社の商品一覧</h1>
<p>当社が取り扱う商品の一覧です。</p>
<ul id="itemlist">
<li>
<article>
<h1>商品A</h1>
<p>さわやかなミントの香りの牛車です(牛は食べられません)</p>
<p>100,000円</p>
<p><a href="http://xxxxxxxx.xxx/item.php?id=1" title="商品Aの商品詳細">>>商品詳細へ</a></p>
</article>
</li><li>
<section>
<h1>商品B</h1>
<p>官位です。これがあれば思いのまま(返品不可)</p>
<p>3,000円</p>
<p><a href="http://xxxxxxxx.xxx/item.php?id=2" title="商品Bの商品詳細">>>商品詳細へ</a></p>
</section>
</li><li>
<section>
<h1>商品C</h1>
<p>古今和歌集です。新版が出たので在庫一掃セールです</p>
<p>16,000円</p>
<p><a href="http://xxxxxxxx.xxx/item.php?id=10" title="商品Cの商品詳細">>>商品詳細へ</a></p>
</section>
</li><li>
<section>
<h1>商品D</h1>
<p>商品説明</p>
<p>100円</p>
<p><a href="http://xxxxxxxx.xxx/item.php?id=15" title="商品Dの商品詳細">>>商品詳細へ</a></p>
</section>
</li></ul>
</article>
<article>
<h1>当社のモットー</h1>
<p>適当な仕事。深刻な社会的被害。</p>
</article>
</div>
<footer>
<p>サンプル株式会社 2012-2017 all rights reserved.</p>
</footer>
</div>
</body>
</html>

このコードを、htmlコードを入力すると自動的に見出しの階層構造を抽出してくれるWEBサービスHTML 5 Outlinerに与えると次のような結果が帰ってくる。

3階層のアウトライン

3階層のアウトライン

つまり各所で指定した見出しレベル(h1)以外にも、sectionタグやarticleタグなどのセクショニング・コンテンツを示すタグを参考に見出し階層を推測してくれているのだ。これが大体のブラウザや検索エンジンの解釈となる。
一方、従来的なhtmlのように、明示的に見出しレベルを指定(h1,h2,h3)しても同様の結果が帰ってくる。

<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="css/base.css" type="text/css">
<meta name="description" content="サンプル株式会社の商品一覧ページです。">
<meta name="keywords" content="サンプル株式会社,ネットショップ">
<title>当社商品の一覧 | サンプル株式会社</title>
</head>
<body>
<div id="wrapper">
<header>
<h1>サンプル株式会社</h1>
</header>
<div id="main">
<article>
<h2>サンプル株式会社の商品一覧</h2>
<p>当社が取り扱う商品の一覧です。</p>
<ul id="itemlist">
<li>
<article>
<h3>商品A</h3>
<p>さわやかなミントの香りの牛車です(牛は食べられません)</p>
<p>100,000円</p>
<p><a href="http://xxxxxxxx.xxx/item.php?id=1" title="商品Aの商品詳細">>>商品詳細へ</a></p>
</article>
</li><li>
<section>
<h3>商品B</h3>
<p>官位です。これがあれば思いのまま(返品不可)</p>
<p>3,000円</p>
<p><a href="http://xxxxxxxx.xxx/item.php?id=2" title="商品Bの商品詳細">>>商品詳細へ</a></p>
</section>
</li><li>
<section>
<h3>商品C</h3>
<p>古今和歌集です。新版が出たので在庫一掃セールです</p>
<p>16,000円</p>
<p><a href="http://xxxxxxxx.xxx/item.php?id=10" title="商品Cの商品詳細">>>商品詳細へ</a></p>
</section>
</li><li>
<section>
<h3>商品D</h3>
<p>商品説明</p>
<p>100円</p>
<p><a href="http://xxxxxxxx.xxx/item.php?id=15" title="商品Dの商品詳細">>>商品詳細へ</a></p>
</section>
</li></ul>
</article>
<article>
<h2>当社のモットー</h2>
<p>適当な仕事。深刻な社会的被害。</p>
</article>
</div>
<footer>
<p>サンプル株式会社 2012-2017 all rights reserved.</p>
</footer>
</div>
</body>
</html>
やはり3階層のアウトライン

やはり3階層のアウトライン

この場合sectionやarticleなどのセクショニング・コンテンツを示すタグは、見出し階層の推測において無視されている。
HTML5では、このようにセクションを表すタグを使って見出しレベルを推測させることもできるし、従来のhtmlのようにあくまで明示された見出し階層のみを推測の根拠とさせることもできる。

W3CのHTML5.1勧告で自動解釈は撤回

そのような状況であったのだが、2016年11月1日に公開されたW3CのHTML5.1勧告で、様々なタグや属性の追加とともにある1つの仕様の削除について言及されていた。

The use of nested section elements each with an h1 to create an outline.

これはつまり、sectionやarticleのようなセクショニング・コンテンツを示すタグは、ページ内の最上階層で使われるもの以外、h1を頂点とした見出しレベルを構成してはいけなくなったということである。
問題をより簡潔に表現するならば、ページ内でh1は1回しか使うなということ。HTML5の登場以前からコーディングを行っている人間には常識のことであるし、登場以降もh1の濫用には何かペナルティがあるのではないかという認識の人間も多かったろう。彼らの時代が再びやって来たのだ。さあ新人コーダをいじめよう!

W3C勧告が当面のWEB制作上影響が無い理由

W3Cと言えば、WEB業界で使われる技術の標準化を行う団体で、HTML5が世に出たての頃など、ドキュメントも少ないので何か分からないタグの使用方法などあったらとにかくW3Cのページを見に行ったものである。そのW3Cのお墨付きがあるのだから、これからブラウザや検索エンジンの解釈も今回の勧告を基準にしたものに変わるのではないかということで、HTML5の登場とともにh1濫用型のコーディングに切り替えた私自身もビックリした(もう納品しちゃってるし…)。
ただ今回の経緯などを調べるうちに分かってきたのだが、確かにHTML5登場当時にW3CはWEB標準化の最前線と言ってほぼ間違いない団体であったが、それは次世代標準の提唱に頓挫してWHATWGという別の団体が提唱していたHTML5を全面的に受け容れることにした経緯によるもので、以降WHATWGとW3Cは協調路線を取っておらず、主要ブラウザなどの実装はWHATWGの提唱するHTML Living Standardのみを基準にしているようなのである(まあ実際、WHATWGの正体がブラウザベンダーの寄り合いのようなものなので当たり前である)。
ではW3C勧告が何の意味を持っているのかというと、実質何の意味も持たない。WHATWG側からHTML Living Standardの剽窃だとか欠陥フォークだとか、現在進行形で厳しい評価を受け続けている。

ということで、ページのアウトラインの形成においてHTML5.1勧告が世に出た後も依然2通りのやり方が使えるのは間違いない。一応、見出しレベルをタグの数字で明示するやり方だとW3Cの要求も満たすことが出来るということが両者の違い。セクション毎にh1を置くやり方はコンテンツの追加時に見出しレベルを気にせず追加できるというメリットがあるし、タグの数字で明示するやり方はソースコードを人間が見て一目で階層が分かり易い(ただし実際にどう解釈されているかを反映していない)というメリットがある。お好きな方でこれからも大丈夫。


box-sizing : border-box 最近はpaddingとborderを幅・高さから引かない

凄く今更な話だけれども、数年くらいWEB制作から離れていると見落としがちな常識の転換。

旧世代CSS:要素の幅・高さはあらかじめ余白と境界を引いた値にしよう

CSSで要素に対して幅や高さを指定する際に、要素の周囲を囲むborderの太さならびに境界内部の余白paddingの値は、あらかじめ目星をつけておかないといけない。というのも、widthやheightといったプロパティで指定された値に、borderとpaddingそれぞれの幅を加えたものが要素が親要素内で占有する大きさとなるからである。

旧padding,border計算方法

旧padding,border計算方法

上図の例で言うと、要素に対してwidthとheightで指定された幅200px高さ150pxという値は、余白paddingや境界線borderの幅がいくら変わっても保証される。その代わり要素自体の大きさは指定幅に加算されていくので、たとえば親要素の幅が400pxのところにこの.classが指定されたボックスをfloatを使って2つ並べたい場合、paddingとborderの幅を取ってしまうと2つ目のボックスが下に落ちてしまう。
そこで、ボックス落ちを防ぐためにはwidthとheightの値を、あらかじめpaddingとborderにあてがう幅分引いて指定しないといけない。上の例で言うならば、widthを150(200-20*2-5*2)px、heightを100(150-20*2-5*2)pxで指定しないと、ボックス落ちである。そして後々ページの見映えを変えたくて、paddingやborderの幅を変更したくなったらもう大変。変更の都度widthとheightの値を動かさないといけない。うわー面倒臭い。

かつてこんな感じに解決してました

この面倒臭さを解決する方法。一つは、クライアントにレビューの際にIE6を使わせる。IE6の場合paddingとborderはwidth,heightから引くという超モダンな解釈をしてくれる。そこで上の例で言えばwidthを200px、heightを150pxと指定しておいて、後からpaddingとborderを変更してもボックス落ちしない。クライアントには、IE6こそが先進的ブラウザで、その他99.9%のブラウザはゴミですと言い聞かせよう。
と、まあ冗談はさておき。問題を分割して、padding部分だけでも解決する場合。要素内にもう一つの要素を放り込んで、余白部分は内側の要素のmarginで指定するようにする。inner_**とかそういった命名の要素があれば、この問題を解決しようと苦心している可能性が高い。
そしてもう一つスマートな解決法として、CSSの変数を使用するというものがあった。CSS標準のものであれば、CSS Variables。

 
:root{
--tekitou-padding-value: 20; /* 変数名は--から始まる適当な名前 */
--tekitou-border-value: 5;
}
 
.class{
width: calc(200 - var(--tekitou-padding-value) * 2 - var(--tekitou-border-value) * 2);
height: calc(150 - var(--tekitou-padding-value) * 2 - var(--tekitou-border-value) * 2);
padding: var(--tekitou-padding-value);
border: var(--tekitou-border-value);
/* var(変数)で変数を定義された値に展開 */
/* calc(数式)で数式を展開 */
}

このようにすれば、後でpaddingとborderの値を変更しても、自動的にwidthとheightの値も連動する。
ただし、このCSS Variablesやcalc関数については対応ブラウザの問題がある。ベンダープレフィックスをつけないと動かない可能性は勿論のこと、CSS Variablesの方はEdgeの登場によりお役御免となったIEでサポートされてないのが痛い。ということで、変数を使う場合は主にSassやLESSのようなCSSプリプロセッサに頼ることになるだろう(コード例は省略)。CSSプリプロセッサを使う理由の全てがこの変数と数式計算という人も、きっと多いはず。

新世代CSS:box-sizing : border-boxで余白と境界をサイズに含めない

この余白と境界の値をあらかじめ考慮しないとボックス落ちしてしまうという仕様は、レスポンシブデザインにおいてはたいへん都合が悪かった。というのも、画面幅に応じて要素の幅も伸縮するレスポンシブデザインでは、幅の指定にパーセントを使用するからである。ボックス落ちしない余白と境界の値をあらかじめ知るのは不可能なので、デザインに遊びを持たせるか、フラットデザインのようにして影響を最小限にするなどしなければならなかった。勿論、CSSプリプロセッサで多少解決出来る部分もあるけれど、それはそれ。
かつてIE6的な余白と境界の解釈を標準化という錦の御旗のもと根絶してしまってから、実はそっちの方が都合が良かったと気付いたのだ。そこでCSS3ではbox-sizingというプロパティが出来て、余白と境界をサイズに含めない計算方法も選べるようになった。

box-sizing : border-boxを指定した場合の計算方法

box-sizing : border-boxを指定した場合の計算方法

指定方法は、box-sizingプロパティの値をborder-boxと指定するだけ(無指定の値はcontent-boxで、これは今までの計算方法だ)。これにより要素のwidthとheightで指定されたサイズが保証されて、paddingとborderはその値から減算することになる。後付けで値の変更を行っても、影響は最小限だ。

box-sizing : border-boxをどこで宣言するか

ちなみにこのbox-sizingプロパティにはinheritという値もあり、これが指定されていると上位要素で宣言された値を継承する。ページ全体にわたってbox-sizingを有効にする場合、一番簡単なのは、全称セレクタを使って全要素に明示的に指定することだけれども、

 
/* 全称セレクタだけでは疑似要素に適用されないので、beforeとafterもついでに指定 */
/* 疑似要素使わないなら指定の必要なし */
 
*, *:before, *:after{
box-sizing: border-box;
}

ただこれだとcontent-box指定を前提として書かれたCSSを拝借してくる場合などに、対象となる全要素をいちいちcontent-box指定に直すのが面倒臭い。そこで、inherit指定を上手く活用した方がbetter。

 
/* 最上位要素のhtmlに対してborder-boxを指定 */
 
html{
box-sizing: border-box;
}
 
/* 全ての要素のbox-sizingがinheritとなるように指定 */
 
*, *:before, *:after{
box-sizing: inherit;
}

このようにすれば、拝借してきたCSSがcontent-box指定の場合でも、その上位要素に対してcontent-boxを指定し直すだけでよい。

box-sizing : border-box入りのリセット/ノーマライズCSS

全称セレクタで全要素に対して指定をするならば、どうせならリセット/ノーマライズCSSで同時にこれをやってくれるものの使用も選択肢として考えたい。確認した範囲で以下のリセット/ノーマライズCSSが最新版で対応している(リンク先はGitHub)。

  • sanitize.css(全要素にinherit&html要素に対してborder-box指定)
  • minireset.css(全要素にinherit&html要素に対してborder-box指定)
  • ress(全要素にinherit&html要素に対してborder-box指定)
  • Marx(全要素にinherit&:root疑似要素に対してborder-box指定)

で、上の画像にも付記してあることだけれども、みんな大好きなTwitter Bootstrapではv2.3.2までにはborder-box指定がなく、2013年8月にリリースされたv3.0.0以降からborder-box指定が入る(全要素にinherit&html要素に対してborder-box指定)。

世代間の壁の存在に留意が必要

そんなわけで、昨今WEB制作の道に入門してくる人達は完全にborder-boxの常識でコーディングを行うだろうし、それ以前の常識で書かれたコードやWEB上のサンプルコードなどはcontent-boxの場合が多い。ここで混乱が起こる可能性がありそう(特にWordPressテーマとプラグインの関係で顕著)。
一応頭でinherit指定を行っておけば世代の異なるCSSコードの付け足しの際、直上の親要素に明示的指定を打って流用することが出来るけれども、付け足しが多数になってくるとあとあと訳が分からなくなってしまう。
そこで、出来ることならば新世代の常識の方に寄せる方向で旧世代コードも手直ししておいた方が良いのではないかと思う。Bootstrap等が軒並み新世代であることや、ブラウザのベンダープリフィックスなしbox-sizing対応がほぼ完了したことも鑑みて(box-sizingの各ブラウザ実装状況)。あと、購入する参考書の発行年などにも今後注意が必要だね。


小ネタ:WEBサイトの配色決めに役立つカラーピッカー

見映えの良いサイトを作成したいけれど、デザインセンスが要求されるので敷居が高い。これから時間をかけて、配色について勉強していかなくてはならないのだろうか…ええと、配色について教えてくれる場所は…美大?

さいわい、WEBデザインの仕事をしている人間が全員美大を出ているわけではない。また、デザインセンスについても、ほとんど皆無なれど仕事をしている人もいる。彼らがどのように仕事をしているのかというと、WEB上にある便利なツールを使って、悩んだりする時間を短縮しているようである。

指定したサイトでの使用色を採取するツール

デザインを決める最も短絡的な方法は、誰か他人のサイトをまねること。気に入ったサイトを片っ端からパクればよい。
ただ、パクるといっても、ページ構造からスタイルから全部のソースをそのままコピーするわけではなく、使用色の組み合わせをいただくのだ。一度は自分の気に入った配色だから、同じ色をベースにサイトを構築していくというのは、地味にモチベーションアップにも繋がる。

そしてその際に便利なのが、WEBサイトのURLを入れると配色を自動的に採取、カラーコードを表示してくれるツール。ネット上に星の数ほどもあるだろうけれど、表示の分かり易さなどから以下のサイトをおススメしたい。

Colours(http://webcolourdata.com

Coloursスクリーンショット

Coloursスクリーンショット

使用色だけでなく、サイト内で使用されている色の割合の情報も重要になる。このサイトの場合リボン状に使用割合を視覚化してくれるので、端の方のあまり使われていない色は文字やborderに使われている色だな、などと判断がつく。とっても便利。

選択色と組み合わせ相性の良い色を選んでくれるツール

どうしても使いたい色(ベースカラー)が決まっていて、その色との組み合わせで使って違和感の無い色の一覧を出してほしい。そんなケースもあるはず。そういった場合にオススメなのが、以下のサイト。

Paletton(http://paletton.com

Palettonスクリーンショット

Palettonスクリーンショット

取っ付きにくそうだけれども、いじっているうちに使い方に気付くはず。左上の小さいダイアルのようなボタンで、1〜4色までベースカラー数を選ぶ。あとはカラーピッカーをクリックしてベース色を選択ないし、”Base RGB”という欄にカラーコードを入れる。右のプレビューからマウスオーバーでカラーコードを取得可能。右下の”EXAMPLES…”タブを選ぶと、実際サイトに適用した例を表示してくれる。
このサイトが他のサイトより優れていると感じるのは、”Vision simulation”というメニューから閲覧者が色盲・色弱の場合の見え方を表示してくれるというところ。そこまで痒いところに手が届くカラーピッカーは、そうそう無い。

色の組み合わせツール(日本語)

Palettonは完璧なように思えるけれど、WEBデザイナーが使うには一点だけ不足部分がある。それは、色の組み合わせのデモがアルファベットを使ったサイトであるということ。アルファベットはそこまで複雑な形状をしておらず可読性も高いため、サイトの攻めの配色の一部として使うことも出来る。
Palettonで配色を決めて、いざ日本語サイトに適用しようとすると、吃驚するほど合わないというケースがある。それだけ漢字は複雑で、デザインの一部に組み込むのが難しいのだ。そこで、日本語に対応したカラーピッカーとして以下のサイトも紹介しよう。

ウェブ配色ツール Ver2.0(http://www.color-fortuna.com/color_scheme_genelator2/

ウェブ配色ツールVer2.0スクリーンショット

ウェブ配色ツールVer2.0スクリーンショット

Palettonに同じく、1色を決めると適当な組み合わせ色を選んでくれる。ただ注意書きに書いてあるように、ツール自体の配色の得手不得手はあるようだから、提示された色をそのままに近いデザインで使って、これなら万人が納得するはず!と思考停止してしまうのは良い結果に繋がらない。そもそもあまりベースカラーに向いていない色などもあるわけで、ツールは過信しすぎず、迷ったら無難な道に靡いていくべきだろうね。


サイトB:CSS3のbackground-size:cover;で背景画像をウィンドウにフィットさせる

最早サイトA、B、Cというカテゴリ分けはあまり意味を為していないけれど、当初のカテゴリ分け基準では、滞在感のあるサイトのノウハウをこのカテゴリに蓄積するはずだったので一応。

ブラウザのウィンドウをぴったりと埋める画像を背景として使い、その上にコンテンツを乗せるというやり方は、サイトに滞在感をもたせようと思ったときの常套手段だ。ただ、CSSのヴァージョンがまだ2.xであったころには、これをやるのがなかなか難しく、時にはJavaScriptやjQueryプラグインの力なども借りなければならなかった。

一方、CSS3に対応しているモダンなブラウザ環境を対象としたサイト作りであれば、こういったデザインも容易に実現できる。滞在感が表現できる上、ウィンドウに追随して大きさが変化するという特性からレスポンシブデザインとも相性が良い。

ウィンドウの大きさに追随する背景の指定

CSS3では、背景画像や色を指定するbackground系プロパティのひとつとして、background-sizeというプロパティが追加された。無指定の場合の初期値はautoだが、スペース区切りで値を2つ指定することで、それぞれ画像の幅と高さを決められる。たとえば指定要素に対して幅は50%、高さは200px固定というようにしたい場合の指定は以下のようになる。

background-size : 50% 200px;

また、特別な指定値としてcontainとcoverがある。containは背景画像として利用する画像をアスペクト比を保ったまま拡大・縮小し、クリッピングすることなく要素内に表示できる最大サイズにしてくれる。したがって、指定先の要素とアスペクト比が異なる場合には必ず画像の全体が表示された上で余白が生じる。

background-size : contain;

一方、coverは元画像のアスペクト比を保ちつつ拡大・縮小し、指定先要素の中に余白を生じることなく画像を表示する。したがって、アスペクト比が異なるのならば、画像は確実に一部分がクリッピングされる

background-size : cover;

したがって、ウィンドウサイズに合わせた背景画像を表示するためには、このbackground-size:cover;とmin-height:100%;をhtml要素に指定するという手順となる。

html{
min-height : 100%;
background-size : cover;
}

min-heightの指定が必要であるのは、内包するコンテンツのサイズによってhtml要素の縦の長さが変わるためだ。

ただ、background-size:cover;を指定する場合の背景画像は、抽象的画像や大写しの風景など見切れても不都合の無いものを選ぼう。人の顔などの場合には、見切れてしまうと大変格好悪い。
また、background-sizeプロパティはbackgroundショートハンド(省略指定)の対象となるので、background-sizeを指定した後あらためてbackgroundで指定しないようにする注意が必要である。


PHPテンプレートエンジンを使おう WordPress編

テンプレートエンジンの仕組みと、そのパラダイムについて何回かに分けて説明してきている(素のPHP編Smarty2.x編Smarty3.x編)。で、Smarty2.xのテンプレートエンジンのパラダイム、”閉じhead前切り”と同じく、テンプレートパーツを順番に呼び出していき最終的なhtmlとして成形するのが、かの有名なCMS、WordPressだ。WordPressのサイトがPHPプログラムからどのように生成されていくのか、入門編的な要素も絡めて解説しよう。

WordPressにおけるhtmlの切り分け方

WordPressにおけるテンプレートを確認するには、ダッシュボードの”外観”メニューから”テーマ編集”を選ぶ。初期画面で表示されているのはWordPressテーマのCSSだが、右側にある”テンプレート”と書かれたセクション、ここにあるのがテンプレートファイルということになる。ただし、このセクションはテンプレートファイルと呼び出し側のPHPスクリプトがごっちゃになっている状態(WordPressの場合、テンプレートファイルの拡張子も.phpになる)であり、また、”テーマ編集”で表示されるのは現在適用中のテーマのテンプレートファイルなので、テーマによって表示されている構成ファイルが異なるということに注意。とりあえず、本解説ではTwenty Twelveのものを基準として、どのテーマにも含まれそうなテンプレートファイルについて解説する。

テンプレートパーツ header.php

Smarty2.xの、”閉じhead前切り”では、html文書の頭の部分から、全ページ共通となる箇所を切り出してテンプレートを作成した。この頭からの部分に当たるのがheader.phpである。Smarty2.xの場合はこの部分に閉じheadタグを含めることができなかったが、これはmetaタグなどheadタグを閉じる前に挿入するページ固有の文言が必要な場合を鑑みてのことであった。
WordPressのheader.phpの場合は、呼び出し元のページ毎に必要な固有文言の挿入を、フィルターやアクションといった仕組みでキューに登録できる。登録した文言は、wp_head()というWordPress関数が呼ばれる際に一緒に呼ばれ挿入される仕組みになっている。したがって、head閉じタグの前で切らなくてもよい。大抵のテーマではヘッダー画像を内包して、mainやsidebarの直接の親要素の開始タグまでをまとめて、header.phpとしているようである(ソースコードの注釈にもそう書かれているのがわかるだろう)。

//Twenty Twelveのheader.php
 
<?php
/**
 * The Header template for our theme
 *
 * Displays all of the <head> section and everything up till <div id="main">
 *
 * @package WordPress
 * @subpackage Twenty_Twelve
 * @since Twenty Twelve 1.0
 */
?><!DOCTYPE html>
<!--[if IE 7]>
<html class="ie ie7" <?php language_attributes(); ?>>
<![endif]-->
<!--[if IE 8]>
<html class="ie ie8" <?php language_attributes(); ?>>
<![endif]-->
<!--[if !(IE 7) | !(IE 8)  ]><!-->
<html <?php language_attributes(); ?>>
<!--<![endif]-->
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>" />
.
.
.
<?php wp_head(); ?>
</head>
<body <?php body_class(); ?>>
<div id="page" class="hfeed site">
	<header id="masthead" class="site-header" role="banner">
.
.
.
	</header><!-- #masthead -->
 
	<div id="main" class="wrapper">

このように、header.phpというテンプレートの終わりはidがmainであるdivの開始タグとなっている。実際に表示されたページで見ると、以下の部分だ。

header.phpの実際の表示

header.phpの実際の表示

テンプレートパーツ sidebar.php

サイドバー部分のテンプレートがsidebar.phpになる。とは言っても、サイドバーに表示するものはウィジェットという形でユーザが自由に追加していく仕組みなので、テンプレートsidebar.phpの内容は大体dynamic_sidebar()というWordPress関数の呼び出し程度である。

sidebar.phpが担当する部分

sidebar.phpが担当する部分

テンプレートパーツ footer.php

footer.phpでは、ご想像の通りheader.phpで開いたid=”main”のdivの閉じタグから始まる。フッター部分のパーツ(クレジットなど)を表示し、bodyタグやhtmlタグも閉じる。bodyタグを閉じる前にwp_footer()という関数を呼んでいるが、これもまたこの位置で挿入されるスクリプト等のキューを参照、表示する。

//Twenty Twelveのsidebar.php
 
<?php
/**
 * The template for displaying the footer
 *
 * Contains footer content and the closing of the #main and #page div elements.
 *
 * @package WordPress
 * @subpackage Twenty_Twelve
 * @since Twenty Twelve 1.0
 */
?>
	</div><!-- #main .wrapper -->
	<footer id="colophon" role="contentinfo">
		<div class="site-info">
			<?php do_action( 'twentytwelve_credits' ); ?>
			<a href="<?php echo esc_url( __( 'http://wordpress.org/', 'twentytwelve' ) ); ?>" title="<?php esc_attr_e( 'Semantic Personal Publishing Platform', 'twentytwelve' ); ?>"><?php printf( __( 'Proudly powered by %s', 'twentytwelve' ), 'WordPress' ); ?></a>
		</div><!-- .site-info -->
	</footer><!-- #colophon -->
</div><!-- #page -->
 
<?php wp_footer(); ?>
</body>
</html>

実際に表示される部分としては、以下の部分。

footer.phpの担当部分

footer.phpの担当部分

WordPressにおけるテンプレートパーツの呼び出し方

この3種類の基本的なパーツを、個々のページファイルから呼び出して表示するわけである。ブログの表玄関である、index.phpでの呼び出され方を見てみよう。

//Twenty Twelveのindex.php
 
<?php
/**
 * The main template file
.
.
.
 */
 
get_header(); ?>
 
	<div id="primary" class="site-content">
		<div id="content" role="main">
		<?php if ( have_posts() ) : ?>
 
			<?php /* Start the Loop */ ?>
			<?php while ( have_posts() ) : the_post(); ?>
				<?php get_template_part( 'content', get_post_format() ); ?>
			<?php endwhile; ?>
 
			<?php twentytwelve_content_nav( 'nav-below' ); ?>
 
		<?php else : ?>
.
.
.
		<?php endif; // end have_posts() check ?>
 
		</div><!-- #content -->
	</div><!-- #primary -->

<?php get_sidebar(); ?>
<?php get_footer(); ?>

get_header()、get_sidebar()、get_footer()というWordPress関数で、それぞれheader.php、sidebar.php、footer.phpを呼び出して表示している。つまり最低限この3テンプレートと、3関数のコールがあればページの枠はできているのである。
あとは、get_header()とget_sidebar()の間に書かれている部分が、ページのメイン部分の内容になる。ここで、もう一種類のテンプレート読み込み関数、get_template_part()というものが登場している。

get_template_part()

get_template_part()という関数は、任意の名称のテンプレートを読み込む関数である。第1引数のみ指定すると(たとえば、”content”という文字列を与えよう)、第1引数.phpというテンプレートファイルを読み込む(例であれば、content.php)。第2引数を添えると(たとえば、”content”,”aside”という2つの文字列を与えよう)、第1引数-第2引数.phpというテンプレートファイルを読み込む(content-aside.php)。
上記のTwenty Twelveの例では、”content”とget_post_format()という2つの引数を与えている。get_post_formatは投稿のフォーマットを返してくるので、contentの後に投稿フォーマットのついた複数のテンプレートファイルにここで振り分けを行っているのだ。確かに、Twenty Twelveの構成テンプレート一覧の中に”content-XXX.php”というファイルが多数ある。

content.phpの一族

content.phpの一族

このようにして、いちいち投稿フォーマット毎にswitch文で分岐を作らなくても、適切なテンプレートを取得してくれるようになっているのである。

WordPressはテンプレートエンジン

このように、特定テンプレートパーツを呼び出すget_header()などの関数、あるいはファイル名を指定して呼び出すget_template_part()関数があるため、WordPressはテンプレートエンジンそのものであると言える。
肝心のプレースホルダについてはどうであるか。WordPressは投稿(Post)を単位として読み込み、投稿のタイトル、本文などの情報にWordPress関数(ゲッタメソッド)経由でアクセス・表示させる。たとえばタイトルと本文をテンプレート中で呼び出す場合には、以下のような具合になる。

<h1 class="title"><?php the_title(); ?></h1>
<div class="honbun"><?php the_content(); ?></div>

Smartyなどのプレースホルダと異なり、関数をそのまま実行という少し無骨な形ではあるが、WordPressサイトの制作に慣れたデザイナー・コーダであれば、大体どの関数が何を出力しているか理解するし、またこの出力部分以外のデザインを変更すればよいと理解するのである。

ということで、WordPressでのサイト制作が現在主流となっているのは、そのCMS機能に期待したものではなく、デファクトスタンダードのテンプレートエンジンとしての需要であるという見方も可能である筈。


PHPテンプレートエンジンを使おう Twig編

PHPテンプレートエンジンについて解説・紹介していく企画、素のPHPSmarty2.xSmarty3.xと紹介してきて、満を持してのTwig登場である。

PHPテンプレートエンジンTwigとは

そもそも、Twigとは何なのだろうか。疑問を解決するためにお手元の検索エンジンで検索しても、小枝の画像ばっかり出てくる(笑)。Twigとは、フランスのSensioLabsというソフトウェア会社にスポンサードされている、オープンソースのWEBアプリケーションフレームワークSymfonyを構成する標準バンドルパッケージの一つである(Symfony公式サイトTwig公式サイト)。
WEBアプリケーションフレームワークという言葉が出てきたが、WEBアプリケーションを作るための”概して便利な”枠組みのことで、Symfonyは企業サイトやらAPIやらのWEB上に展開するサービスを作成する際に、ヴァージョンの管理やライブラリの管理、データ構造など様々なことを、MVCの考え方に基づいて整理・管理してくれる仕組みだ。
MVCにのっとっているため、Symfonyは多人数が関わるプロジェクトなどにおいて強みを発揮する。逆に言うと、小規模で作ったら作りっぱなしのようなプロジェクトに導入する意義はそれほど無い。でもそうした小規模プロジェクトでも、Symfonyの特定機能だけ利用したいという需要があるかもしれないので、Symfonyでは機能の多くをモジュール化しており、Symfony本体を導入しなくてもかいつまんで使えるようになっている。そのモジュールの一つが、PHPテンプレートエンジンのTwigというわけだ。

Twigの利用方法

Twig単体で利用する場合、先程紹介したTwig公式サイトより本体を落としてきて、libディレクトリ内のTwigディレクトリを適当な場所に配置する。あとはキャッシュ用のディレクトリと、テンプレートファイル格納用のディレクトリを必要に応じて作っておけばよい。なおインストールにはcomposerというSymfonyのモジュールを使う方法もあり、ファイルの依存関係を管理するというcomposer自体の機能も使いたい場合には、一緒に導入しておいても良いだろう。
で、ひとまずcomposerを使用しないインストールが済んだとして、呼び出し側のPHPスクリプトではこういった感じに書く。Smarty2.xの説明で出した例と同じことをやっているので、適宜比較などしてほしい。

//index.php
 
require_once("Twig/Autoloader.php");
Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem("twigtmp/");
$twig = new Twig_Environment($loader, array("cache" => "cache/", "debug" => false));
$template = $twig->loadTemplate("default.html.twig");
$template->display(array("title" => "トップページ"));

まず、先程のTwigディレクトリにあるAutoloader.phpを読み込む。これは関連ファイルを全て読み込むためのクラスで、Twig_Autoloader::registerメソッドを呼ぶ。
次に$loaderに入れているのはテンプレートをロードするクラスのインスタンスで、Twig_Loader_Filesystemの場合コンストラクタにテンプレートファイルのあるディレクトリへのパスを引数として与える。ファイルを読み込むのでなくインラインのStringでテンプレートを用意する場合はTwig_Loader_Stringクラスなど、いくつか種類があるのだが、とりあえずTwig_Loader_Filesystemだけ覚えておけば良い。

次のTwig_Environmentというクラスのインスタンス作成時に、$loaderと配列にした各種設定を渡している。”cache”はキャッシュを入れるディレクトリへのパス、”debug”はデバッグの有無など。キャッシュを使わずデバッグモードもオフならば、第一引数のみで良い。

$templateはTwig_environmentのメソッドであるLoadTemplate()で読み込むテンプレートファイル名を与える。そして$templateのdisplay()メソッドの引数に、変数の値をラベル付き配列で与える。これで標準出力へと出力されることになる。
テンプレート側の記述はこのように。変数の先頭に$をつけず、二重波括弧({{}})で変数名を囲む。

//default.html.twigの記述
 
<!doctype html>
<html lang="ja">
<head>
<title>{{ title }} | サンプル株式会社</title>
</head>
<body>
.
.
</body>
</html>

商品一覧ページをTwigで作ってみる

それでは、Smarty3.xを用いて作った商品一覧ページを、Twigで作り直してみよう。まずはテンプレートファイル側。

 
<!-- base.html.twig -->
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="css/base.css" type="text/css">
{% if description is not empty %}
<meta name="description" content="{{ description }}">
{% else %}
<meta name="description" content="サンプル株式会社のホームページです">
{% endif %}
{% if keywords is not empty %}
<meta name="keywords" content="{{ keywords }}">
{% else %}
<meta name="keywords" content="サンプル株式会社,小売業,日本">
{% endif %}
<title>{{ title }} | サンプル株式会社</title>
{% block head %}
{% endblock head %}
</head>
<body>
<div id="wrapper">
<header>
<h1>サンプル株式会社</h1>
</header>
<div id="main">
{% block main %}
<article>
<h1>デフォルト文章</h1>
<p>mainのブロックに指定が無い場合のデフォルト文章です。</p>
.
.
</article>
{% endblock main %}
</div>
<footer>
<p>サンプル株式会社 2012-{{ "now"|date("Y") }} all rights reserved.</p>
</footer>
</div>
</body>
</html>
 
<!-- item.html.twig -->
<li>
<section>
<h1>{{ value.name }}</h1>
<p>{{ value.description }}</p>
<p>{{ value.price|number_format(0) }}円</p>
<p><a href="http://xxxxxxxx.xxx/item.php?id={{ value.id }}" title="{{ value.name }}の商品詳細">>>商品詳細へ</a></p>
</section>
</li>
 
<!-- itemlist.html.twig -->
{% extends "base.html.twig" %}
{% block main %}
<article>
<h1>サンプル株式会社の商品一覧</h1>
{% if items is empty %}
<p>現在取り扱っている商品はありません</p>
{% else %}
<p>当社が取り扱う商品の一覧です。</p>
<ul id="itemlist">
{% for value in items %}
{% include "item.html.twig" %}
{% endfor %}
</ul>
{% endif %}
</article>
{% endblock main %}

テンプレートファイル側でのSmartyとの違いは、プレースホルダの書き方は先程説明の通り。ifなどの制御構造は括弧だけでなく、end〜という閉じタグになるところや、foreachの書き方がfor inになるところ、blockのname=でなく直接block名指定になるところ、比較演算子がis notのような自然言語的な書き方になることなど、細かい違いが結構あると言える。配列のラベルへのアクセスは同じだが、Twigの場合value[“name”]のようなアクセスも可能。そして、オブジェクトのメンバへのアクセスも同じ書き方で出来る。
修飾子が”|”の後に続くのも同じ。あとは、オシャレなマニュアルでチェックしてほしい。

呼び出し側はこのように。

//itemlist.php
 
require_once("Twig/Autoloader.php");
Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem("twigtmp/");
$twig = new Twig_Environment($loader, array("cache" => "cache/", "debug" => false));
$items = array();
 
//例の如く、下記の配列が帰ってきたと仮定
 
$items = array(
array("id" => "1","name" =>"商品A","description" => "さわやかなミントの香りの牛車です(牛は食べられません)","price" => "100000"),
array("id" => "2","name" =>"商品B","description" => "官位です。これがあれば思いのまま(返品不可)","price" => "3000"),
array("id" => "10","name" =>"商品C","description" => "古今和歌集です。新版が出たので在庫一掃セールです","price" => "16000")
);
$page = array(
"description" => "サンプル株式会社の商品一覧ページです。",
"keywords" => "サンプル株式会社,ネットショップ",
"title" => "当社商品の一覧",
"items" => $items
);
$template = $twig->loadTemplate("itemlist.html.twig");
$template->display($page);

まあ既に説明した内容である。displayメソッドに持たせる引数が標準で配列であるため、テンプレート側からそのままラベルのみでアクセスしていることに注意。
あと、この例だとキャッシュを有効化しているので、いじってテストなどする際には、結果確認の前にキャッシュディレクトリの中身を廃棄しておこう(これをわざわざやらなくて良いためにデバッグモードがあるらしい。先程知った)。

SmartyとTwigはどちらが良いのか

以上、Twigについても見てきた。仕組みはそれほどSmartyと変わらないので、乗り換えは楽だろう。ただ、乗り換え後過去資産を活用しようとすると変換は面倒臭いので、そこはあまり期待しない方が良い。
良く言われるSmarty3.xとTwigの速度面の差だが、確かに体感などTwigの方がキビキビ動いている印象がある(Smarty2.xには劣るけど)。速度比較については厳密度は分からないけれど、こんなデータもある。
あとはマニュアルのオシャレさなんかを基準にどちらを使うか決めれば良いだろう。