レイアウトのチューニングは時間がかかる。でも見た目のインパクトは小さくて少し悲しい・・・。
前回は、WordPress のテーマ Twenty Fourteen の子クラス Twenty Fourteen Child(2014 Child)の作成例のうち、レイアウトの概要とテンプレートについて説明した。今回は functions.php や CSS などのコード類について説明する。今回の作成例が一つのテストということもあって、CSS 以外のコードはあえて複雑にしている部分があるので、その点をあらかじめ頭の片隅に入れておいて頂きたい。
- 1. Twenty Fourteen Child のレイアウトとテンプレート(前の記事)
- 2. Twenty Fourteen Child の CSS と java script
- 1)functions.php
- 2)CSS
- 3)java script
- 4)おわりに
2. Twenty Fourteen Child の CSS と java script
1)functions.php
2014 Child の functions.php は子テーマにしては中身が多い。
「ここでなければできない(ランク AA)」処理と「ここでやるべき(ランク A)」処理、それに「無理してここでやらなくても良い(ランク C)」処理が入り混じっているからだ。実のところ処理として必須なのは CSS の登録だけで、他はテストの一環だと思って頂きたい。
functions.php の全コード:
<?php /** * Twenty Fourteen Child functions * Based on WordPress Twenty Fourteen */ // 親テーマ Twenty Fourteen の style.css と自作のスタイルシートを登録。 function theme_enqueue_styles() { $stylesheet_Dir = get_stylesheet_directory_uri(); // Twenty Fourteen の style.css wp_enqueue_style( 'twentyfourteen-style', get_template_directory_uri() . '/style.css', array( 'twentyfourteen-lato','genericons' ), null ); if( is_page_template( 'page-templates/full-width.php' ) || is_page_template( 'single_full-width.php' ) ) { // 2 カラムレイアウト表示用の CSS wp_enqueue_style( 'fullwidth-custom-style', $stylesheet_Dir. '/css/fullwidth-custom-style.css', array( 'twentyfourteen-lato', 'genericons', 'twentyfourteen-style' ), null ); // table 表示用の CSS wp_enqueue_style( 'custom-style', $stylesheet_Dir. '/css/custom-style.css', array( 'twentyfourteen-lato', 'genericons', 'twentyfourteen-style', 'fullwidth-custom-style' ), null ); // ポジション固定ヘッダーの width 調整用スクリプト wp_enqueue_script( 'masthead-resize-script', $stylesheet_Dir. '/js/masthead-resize.js', array(), null ); } } // 関数をアクションフックに登録する。 add_action( 'wp_enqueue_scripts', 'theme_enqueue_styles' ); // body にクラスを追加登録する。 function child_fullwidth_class_name( $regClassNames ) { // テンプレートがロードされていれば新しいクラスセレクタを追加する。 if( is_page_template( 'page-templates/full-width.php' ) || is_page_template( 'single_full-width.php' ) ) { // 追加セレクタは 1 個なので次のようにして追加する。 $regClassNames[] = 'child-full-width'; } return $regClassNames; } // 関数をフィルターフックに登録する。 add_filter( 'body_class', 'child_fullwidth_class_name' ); // 固定ページでは sidebar-1 内の「最近のコメント」を削除する。 // インデックスはこのテーマを適用するサイトの実際の値を入れる。 function disable_sidebar_widget( $regWidgets ) { if( is_page() ) { wp_unregister_sidebar_widget('recent-comments-2'); // full-width.php 適用時には sidebar-1(secondary)内のアーカイブを削除する。 // インデックスはこのテーマを適用するサイトの実際の値を入れる。 if( is_page_template( 'page-templates/full-width.php' ) ) { wp_unregister_sidebar_widget( 'archives-2' ); } } return $regWidgets; } // 関数をフィルターフックに登録する。 add_filter( 'sidebars_widgets', 'disable_sidebar_widget' );
関数の役割:
2014 Child の functions.php の各関数の役割は次の通りだ。
関数名 | 役割り | ランク | 処理の重要度 |
theme_enqueue_styles | CSS ファイルと java script ファイルを登録する。 | A | ◎ |
child_fullwidth_class_name | body のclass 属性にクラスセレクタを登録する。 | C | 〇 |
disable_sidebar_widget | 固定ページ表示時にウィジェットを削除する。 | AA | ー |
style.css の登録は子テーマとして必須で、fullwidth-custom-style.css の登録は 2014 Child として必須だ。
body の class 属性へのクラスセレクタ登録は、header.php の 33 行目を <body <?php body_class(‘child-full-width’); ?>> と書き換えて登録する方が簡単だ。
条件分岐(参考):
is_page_template、is_page などの条件分岐タグを functions.php の中で直接使うことはできない。
必ずユーザー関数の中に記入して、アクションフックやフィルターフックの中で有効にする必要がある。
- theme_enqueue_styles の条件分岐の意味
CSS、スクリプトなどの登録内容を、現在の投稿/固定ページが使用するテンプレートの種類で切り替えるテストとして使っている。CSS については、通常レイアウトでページを表示した時に style.css と fullwidth-custom-style.css が同居するのを回避している。
- child_fullwidth_class_name の条件分岐の意味
body 要素へクラスセレクタを登録するテストとして使っている。
これは、2 カラムレイアウトで表示した時に 、style.css と fullwidth-custom-style.css が競合(コンフリクト)するのを防止するための処理だ。詳細は CSS のところで説明する。
ウィジェットの登録/削除処理(参考):
一度ウィジェットを登録した後で、別途ウィジェットの登録/削除を実行することはできない。
登録/削除を実行するためには、処理を functions.php の中で sidebars_widgets フィルターに事前登録しておく必要がある。
これはウィジェット登録/削除のテストだ。2014 Child では固定ページ表示時にコメントとアーカイブのウィジェットを削除している。
recent-comments-2 、archives-2 などのインデックスは私のプロジェクトに固有の値なので、他のプロジェクトでこのコードをテストする場合は、サイト上に表示される実際の値 ―― つまり content-sidebar 内の該当する aside の ID を指定する必要がある。【検証】や他のブラウザの開発ツールを使えば簡単に調べられるが、素(す)のソースコードだとちょっと大変かも知れない。
2)CSS(目次へ戻る)
styles.css:
2014 Child の style.css は次のようなコメントだけで成り立っている。
必須項目は Theme Name と Template だけだが、オープンライセンスの部分は親テーマの内容を全部残してある。
Theme Name: Twenty Fourteen Child
Theme URI: https://ys.moon-sky.net/themes/twentyfourteen-child/
Author: Bonkure
Author URI: https://ys.moon-sky.net/
Template: twentyfourteen
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
This theme is licensed under the GPL.
*/
fullwidth-custom-style.css:
これは 2 カラム右サイドバー仕様のレイアウトを実現する CSS だ(以下 fullwidth CSS)。
このレイアウトを PC で見ると、記事表示部分(entory-content)の width が padding 込みで 907px、右サイドバー(content-sidebar)が、やはり padding 込みで 353px で表示されるはずだ(ズーム率 100% )。
- fullwidth-custom-style.css 全コード
/** * Twenty Fourteen Child CSS * Based on WordPress Twenty Fourteen Styles */ .child-full-width { background-color: #f5f5f5; } .child-full-width .site { max-width:1260px; } /* デフォルトでは secondary 配置用のスペースを確保している。 * 182px(min-width: 1008px)、222px(min-width: 1080px) */ .child-full-width .site:before { width: 0px; } /* ズーム 125% 時の 1px の空白をキャンセルする。 この現象は Chrome のみに発生する。 */ .child-full-width #site-header img { vertical-align: bottom; } .child-full-width .site-header { max-width: 1260px; width: inherit; background-color: transparent; } .child-full-width .header-main { background-color: #000000; } /* header 関連終わり。 */ .child-full-width .site-content .entry-header, .child-full-width .site-content .entry-content, .child-full-width .site-content .entry-summary, .child-full-width .site-content .entry-meta, .child-full-width .page-content { margin: 0 auto; max-width: 900px; line-height:1.64; } .child-full-width .hentry { max-width: 100%; } .child-full-width .content-area { padding-top: 64px; padding-left: 0; padding-right: 0; margin: 0; } .child-full-width .content-sidebar { padding-top: 64px; width: 100%; margin: 0 10px; } /* Media Queries */ @media screen and (min-width: 673px) { .child-full-width .site-content { margin-right: 0; } .child-full-width .content-sidebar { margin: 0 auto; } } @media screen and (min-width: 710px) { .child-full-width .site { margin: 10px; } .child-full-width #site-header { margin-left: 10px; margin-right: 10px; } .child-full-width .site-header { margin: 0 10px; } } @media screen and (min-width: 783px) { .child-full-width .site { margin: 20px; } .child-full-width #site-header { margin-left: 20px; margin-right: 20px; } .child-full-width .site-header { margin: 0 20px; } } @media screen and (min-width: 910px) { .full-width .main-content { float: left; } .child-full-width .site-content { margin-right: 33%; margin-left: 0; } .child-full-width .content-sidebar { margin-left: -33%; width: 33%; float:right; } } @media screen and (min-width: 1008px) { .child-full-width .site-content { margin-right: 31%; margin-left: 0; } .child-full-width .content-sidebar { margin-left: -31%; width: 31%; } .search-box-wrapper, .featured-content { padding-left: 0; } } @media screen and (min-width: 1080px) { .child-full-width .site-content { margin-right: 28%; margin-left: 0; } .child-full-width .content-sidebar { margin-left: -28%; width: 28%; } .child-full-width .site { margin: 30px; } .child-full-width #site-header { margin-left: 30px; margin-right: 30px; } .child-full-width .site-header { margin: 0 30px; } }
- 2 カラムレイアウトを実現するクラス型スタイル(クラス)と :before 疑似要素型スタイルの設定
下の表で Child 設定値が 0(ゼロ)に変更されている部分が、キャンセルされた左サイドバー表示領域だ。
スタート用テンプレートの single_full-width.php と full-width.php では、この領域に配置されるコンテナ要素 secondary そのものが削除されているので、これでレイアウトが完全な 2 カラムになる。
セレクタ | 行 | property | 既定値 | Child 設定値 |
.site:before | 16 | width | 182-222px | 0 |
.search-box-wrapper | 136 | padding-left | 182-222 px | 0 |
.site-content | 113 | margin-left | 182-222 px | 0 |
.site-content | 112 | margin-right | 29.047-33.33%:Val1 | 28-33%:Val2 |
.content-sidebar | 118 | width | Val1 | Val2 |
.content-sidebar | 117 | margin-left | Val1(※) | Val2 |
※Val はマイナス値のマージン。
- その他の修正
次にその他の修正を挙げる。
Chrome のデベロッパーツール【検証】でこれを変更しても、通常の表示では違いが見えない部分なので、コードを見ただけでは何のために入っているのか分りづらい部分だ。プロパティ値はコード例で確認して頂きたい。
セレクタ | 行 | property | 修正理由 |
#site-header img | 23 | vertical-align | ズーム率 125% で発生する 1px の空白補正 |
.site-header | 28 | width | java script による width 補正前の初期値 |
.main-content | 108 | float | Media Queries の条件変更による修正(固定ページのみ) |
- fullwidth CSS の適用範囲(スコープ)を制限する
スコープを制限する目的:
- (1)fullwidth CSS の中でオーバーライドされたデフォルトスタイルのプロパティを、他の CSS に継承させない。
- (2)fullwidth CSS の作成および改編を容易にする。
最初のが当初の目的だ。
2014 Child のダウンロード用サンプルを作ると決めた時に、最初に思い浮かんだのがこれ。CSS の登録順で他の CSS に影響を与えるようなものは作れないということだ。
下のは後付けの理屈だ。
スコープを制限したら実際に作成スピードと精度が上がったので、付け加えることにした。
スコープを制限する方法:
- (1)2 カラムレイアウト用テンプレートを使用する時に、body 要素の class 属性に.child-full-width クラス型スタイル(以下「クラス」)を設定する。
- (2)fullwidth CSS の中で、すべてのクラスをこの .child-full-width の下位クラスに指定する(ID 型スタイル #site-header も含む)。
最初の手順は functions.php の中で実施している。
functions.php では fullwidth CSS の登録制御も実施しているので、同じ目的の処理が重なっていることが分かる。だからテストなのだ。
次の手順は fullwidth CSS で行っている。
セレクタが【.child-full-width セレクタ】となっている部分がそうだ。ほとんどすべてのクラスがそうなっているが、.main-content のみ .full-width の下位クラスになっている。
custom-style.css:
これは table 要素の overflow 分をスクロールする CSS だ。
2 カラムレイアウトとは直接関係はないが、4 列以上のテーブルを iPhone エミュレータで表示した時の表示がかんばしくないので、とりあえずその対策の一つとして入れておいた。
この CSS を利用するためには table 要素の中に thead 要素を置く必要がある。
table 開始タグの直下に thead 要素を置き、tbody の先頭の tr 要素を丸ごと切り取ってその中に配置すれば良い。それで列見出しが全部 thead の中に配置される。
この CSS はほとんど下の参考リンクから頂いたものなので、詳細はそちらを参考にして頂きたい。
参考リンク:【Design Spice】レスポンシブWebデザインでテーブルを使う時の小技
- custom-style.css 全コード
.entry-content table { font-size: 15px; } .table, .table-2nd { border: solid 1px gray; border-radius: 3px; } thead{ background-color: #f2f2ee; } @media only screen and (max-width: 490px) { /* table-layout の設定がないと tbody が site-content の幅を超えて * はみだす。*/ .table { width: 100%; table-layout: fixed; border-radius: unset; } .table thead{ display: block; float: left; } .table tbody{ display: block; overflow-x: scroll; white-space: nowrap; } .table tr{ display: inline-block; vertical-align: top; } .table th, .table td{ display: block; } .table::after{ content:""; clear: both; height: 0; } .table-2nd { border-radius: unset; } }
3)java script(目次へ戻る)
これは、スクロールダウン時に固定位置で表示(position:fixed)されるマスタヘッダー(masthead)の width を調整するための、java script のイベントハンドラだ。
DOMContentLoaded イベントと resize イベントに同じイベントハンドラを指定しているので、分かり易いと言えばそうなのだが、少しイレギュラーな構成かも知れない。
イベントハンドラ:
イベントハンドラ | width 基準要素 | ヘッダー画像 |
reSizeMastHead | site-header | 〇 |
reSizeMastHead_2nd | page | - |
reSizeMastHead はヘッダーに画像がある場合のみ有効なイベントハンドラで、reSizeMastHead_2nd は制限なしのバージョンだ。これらは元々一つのイベントハンドラだったが、今はあえて二つに分割してある。私にはその方がデバッグしやすかったからだ。
- 全ソースコード
window.onresize = function() { reSizeMastHead(); } window.addEventListener("DOMContentLoaded", function() { reSizeMastHead(); }); function reSizeMastHead() { var elemReference = document.getElementById( 'site-header' ); if( elemReference == null ) { reSizeMastHead_2nd(); return; } var elemTarget = document.getElementById( 'masthead' ); var referenceWidth = elemReference.getBoundingClientRect().width.toFixed(3); /* ターゲット要素の width を設定する。 */ elemTarget.style.width = referenceWidth + 'px'; } function reSizeMastHead_2nd() { /* 基準(reference)の要素とターゲット要素を取得する。 */ var elemReference = document.getElementById( 'page' ); var elemTarget = document.getElementById( 'masthead' ); /* 基準要素の style のプロパティを取得する。 */ var referStyle = window.getComputedStyle( elemReference, null ); /* getComputedStyle が値を返さない場合は処理を中止する。 * firefox と Edge、および IE Ver11 は正常動作を確認した。 */ if ( referStyle == null ) { elemTarget.style.width = '100%'; return; } /* ターゲット要素の style のプロパティを取得する。 */ var targetStyle = window.getComputedStyle( elemTarget, null ); /* 基準値となる width を小数点以下 3 桁まで取得する。 * getBoundingClientRect().width を使用した時とほぼ同じ値 * が返される。parseFloat に注意!! */ var referenceWidth = parseFloat( referStyle.width ).toFixed(3); /* reference の padding を取得する。 */ var _paddingRight = parseInt( referStyle.paddingRight ); var _paddingLeft = parseInt( referStyle.paddingLeft ); /* 基準値の width から padding を差し引く。 */ referenceWidth = referenceWidth - _paddingLeft - _paddingRight; /* ターゲット要素の margin の処理。今は padding を考慮しない。 */ var _marginRight = parseInt( targetStyle.marginRight ); var _marginLeft = parseInt( targetStyle.marginLeft ); /* margin を考慮したターゲット要素の width を設定する。 */ elemTarget.style.width = referenceWidth - _marginLeft - _marginRight + 'px'; }
2nd の処理が多いのは、基準要素 page の左右の padding と、ターゲット要素 masthead の 左右の margin の設定を補正するためだ(※1)。padding や margin を設定しない場合は、それらの計算部分は不要になる。
私は jQuery のことは何も知らないので、ここではそのことには触れない。
また、【検証】で java script をデバッグするのも初めてだったので、あまり分かったようなことも言えない。いま言えるのは、変数や制御コードを追加 / 削除しながらスクリプトをデバッグするのは大変だったが、とりあえず何とかすることはできた(※2) ―― ということだけだ。
これについては、きちんとオーソライズされた方法を見つけたら、何かを書くことがあるかも知れない。
- ※1)masthead に左右の margin を設定する場合は、site-header も同じだけ margin を設定する必要がある。
- ※2)Event listeners タブの resize イベントから msthead-resize.js を削除する。js ファイルの中身を全部コピーして、Chrome の【検証】の Console に貼りつけ Return キーを押す ―― というようなことをやってみた。
おわりに:(目次へ戻る)
日常的にキーボードに向かっていればそれほど気にならないテーマの更新も、長期間ブログを休んでいた時にはかなり億劫(おっくう)に感じられ、つい実行が遅れがちになってしまった。
ファイルの書き換えやコピペで更新を乗り切る、というアドホックなやり方には少し嫌気がさしていたので、もっと楽な ―― というか筋道の通った方法を探したら、WordPress の Codex 日本語版で次のような子テーマの説明を見つけた。
Codex 日本語版「子テーマ」より引用:
- テーマを直接変更した場合、そのテーマがアップデートされると変更が失われるかもしれません。子テーマを使用すればテーマの変更は確実に保持されます。
- 子テーマを使用することで開発時間を短縮できます。
- 子テーマの使用することでWordPressのテーマの開発を良い形で学べます。
これに励まされて、その時使っていたテーマ anjirai に変更・追加ファイルを移動したら、確かにテーマの更新がとても楽になった。今頃何言ってんだ?・・・と呆れられそうだが、私が子テーマ関連のドキュメントを真面目に読んだのは、実はこれが初めてという情けなさなのだ。
その余勢を駆って、テンプレート込みの新しい子テーマ 2014 Child を作ってみたワケだ。
自作テンプレートを使いたくて 2014 Child を作ったのではなくて、子テーマ作成の敷居(しきい)が想像していたよりもずっと低かったので、次のステップを踏み出す気になれたということだ。
そして既存のテンプレートをカスタマイズして、それを固定ページと投稿記事に適用することも、想像していたよりずっと簡単だった。本当はこの記事でそのことをお伝えしたかったのだが、自分のための備忘録を兼ねて書いているので、そういう雰囲気はうまく書き切れなかったように思う。
話が少し長くなったが、この記事を終えるにあたり、上の二点はだけはどうしても強調しておきたかった。