page.html
, section.html
ではルート相対パスを使おう。もしファイル相対パスにするとURL末尾に/
をつけたら参照できなくなってしまう。
💀罠
静的サイトジェネレータzolaは、おなじページを以下のような異なるURLで参照できてしまう。
{base_url}/about
{base_url}/about/
このときファイル相対パスだと、一階層分../
の違いが生じてしまう。よってCSSを参照するには以下のようなコードにせねばならない。
<!-- {base_url}/about --> <link rel="stylesheet" href="css/style.css"> <!-- {base_url}/about/ --> <link rel="stylesheet" href="../css/style.css">
だが、これにはいくつもの問題がある。
- 冗長である
- すべての深さを網羅せねばならない(メンテ大変。バグの温床)
- 必ずエラーになる(どれかひとつしか有効でない。それ以外はエラー。ブラウザの開発ツールにあるコンソール参照)
⭕対処
よって、zolaではpage.html
, section.html
のようなテンプレートでURLを指定するとき、ルート相対パスをもちいるべきだ。なぜならそれらテンプレートは、異なる深さの階層で参照されうるから。
<link rel="stylesheet" href="/css/style.css">
基礎として、HTMLでURL指定するときは以下の要点を理解しておく必要がある。
パス表記方法 | HTML内パス | URLが{base_url}/about/ 時のHTML内パス |
---|---|---|
絶対パス | {base_url}/css/style.css |
{base_url}/css/style.css |
ルート相対パス | /css/style.css |
{base_url}/css/style.css |
ファイル相対パス | css/style.css ./css/style.css ../css/style.css |
{base_url}/about/css/style.css {base_url}/about/css/style.css {base_url}/css/style.css |
先頭に/
があるかないかで参照パスが変わってしまう。これが気づきにくいせいで罠になる。文字としても小さくて気づきにくい。また、URLが{base_url}
のときはおなじ参照パスである。なのにルートよりも下のパス、たとえば{base_url}/about/
になると違う参照パスになる。これもまた気づきにくい一因だ。
詳しくみていこう。
使い分け
方法 | 動機 |
---|---|
絶対パス | 異なる階層から参照されうる。 |
ルート相対パス | ドメインを省略したい。異なる階層から参照される。 |
ファイル相対パス | パスも省略したい。同じ階層からしか参照されない。 |
<link rel="stylesheet" href="https://example.com/css/style.css"><!--絶対パス--> <link rel="stylesheet" href="/css/style.css"><!--ルート相対パス--> <link rel="stylesheet" href="css/style.css"><!--ファイル相対パス--> <link rel="stylesheet" href="./css/style.css"><!--ファイル相対パス--> <link rel="stylesheet" href="../css/style.css"><!--ファイル相対パス-->
zolaではルート相対パスを使うべき。なぜならzolaのページは必ず、末尾に/
がつくときとつかないときの2種類ある。よって異なる階層から参照されることを想定したパス指定をすべきだ。
❌ダメ
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="./css/style.css">
参照するURLの先頭になにもつけないか./
をつけることで、ファイル相対パスになる。
ファイル相対パスは、現在のHTMLファイルが存在するディレクトリからの相対パスだ。このとき、このHTMLがテンプレートであり、異なる階層にあるページから参照される場合、CSSを参照できなくなることがある。
以下コードのように全パターンを網羅すれば参照できなくはない。
<!-- {base_url}/about --> <link rel="stylesheet" href="css/style.css"> <!-- {base_url}/about/ --> <link rel="stylesheet" href="../css/style.css">
けれど面倒だし、抜けや漏れが生じうる。また、必ずどれかひとつしか参照できず、それ以外はエラーになってしまう。ブラウザの開発ツールでコンソールを開けばわかる。それは好ましくない。
よって、複数の異なる階層から参照されるファイルは、絶対パスで指定するか、またはルートからの相対パス(ドメイン省略)で指定すべきである。
⭕OK!
<link rel="stylesheet" href="/css/style.css">
参照するURLの先頭に/
をつけることで、ルート相対パスになる。
ルート相対パスは、ルートディレクトリ(ドメイン)からの相対パスだ。ルートとはURLでいうと{base_url}
だ。config.toml
のbase_url
キーで指定された値である。デフォルトはhttps://example.com
。ローカルサーバで起動したならhttp://127.0.0.1:1111
。またはzola build
したときのpublic/
直下だ。
ルート相対パスならどの階層のURLから参照されたとしても、おなじ表記でおなじパスを示すことができる。
HTMLにおけるURL参照
これはzolaのせいではなくHTMLやURLの参照仕様だと思われる。そこで、あらためてHTMLにおけるURL参照について整理してみた。
{base_url}
=https://example.com
とする。このときstyle.css
ファイルへのURL指定方法は以下の4通りある。
パス | 意味 |
---|---|
style.css |
現在HTMLが存在するディレクトリからの相対パス |
./style.css |
現在HTMLが存在するディレクトリからの相対パス |
/style.css |
{base_url} からの相対パス |
https://example.com/style.css |
絶対パス |
絶対パスは明確だからわかりやすい。これを使えば今回の罠にかかることもない。ただ、ドメイン名が変更されたりしたときなどで変更が面倒になる。なので相対パスを使いたい。だが、その相対パスが厄介だ。
相対パス
問題は相対パスだ。わずかな表現のちがいでありながら、まったくことなるパスを指す。これがじつに紛らわしい。
パス | 意味 |
---|---|
/style.css |
{base_url} からの相対パス |
style.css |
現在HTMLが存在するディレクトリからの相対パス |
./style.css |
現在HTMLが存在するディレクトリからの相対パス |
さらにまとめてみる。
相対パスには2種類ある。基準となるパスが違う。
基準 | URL先頭 |
---|---|
ルートディレクトリ({base_url} ) |
/ |
現在HTMLディレクトリ | なにもつけない or ./ |
Linuxのファイルシステムに似ている。ルートは/
で表現されるから。先頭/
の相対パスはドメイン名を省略できるものだと覚えておけばいい。
URLが{base_url}/about/
だとしたら、以下のようになる。
相対パス | 参照パス |
---|---|
/style.css |
{base_url}/style.css |
style.css |
{base_url}/about/style.css |
./style.css |
{base_url}/about/style.css |
現在HTMLが存在するディレクトリを基準にして、その親をたどっていくパス指定もできる。
パス | 意味 |
---|---|
../style.css |
現在HTMLが存在するディレクトリからの相対パス(親ディレクトリ) |
../../style.css |
現在HTMLが存在するディレクトリからの相対パス(2親ディレクトリ) |
たどる親の数だけ../
を足していけばいい。
区別するために名前をつける。
名前 | 例 | URLが{base_url}/about/ 時のパス |
---|---|---|
ルート相対パス | /style.css |
{base_url}/style.css |
ファイル相対パス | style.css ./style.css ../style.css |
{base_url}/about/style.css {base_url}/about/style.css {base_url}/style.css |
ファイル相対パス
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="./css/style.css">
パスの先頭になにもつけないか./
をつけると、現在ファイルがあるディレクトリからの相対パスになる。
このとき、URLが{base_url}/
のように末尾に/
がつくとCSSが参照できなくなってしまう。なぜならつぎのようなパスになるからだ。
URL | 参照パス |
---|---|
{base_url}/about |
{base_url}/css/style.css |
{base_url}/about/ |
{base_url}/about/css/style.css |
zolaのstatic/css/style.css
にファイルを作ったとする。このときzola build
するとpublic/
配下には/css/style.css
に出力される。URLで参照するなら{base_url}/css/style.css
だ。
項目 | 値 |
---|---|
作成パス | $SITE_ROOT/static/css/style.css |
出力パス | $SITE_ROOT/public/css/style.css |
URL | {base_url}/css/style.css |
実際にCSSが存在するパスは{base_url}/css/style.css
なので以下のようになる。
URL | 参照パス | 存在是非 |
---|---|---|
{base_url}/about |
{base_url}/css/style.css |
⭕ |
{base_url}/about/ |
{base_url}/about/css/style.css |
❌ |
URL末尾に/
があるかないか。それだけで参照できなくなってしまうバグとなる。もうそれだけでも大問題なのだが、さらに問題がある。
CSS参照するHTMLはテンプレートで共有することが多いだろう。とくにpage.html
は異なるセクションの単一ページすべてに流用される。このとき罠になるのは、その単一ページが存在するパス階層がちがうという点だ。たとえば/about
, /about/
, /blob/2021-08-01/
のように。
それぞれのページにおいて存在する階層がちがうなら、相対パスも深さのちがいを考慮せねばならない。たとえばabout
, about/
の2階層分なら以下のようになる。
<!-- {base_url}/about --> <link rel="stylesheet" href="css/style.css"> <!-- {base_url}/about/ --> <link rel="stylesheet" href="../css/style.css">
ほかにもセクションがあれば/blob/2021-08-01/
のようになる。さらに、セクションの中に子セクションを作ることもできる。無限に階層を深くできるのだ。では、一体いくつの階層パターンを用意すればいいのか。漏れや抜けだってありうる。
また、たくさんURLパターンを用意したところで、実際に存在しているのはひとつだけだ。それ以外のURLは参照エラーになってしまう。ブラウザの開発ツールでコンソールを開いたらエラーになっているのがわかる。
ファイル相対パスで指定するのは非現実的だ。
よって、異なる階層から参照されるときはルート相対パスで指定すべきである。
ルート相対パス
<link rel="stylesheet" href="/css/style.css">
パスの先頭に/
をつけると、ルートからの相対パスになる。
このときはURLの末尾に/
があってもなくても、CSSを参照できる。
なぜならURLに関わらずパスは必ず{base_url}/css/style.css
になるからだ。
結論
異なる階層から参照されうるときはルート相対パスを使おう。zolaならテンプレートであるpage.html
, section.html
ではルート相対パスを使うべし。もしファイル相対パスにすると、URL末尾に/
がついたら参照できなくなってしまう。
つまるところ、URL指定するときは以下の要点を理解しておけばよい。
パス表記方法 | HTML内パス | URLが{base_url}/about/ 時のHTML内パス |
---|---|---|
絶対パス | {base_url}/css/style.css |
{base_url}/css/style.css |
ルート相対パス | /css/style.css |
{base_url}/css/style.css |
ファイル相対パス | css/style.css ./css/style.css ../css/style.css |
{base_url}/about/css/style.css {base_url}/about/css/style.css {base_url}/css/style.css |
所感
こういう小さい罠ってすごく腹が立つ。なんなの? こんな些細なことを気にしなきゃいけないの? バカなの? 私がバカなんだろうな。知ってた。
対象環境
- Raspbierry pi 4 Model B
- Raspberry Pi OS buster 10.0 2020-08-20 ※
- 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