フレームワークのようにベースとなるHTMLをつくる。
成果物
extends
ベースとなるHTMLをつくり、その内側の一部分だけ変更したいときがある。そのときにextends
を使う。
templates/base.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> {%- block head %}{% endblock -%} </head> <body> {%- block content %}{% endblock -%} </body> </html>
head
とcontent
というブロック要素が可変部分である。
{%- block head %}{% endblock -%} {%- block content %}{% endblock -%}
これを各テンプレートごとに少しずつ変えて書く。
- index.html
- section.html
- page.html
templates/index.html
{% extends "base.html" %} {%- block head %} <title>{{ config.title }}</title> {% endblock -%} {%- block content %} <h1>{{ config.title }}</h1> <p>{{ config.description }}</p> {% endblock -%}
まずはファイルの先頭で{% extends "base.html" %}
する。
つぎにベースで定義したblock
要素に書き出す内容を書いていく。
templates/section.html
{% extends "base.html" %} {%- block head %} <title>{{ section.title }} | {{ config.title }}</title> {% endblock -%} {%- block content %} <ul> {% for page in section.pages %} <li><a href="{{ page.permalink }}">{{ page.title }}</a></li> {% endfor %} </ul> {% endblock -%}
templates/page.html
{% extends "base.html" %} {%- block head %} <title>{{ page.title }} | {{ config.title }}</title> {% endblock -%} {%- block content %} {{ page.content | safe }} {% endblock -%}
気に食わない点
include
,import
,extends
を使い分けねばならない{% block * %}{% endblock * %}
は必須で冗長
可読性が低い。パッと見よくわからない。以下のように短く書きたかった。
base.html
<head>{$ head $}</head> <body>{$ content $}</body>
継承する側も以下のように短く書きたかった。
index.html
{$ base.html $} $head <title></title> $content <h1></h1>
罠
マクロを隠しインクルードする技はextendsで使えない
以下のようなマクロを作ったとする。
templates/macro/footer.html
{% macro footer() %} <footer>© 2021 {{ config.extra.author }}</footer> {% endmacro footer %}
マクロ呼出だけをテンプレートにする。
templates/include/footer.html
{% import "macro/footer.html" as macro %} {{ macro::footer() }}
マクロ呼出テンプレをベーステンプレでインクルードする。
templates/base.html
{%- include "include/footer.html" %}
ベースをほかのテンプレで継承する。
templates/index.html templates/section.html templates/page.html
{% extends "base.html" %}
実行するも、エラーになる。
zola serve
Failed to build the site Error: Failed to render page '/tmp/work/0/ytyaru-zola/content/archive/index.md' Reason: Failed to render 'page.html' (error happened in 'base.html'). Reason: Macro namespace `macro` was not found in template `base.html`. Have you maybe forgotten to import it, or misspelled it?
「macro
というマクロ名前空間が見つからない」と怒られた。おそらく「import
はファイルの先頭に書かねばならない」ルールに抵触したせいだろう。今回のテンプレではインポートがファイルの途中に書き出されてしまう。以下のように。ファイルの先頭にないせいで正しくインポートできず、マクロ名前空間も存在しない。よって本件のエラーになったものと推測する。
<!DOCTYPE html> <html> ... {% import "macro/footer.html" as macro %} {{ macro::footer() }} ... </body> </html>
今回わかったことは以下。
- インポートとマクロ呼出は直接ベース(
extends
元)に書かねばならない
それだとゴチャゴチャになるんだよなぁ。それを避けたくてマクロ呼出をインクルードする技を使ったのになぁ。
残念。
include
, macro
(import
), extends
のちがい
フレームワークにすべき部分はどこか?
その答えは全ページに共通している部分だ。かなり限られていると思う。<html>
や<body>
など必須の要素のみが対象だ。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> {%- block head %}{% endblock -%} </head> <body> {%- include "include/header.html" %} {%- block content %}{% endblock -%} {%- include "include/footer.html" %} </body> </html>
lang
属性
これはページごとに変わりうる
メタデータ
ファビコンやビューポートなら変わらないかもしれない。
<meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="shortcut icon" href="favicon.svg">
個人サイトなら著者も同じだろう。
<meta name="author" content="{{ config.extra.author }}">
タイトル、説明はほぼ違う。
<title>{{ page.title }} | {{ config.title }}</title> <meta name="description" content="{{ page.description }}">
変数を使えば共通化できるかもしれないが、page
やsection
など変数自体が別物だと統一できない。
<title>{{ section.title }} | {{ config.title }}</title> <meta name="description" content="{{ page.description }}">
条件分けすれば共通化できるか? 未確認。
<title> {%- if page and page.title %}{{ page.title }} | {% endif -%} {%- if section and section.title %}{{ section.title }} | {% endif -%} {%- if config and config.title %}{{ config.title }}{% endif -%} </title>
CSSは変わりうる。メインコンテンツ次第。
<link rel="stylesheet" href="/css/black.css""> <link rel="stylesheet" href="/css/white.css""> <link rel="stylesheet" href="/css/mobile.css" media="screen and (max-width: 899px)"> <link rel="stylesheet" href="/css/pc.css" media="screen and (min-width: 900px)">
メインコンテンツ。これはもう絶対に違う。パターン化できたとしてもセクション単位。サイト全体ではほぼ間違いなく変わる。[zola][]においてもindex.html
, section.html
, page.html
の3種類の異なるテンプレートがあるくらいだ。最低でも「記事ページ」とその「一覧ページ」の2種類は必要だ。それらの内容が同じわけがない。
<main><article><h1>{{ page.title }}</h1><p>{{ page.description }}</p>{{ page.content | safe }}</article>bbbbbbbbbbbbb</main> <aside> <nav class="pagination"> {% if page.earlier %}<a class="previous" href="{{ page.earlier.permalink }}">‹ {{ page.earlier.title }}</a>{% endif %} {% if page.earlier and page.later %} {% endif %} {% if page.later %}<a class="next" href="{{ page.later.permalink }}">{{ page.later.title}} ›</a>{% endif %} </nav></aside> <aside><!-- ad --></aside>
<main>
/<aside>
/<article>
の大枠くらいは共通できそうな気がする。
<main><article><h1>{{ page.title }}</h1><p>{{ page.description }}</p>{{ page.content | safe }}</article></main>
よくある前後記事リンク。これは欲しいときとないほうがいいときがありそう。
``html
メイン以外。広告とかサイドバーなど。でもこれって、そもそも存在しないほうが嬉しいものなんだよね。共通化して全ページで出したら邪魔すぎて殺意をいだくやつ。
もし`<body>`タグ内で全ページ共通するところがあるとすれば`<header>`や`<footer>`くらいだろう。 * `about` * `author` * `archive` * `feed` * `sitemap` * `search` * `language` * `style` * `Github Repository` * `twitter` * `copyright` * `license` * `Site Policy` パンくずリストは階層によって変わる。なので全ページ共通にはできない。マクロを使えば共通化できるかもしれないが、今の知識ではわからない。 こうして考えてみると、以下のような問題がある。 * 共通化できるか? * どうやって共通化する?: `include`, `macro`(`import`), `extends` そもそも共通化できるかどうかわからない。その答えにたどりつくには[zola][]や[tera][]に精通している必要がある。そして、それができているなら、共通化する手段についても当たりがつく。 結局、[zola][]や[tera][]を学ぶしかない。 * `<html>` * `<head>` * `<meta charset="utf-8">` * `<title>{{ page.title }} | {{ config.title }}</title>` * `<meta name="description" content="{{ page.description }}">` * `<meta name="author" content="{{ config.extra.author }}">` * `<meta name="viewport" content="width=device-width, initial-scale=1">` * `http-equiv` * `<meta http-equiv="content-language" content="ja">` * `<html lang="ja">`が正しい * べつにいらない * `<meta http-equiv="default-style" content="default.css">` * OGP * `<meta property="og:title" content="ページタイトル">` * `<meta property="og:type" content="article">` * `<meta property="og:site_name" content="サイト名">` * `<meta property="og:url" content="ページURL(絶対パス)">` * `<meta property="og:image" content="ページOGP画像パス(絶対パス)">` * `<meta property="og:description" content="ページ説明文">` * https://ogp.me/ * `og:audio` * `og:video` * `og:image` * `og:type` * `music.song` * `music.album` * `music.playlist` * `music.radio_station` * `video.movie` * `video.episode` * `video.tv_show` * `video.other` * `article` * `book` * `profile` * `website` * `` * `` * `` * `` * `` * `` * `` * `` * `` * `` * `` * `` * `` * `` * Audio * `og:audio` * `og:description` * `og:determiner` * `og:locale`: `ja_JP` * `og:locale:alternate`: `en_US` * `og:site_name` * `og:video` * `<>` * `<body>` # 所感 # 対象環境 * <time datetime="2021-08-02T17:28:01+0900" title="実施日">2021-08-02</time> * [Raspbierry pi](https://ja.wikipedia.org/wiki/Raspberry_Pi) 4 Model B * [Raspberry Pi OS](https://ja.wikipedia.org/wiki/Raspbian) buster 10.0 2020-08-20 [※](http://ytyaru.hatenablog.com/entry/2020/10/06/111111) * [bash](https://ja.wikipedia.org/wiki/Bash) 5.0.3(1)-release
$ uname -a Linux raspberrypi 5.4.83-v7l+ #1379 SMP Mon Dec 14 13:11:54 GMT 2020 armv7l GNU/Linux