Skip to the content.

第6章 レイアウトのカスタマイズ

この章ではレイアウトとLiquidの説明をします。

ファイルの構成と配置

「Jekyll tutorial for beginners」の構成を考えてみます。 このサイトのメインはJekyllのチュートリアル・ドキュメントで、それがファイル数でも最も多くなっています。 そこで、ドキュメント・ファイルを一つのディレクトリの下にまとめることにしました。 ファイルの構成は次のようになります。

ディレクトリ名「_chapters」の最初にアンダースコア(_)がつくのは、Jekyllのコレクションという機能にあわせるためです。

+--- _config.yml
+--- index.md
+--- about.md
+--- toc.md
+---_chapters
|       +--- ch1.md
|       +--- ch2.md
|       + ... ... ...
+---assets
|       +--- css
|       +--- images
|       +--- javascript
+---_site
... ... ...

このファイル構成はそのまま_siteのファイル構成になります。 ただし次の2点が異なります。

各HTMLファイルには他のページへのリンクが必要です。 リンクはバラバラではなく、まとまって配置するのがユーザ・フレンドリーです。 そこで、コンテンツ内上部に、横並びに設置する方法を取ることにします。 このリンクのことをコンテンツ・ナビゲーション(短くして「コナビ」)と呼ぶことにします。 これは、このチュートリアルの中での呼び方で、一般に使われるものではありません。

コナビはどのページにも使われますので、それらが共有するレイアウトファイルの中に記述することにします。 ただし、default.htmlは変更せずに、その子レイアウトとして「home.html」「chapter.html」を作ります。

home.html

「index.md」「about.md」「toc.md」の3つのファイルのコナビを記述するレイアウトを「home.html」とします。 _layoutsフォルダを作り、その下にhome.htmlを置きます。

---
layout: default
---
<ul class="nav">
  <li>
    <a href={{ "/index.html" | relative_url }}>トップページ</a>
  </li>
  <li class="nav">
    <a href={{ "/about.html" | relative_url }}>Aboutページ</a>
  </li>
  <li class="nav">
    <a href={{ "/toc.html" | relative_url }}>目次</a>
  </li>
</ul>
{{ content }}

フロントマターにlayout: defaultがあるので、home.htmlはdefault.htmlのコンテンツの部分に表示されます。

各ページへのリンクが順序なしリストになっています。

href=の右のリンク先アドレスはLiquidで書かれています。 | relative_urlは左から流れ込んだ入力のアドレスに_config.ymlで指定したbaseurlを付け足します。 baseurlを設定していなければ空文字列になります。

ここで注意しなければならないことがあります。 _config.ymlbaseurlを設定していなくても、GitHub Pagesではそのレポジトリ名を「自動的に」site.baseurlにしてしまうということです。 relative_urlsite.baseurlbaseurl同様に扱います。

このことについては、Michael Roseさんのウェブサイトが参考になります。

少し詳しく説明しましょう 例えば「user」という名前のGitHubユーザがレポジトリを作り、GitHub Pagesの機能をオンにしたとします。

ここで、URLの表現には3つのパターンがあることに注意してください。 絶対URL、絶対パスURL、相対URLの3つです。 なお「絶対パスURL」はここでの呼び方で、一般的な呼び方は定まっていないようです。 例えば、https://user.github.io/sample/abc.htmlをブラウザが表示しているとします。 そのときhttps://user.github.io/sample/xyz.htmlへのリンクアドレスは

「絶対URL」と「相対URL」は問題が起こりませんが、絶対パスURLでは問題が発生する可能性があります。 Jekyllのソースファイルではそのトップディレクトリをルート/にします。 これは絶対URLでのhttps://user.github.io/sample/をルート/としているということです。 ところがGituHub PagesのURLでは/https://user.github.io/が対応します。 ここにずれが発生するのです。

GitHubはこの差を埋めるためにJekyllのsite.baseurl/sampleにします。 これによりリンクは次のように変換されます。

  リンク先の記述 変換後(ローカル) 変換後(GitHub Pages)
1 /abc.html /abc.html /abc.html
2 {{ "/abc.html" | relative_url }} /abc.html /sample/abc.html
3 {{ site.baseurl }}/abc.html /abc.html /sample/abc.html

この表からローカル、GitHub Pagesでリンクが正しい(T)か正しくない(F)かは次のようにまとめられます。

  ローカル GitHub Pages
1 T F
2 T T
3 T T

2と3は正しいリンクを実現しています。 私の意見としては、2番めのrelative_urlをつけるのが最善の方法だと思います。

ところで、上の表ではローカルでは常にリンクが正しく表示されるところが気になります。 /abc.htmlとリンクを書くと、ローカルではエラーにならずにGitHub Pagesではエラーになるので、ローカルがテストとしては機能していないわけです。 ローカルとGitHub PagesのT/Fを一致させたいときは_config.yml

baseurl: /sample

を書くようにします。 これによりローカルのルートもずれるので、index.htmlをブラウザで表示するには

http://localhost:4000/sample/index.html

をアクセスしなければなりません。 http://localhost:4000/index.htmlではインデックスページにアクセスできません。

このようにすると、先程の表が

  ローカル GitHub Pages
1 F F
2 T T
3 T T

となって、ローカルとGitHub PagesのT/Fが一致し、ローカルのテストで誤りを発見できます。

baseurlを記述するかどうかはそれぞれのユーザの考えによります。 私の意見としては、baseurlをつけるのがベターだと思います。

クラスnavはスタイルシート・ファイル「style.scss」で定義されています。 「style.scss」は/assets/cssフォルダに置きます。

---
---

@import "{{ site.theme }}";

ul.nav {
  display: flex;
}
li.nav{
  list-style: none;
  margin-left: 20px;
}

(注意)このファイルの内容はcssと変わりませんが、インポートするファイルがscssなので、拡張子は.scssにします。 拡張子を.cssにすると動作しませんので注意してください。

インポートするファイル名がLiquidのオブジェクトsite.themeになっています。 site.themeの値は_config.ymlで設定したthemeキーの値で、「jekyll-theme-cayman」です。 同名のScssファイルがCaymanテーマの_sassディレクトリの中に置かれています。

「index.md」「about.md」「toc.md」のフロントマターのレイアウト設定をdefaultからhomeに変更します。 ここまでで、index.mdを表示するとコンテンツの最初に3つのリンクが横並びに表示されます。

index.mdのコナビ

コレクション

Jekyllにはコレクションという機能があります。 コレクションはページ(またはそのページを生成する元ファイル)を整理し、管理できるようにします。

例えば「ch1.md」「ch2.md」・・・は「チュートリアルの章」という括りでまとめられます。 これらを「_chapters」ディレクトリの下に入れることにより、他のファイルと区別できます。 全体としてもより整理され、分かりやすくなります。 そしてコレクションは_config.ymlの中で定義します。 コレクション名はディレクトリ名から先頭のアンダースコアを取ったものになります。

collections:
  chapters:
    output: true

※ Jekyllのver4からは「sort_by」オプションが導入され、コレクションの要素の並び順を定義できます。 例えば「sort_by: chap」とすると章の番号(各ドキュメントのフロントマター要素)で昇順にソートされます。 しかし、現時点(2022/8/23)ではGitHubのJekyllのバージョンが3.9.2であり、sort_byはサポート外です。 そこでこのチュートリアルでもsort_byを使っていません。

この定義により、Liquidのタグにおいてsite.chaptersが「chaptersコレクション」を表すようになります。 例えば、次のプログラムでは、各章のタイトルが出力されます。 forはLiquidのコマンドです。第9章に説明があります。

{% for p in site.chapters %}
  {{ p.title }}
{% endfor %}

ドキュメントのレイアウト

ドキュメント・ページではコナビに「前の章」「次の章」を加えます。 また、コナビはコンテンツの最初と最後につけることにします。 2箇所に同じコナビをつけるので、コナビを独立したファイルにし、レイアウトの中でインクルードします。

インクルード

インクルード対象のファイルは「_includes」ディレクトリに置きます。

コナビを表すパーツは下記のリストのようになり、_includes/doc_nav.htmlに保存されます。

<ul class="nav">
  <li>
    <a href={{ "/index.html" | relative_url }}>トップページ</a>
  </li>
  <li class="nav">
    <a href={{ "/about.html" | relative_url }}>Aboutページ</a>
  </li>
  <li class="nav">
    <a href={{ "/toc.html" | relative_url }}>目次</a>
  </li>
  {% if page.chap > 1  %}
    <li class="nav">
      <a href="ch{{page.chap|minus: 1}}.html">前の章</a>
    </li>
  {% endif %}
  {% if page.chap < site.chapters.size %}
    <li class="nav">
      <a href="ch{{page.chap|plus: 1}}.html">次の章</a>
    </li>
  {% endif %}
</ul>

上から10行まではhome.htmlと同じです。 {%%}で囲まれたものはLiquidのタグと呼ばれます。 ここにはプログラムのコントロール・フロー(if, else, unlessなどの条件分岐)などを書くことができます。 タグの内容が仮に値を持っても、それがただちにHTMLに書き込まれることはありません。 そこが{{}}で囲んだ場合と違います。

{% if page.chap > 1  %}
  <li class="nav">
    <a href="ch{{page.chap|minus: 1}}.html">前の章</a>
  </li>
{% endif %}

ifの条件は「そのページの章(chap)が1より大きい」すなわち「第2章以降」で、このときは「前の章」が存在します。 条件が成立する時にifとendifで囲まれた部分が出力されますが、その出力内容は「前の章へのリンク」です。

例えば第3章の前は第2章で、ファイル名は「ch2.html」(変換後なので拡張子は.mdではない)になります。 数字の2にあたる部分はLiquidのフィルター({{}}で囲まれた部分)で表されています。

{{page.chap|minus: 1}}

縦棒|は前にも出てきた「フィルター」で、左の出力を右の入力につなげます。 このときフィルターの動作はパイプの右側に記述します。 「minus」は引き算のフィルターです。 例えば第3章では「page.chap」は3なので、「minus: 1」はそこから1を引き、2になります。

Liquidには算術演算子がありません。 計算にはフィルターを使います。

{% if page.chap < site.chapters.size %}
  <li class="nav">
    <a href="ch{{page.chap|plus: 1}}.html">次の章</a>
  </li>
{% endif %}

ほとんど同じですが、site.chapters.sizeのところが新たな内容です。 変数siteにコレクション名をつけ、更にsizeをつけています。

章の数が配列のサイズより小さい、すなわち「最後の章ではない」ときに「次の章」をコナビに入れます。

ドキュメントのレイアウト

ドキュメントのレイアウトはchapter.htmlです。

---
layout: default
---
{% include doc_nav.html %}
<h1>第{{page.chap}}章 {{page.title | escape}}</h1>
{{ content }}
{% include doc_nav.html %}

前に作ったdoc_nav.htmlを2ヶ所でインクルードしています。 インクルードのおかげで短くさっぱりした記述になっています。

コナビとコンテンツの間に「第何章」というタイトルをh1タグで入れました。 タイトルにはHTMLで特別な意味をもつ文字が含まれている可能性があるので、escapeフィルターでエスケープします。 escapeフィルターは第9章で説明しています。

ドキュメント

ドキュメントのフロントマターにはchapを入れます。 例えば、第1章のドキュメントのフロントマターは次のようになります。

---
layout: chapter
title: Jekyll、GitHub Pagesとは
description: JekyllとHitHub Pagesの基礎知識
chap: 1
---

目次

目次の生成にはforループを使います。 以下はtoc.mdのソースコードです。

---
layout: home
title: 目次
description: チュートリアルの目次
---
## 目次

{% assign chaps = site.chapters | sort: "chap" %}
{% for doc in chaps %}
- [{{doc.chap}}章 {{ doc.title | escape }}]({{ doc.url | relative_url }})
{% endfor %}

下4行が目次を生成する部分です。

このようにして、各章へのリンクがMarkdownのリストとして生成されます。

今あなたが読んでいるウェブサイト「はじめてのJekyll + GitHub Pages」は、この章で説明したプログラムを使っています。 ぜひレポジトリをクローンしてレイアウトやドキュメント、目次のソースファイルを読んでください。 より一層理解を深めることができると思います。