はじめに

しばらく閉鎖状態となっていた当サイトですが、ドメインは自動更新で放置していたので、久々に復活させることにしました。

とは言っても一日に何度も更新させるような意欲は無いため、不定期で更新していく予定です。

再始動にあたり、ウェブサイトそのものをある程度見直しており、できるだけシンプルで高速に動作するように1から作り直しました。

サイト再構築を行うにあたってはjxck.ioさんおよびsuzukikenichi.comさんが大変参考になりました。この場でお礼申し上げます。

ウェブサイト構成

ここでは当サイト、pr1sm.comを構成している各要素について簡単に説明します。

Server

使用しているホスティングは以前と変わらずVultrのままです。

低コストなだけでなく性能も充実しているという、非常にコストパフォーマンスが良いサービスなので重宝しています。

Vultrに関する詳細は記事化していますので、興味があればご覧ください。

ウェブサーバはずっとNGINXを使い続けています。

軽量かつ高速で動いてくれるのでスピード厨にとっては神のような存在です。

2024-04-03追記

長年Vultrを利用していましたが、毎月のサーバのコストを考えた結果、Cloudflare Pagesに移行しました。

これにより、サーバ、TLS設定、CSPなどはCF依存のものになっています。

SSGはCF PagesがZolaに対応していたため、そのまま移行することができました。

ただし執筆時点ではバグがあるため、そのまま導入することができず、バイナリをリポジトリに置いて展開する必要がありました。

TLS

数年前はSSL/TLSというように、TLS(Transport Layer Security)の他にSSL(Secure Socket Layer)も付け加えていましたが、今となってはTLS主体なので、もはやSSLを付ける必要はないかもしれません(とはいえ設定でSSLの文字が入っている項目もあります)。

また、現時点ではサーバにHTTP/2を適用させていますが、もうしばらくしたらHTTP/3に更新しようと考えています。

HTTPS化に必要な証明書にはLetsEncryptを使用していますが、非常に簡単に導入することができて自動更新も対応しているので、本当にありがたいご時世になったと感じます。

昔は今は亡きStartSSLの証明書を使うなどしていましたが、当時と比べてもLetsEncryptの使いやすさには涙が出ます。

TLSの設定にはMozillaのSSL Configuration Generatorがとても便利でした。

TLSのセキュリティチェックは定番のSSL LabsのSSL Server Testが便利です。

CSP+SecurityHeaders

当サイトではContentSecurityPolicyおよび複数のSecurityHeadersを適用しています。

そこそこ堅めに設定していますが、その状態でどれくらいまでのサイトなら構築できるのかというテストも兼ねています。

現在の設定ではscript-srcselfにしていますが、本来はstrict-dynamicを使いつつhash指定されたJSのみを使うことを考えていました。

しかし、chromeとは異なりfirefoxではインラインコードしかhash指定できないようなので若干妥協しています。もし利用可能になったり、代替策があればselfは廃止するつもりです。

CSPの設定にはMozillaのObservatoryやGoogleのCSP Evaluatorがとても参考になりました。

SecurityHeadersの設定に関してはOWASP Secure Headers Projectおよびsecurityheaders.comが大いに役立っています。

なお、CSPやSHで扱うレポートには、securityheader.comの創設者であるScottHelme氏が設立したReportURIという便利なサービスがあります。

HTML

以前のサイトではWordPressを使用していましたが、全体的に軽量で動くものが欲しかったため、Rust製の静的サイトジェネレータ(Static Site Generator)であるZolaを用いてウェブサイトの構築を行っています。

Zolaの利用には一定の学習が必要ですが、依存関係にあるファイルが無く、そして高速なビルドが可能なことからとても使いやすいものとなっています。

当サイトではZolaの導入および設定方法を記した記事を作成しています。もし興味があればご覧ください。

また、Zolaでは記事の執筆にマークダウンが必要となっているため、その際のエディタとしてAtomを利用していました。

AtomはGithub社によって制作されたテキストエディタであり、数千種類もの拡張機能があるため、非常にカスタマイズ性に優れています。

しかし、2022年6月8日にGithubがAtomの開発停止を宣言したため、代替としてVisual Studio Code(VSCode)を使用することにしました。

VSCodeはAtomと同様に拡張性があるだけでなく、軽量さも持ち合わせているので多くの人々から利用されています。

2024-10-02追記

今更ですが、ダークモードにも対応しました。

これはOSのモードによって自動的に切り替わるスタイルになっています。

Markdown

Markdown(md)はZolaが必要とする記法をもとに作成します。

テンプレートエンジンは同じくRust製のTeraが使われています。

テンプレートは以下の通りです。

+++
title = "タイトル名"
description = ""
date = 2022-01-14
updated = 0000-01-01

draft = true

[taxonomies]
categories = ["web"]

[extra]
thumb = "ファイル名.jpg"

+++

ここから概要文(summary)

<!-- more -->

ここから本文

descriptionについてはテンプレートを改変しており、<!-- more -->以前の文章(Zolaではsummaryとして扱われる)をエスケープ処理および短縮することで別途用意しているため、実際には使っていません。

記事のアップデート時間はupdated = 0000-00-00で作成できますが、テンプレート内にとりあえず置いておこうとupdatedのみで中身がない場合(月日が00の場合も含む)はビルド時にエラーが発生してやや面倒なので、ユーザ作成([extra])で作ろうとも考えていました。

しかしながら、Zolaが自動生成するsitemap.xmlatom.xmlなどにはupdatedの時間も反映されることから、改変する必要が出てきます。

なのでほんの少し手間ですが、Zolaの構成を保つことを優先にして記事の更新を行うときに限りupdatedを追記するようにしています。

これらテンプレートのソースは以下のリンクに置いてあります。

drafttrueにすることでビルド時に公開設定にならないものです。

[taxonomies]はカテゴリやタグ等を設定することができます。ただし、事前にconfig.tomlでの設定が必要です。

[extra]は先述したようにユーザ作成の自由に使える部分であり、このケースではthumb = "ファイル名.jpg"が記事のアイキャッチ扱いとして設定しています。当サイトではアイキャッチ画像は表示していないので内部データのみが反映されます。

構造化マークアップ

構造化マークアップはmicrodataを使用しています。

JSON-LDによるマークアップも検討していますが、気が向いたら対応したいとは考えています。

また、最近気付いたのですが、JSON-LDはインライン記述が必要になるものの、type="application/ld+json"の場合はインラインでもContentSecurityPolicyに引っかかりません。

そのため、動的にJSON-LDのマークアップデータを生成することで対応できますが、マークアップテストでは反映されなかったりすることもあるようです。

ただし、Googleによると動的に生成されたJSON-LDでもサポートはされるとのこと。

CSS

デザインは以前と同じくシングルカラムを採用しています。

HTTP/2が登場する前は、基本的にCSSなどのコンテンツは一つにまとめ、リクエスト数を減らすことが推奨されていましたが、現在ではサーバの設定によって並列ダウンロードができるようになったため、それを活用するために複数のCSSに分割しています。

他にもloadCSSという方法でCSSを非同期で読み込むことも考えましたが、できるだけContentSecurityPolicyを尊重したかったため、インライン記述が必要となる方法は現時点では採用していません。

その代わりにrel=preloadを使っており、対応しているブラウザではファイルの事前読み込みを行うようにしています。

また、ブラウザがデフォルトで出力するスタイルをなるべく使用することで、CSSの記述量を減らしました。

JS

基本的にあまり必要とされないJSは極力使わないようにしています。

現時点ではServiceWorker用のファイルが2つ(sw-loader.jsおよびsw.js)とLazyload用に1つ(lazysizes.js)を設置しており、こちらもrel=preloadで事前読み込みを行っています。ただ、Lazysizesに関してはブラウザでのLazyloadサポートが圧倒的になると同時に利用者層も厚くなれば廃止する予定です。

ServiceWorkerは4つのキャッシュセクションに分類(Core,Pages,Images,Assets)し、キャッシュ時間はデフォルトの24時間のままにしています。

もともとSWはIE11に対応していませんが、構文によってはエラー文章が発生して鬱陶しかったのでBabelを使ってそれをスルーできるようにコードを変換しました。

アクセス解析には興味がないのでGoogleAnalyticsは入れていませんし、サイトが激重になる原因筆頭であるAdsense関連も一切使用していません。

以前のサイトではリンクをマウスオーバーすることで先読みを行うInstantClickを採用していましたが、そもそも構成上サイト内を複数巡回する人は少なく、Lazyloadに比べるとそこまで必要にはならないと結論に至ったため、現在は使っていません。

ちなみにInstantClickは随分前から更新されていませんが、有志によって改良が加えられたバージョンが公開されているので、興味のある方は見てみるといいかもしれません。

また、類似したツールにはInstantClick作者によるInstantPageや、GoogleChromeLabsが制作したquicklinkがありますが、それらを用いた統計によると有益な効果がほとんど見られなかったようなので、こちらも使用していません。

Images

基本的に<img>にはloading="lazy"およびdecoding="async"の両方を付与させており、幅広いブラウザで読み込み最適化を行います。

もしブラウザ提供のLazyloadが利用できない場合には、代替策としてJavaScriptを用いてLazyloadを作動するLazysizesを適用します。

Lazysizesそのものには特に変更したい点が無かったため、デフォルトのまま使用しています。

使用する画像(大抵はjpgとwebp)は事前にエンコードをしており、jpgではmozjpeg、webpはgoogleが提供しているものを使用します。

Qualityは共に75に設定しており、どちらも非可逆圧縮で処理しています。

pngはほとんど使用しない予定ですが、事前エンコードにはzopflipngを使用しています。

zopflipngを実行する際には--lossy_transparent --iterations=20 --filters=0meを設定しています。

しかし、zopflipngは動的にエンコードを行うには時間がかかりすぎるため、サーバ内でリアルタイム処理を行ったり、大量のファイルを扱う場合には、optipngの改良版であるoxipngがおすすめです。

ちなみにZolaを経由している外部ファイル(CSS,JS,IMG等)のほとんどは設定によって?h=hashというクエリを付与しており、ファイルが変更されるとクエリが変更されるいわゆるキャッシュバスター(cachebust)システムになっています。

それに加え、integrity属性も追加することでファイルの整合性もチェックしています。

圧縮

大抵のファイルは事前にgz圧縮およびbr圧縮を行っています。

ヘッダもHTTP/2によって圧縮(HPACK)をされているので通信量を削減できます。

また、css類はminify(縮小化)することでファイルサイズの削減も行っています。

gz圧縮にはdeflate互換性のあるzopfliを使います。強度は--i1000で処理しています。

brotli(br)圧縮は処理が異なるためdeflate互換性がありません。しかし最近のブラウザの多くは既に対応済みです。

br圧縮の強度に関してはデフォルトでも最大設定なので、そのまま使用しています。

事前圧縮されたファイルはクライアントにそのまま送信しており、ブラウザがbr圧縮に対応していれば、brの方をクライアントに提出し(brotli_static on;)、対応していなければgzを渡します(gzip_static on;)。

仮に両方の圧縮に対応していない場合でも、nginxのgunzip機能(gunzip on;)により、gzファイルを解凍してから送信します。

事前圧縮していないコンテンツに関してはnginxによるgzもしくはbr圧縮が動的に行われます。

圧縮強度は最低でもそこそこ圧縮できるため、動的圧縮を行う場合はサーバ負荷の軽減を優先にgzではgzip_comp_level 1;、brではbrotli_comp_level 1;に設定しています。

余談ですが、圧縮ファイルを受信する際、セキュリティソフトによってはContent-Encodingx-content-encoding-over-networkに書き換えられる模様。

このケースではサーバから圧縮ファイルを受け取っているものの、セキュリティソフトが間に入ってチェックしているため、ブラウザではファイル展開後として扱われます。

とはいえ、レスポンスヘッダの表示が変わっているだけなので、通常使用においては特に問題はありません。

音声や動画

現時点では音声や動画は当サイトでは取り扱わない予定です。

以前のサイトではYoutubeの動画をiframeでembedしていましたが、CSPでの対応が面倒なのと大して使わないコンテンツにCSSやJSのリソースを使うのはもったいないとして、埋め込み化をやめました。

feed

これまではRSS Feedでの配信を行っていましたが、もはや需要がほとんど無いので配信停止することにしました。

構文およびマークダウン一覧

以降からは、このサイトで用いられる構文(マークアップ)およびマークダウンのテストサンプルを記述します。

マークダウン記法についてはCommonMarkのMarkdown Referenceで簡単な説明を見ることが可能です。

各HTML要素についてはMozilla Developer NetworkのHTML 要素リファレンスにて詳細を確認できます。

セクション2

セクション(section)は<h1><h2><h3><h4>で使用される見出しとなる構文です。

マークダウンでは#の数によって振り分けが行われます。

例では## テストと記述することでテストという文字が<h2>で展開されます。

ちなみにこの段落は### セクション2であり、#が3つ付いているため、<h3>です。

また、各セクションのheading(h2~)前後には<section>タグを設置しています。

Zola側でビルド時にそれぞれのhタグ前後にsectionを自動で付与してくれれば楽なのですが、現時点では未対応であり、対応してくれるかどうかも不明です。

セクション3

ここは<h4>です。

リスト

これは<ul><ol>の中に<li>を用いることで箇条書きのリスト化を行います。

数回半角スペース(基本的に2,3回以上)もしくはtabによるインデント1回を挿入することで入れ子を作成することも可能です(ただしolを使っている際に番号指定のリストを行った箇所では入れ子できない場合があります)。

表示上の関係から、基本的に入れ子は2つまでに留めます。

順序なしリスト

<ul>では順番が関係ない要素で用いられます。

マークダウンは- 要素によって作成されます。

入れ子は前要素の次の行で - 要素(-の前に半角スペース2回かタブ1回)を入力することで作成できます。

  • トマト
    • ミニトマト
  • レタス

入れ子の入れ子を追加するには-の前に4回スペースを入力します。

少しややこしくなりますが、各種タグをリスト内で入れ子内に加える場合は4回半角スペースもしくはタブ2回をタグの前に入力します。

ただし、<pre>のような複数行に渡る場合のある特殊なタグを入れ子内に加える場合は```の代わりに8回半角スペースもしくはタブ2回を対象となるすべての行に加えることで可能となります。

順序ありリスト

<ol>では順序が必要となる要素で用いられます。

マークダウンは1. 要素で作成されます(次の行からは数字は加算しなくても可)。

  1. フライパンに油を入れて熱する。
    1. 表面加工されているものでは空焚きしないように注意。
  2. よくといた卵を流し込み、少しの間混ぜる。
  3. 全体に火が通ったらお皿に盛り付けて完成。

引用

引用には<blockquote>が用いられます。

マークダウンでは> 文章で表示を行います。

ここは文章の引用部分です。 複数行に渡って記述することも可能です。

>> 文章で二重引用を用いることもできます。

引用元の最後には<cite>タグで囲んだURLをリンク化させて記載します。

https://example.com

説明リスト

説明リストでは<dl>および<dt><dd>を用いて表示されます。

大抵のマークダウンには対応していないため、手動でタグを用いて記述する必要があります。

Zolaでは非対応です。

<dl>は説明リスト(description list)を意味し、リスト全体を囲みます。

<dt>は説明用語(description term)を意味し、リスト内の各名前を扱います。

<dd>は説明詳細(description details)を意味し、<dt>ごとの説明を記載します。

ここは説明用語です(dt)
ここは詳細説明(dd)です
りんご(dt)
赤くて甘い(dd)

テーブル

テーブル(table)も基本的にはマークダウンに対応していないため、手動でタグを付ける必要があります。

Zolaではマークダウンに対応しています。

<table>は使用する表全体を囲みます。

<thead><th>タグをグループ化します。

<tr>はtable rowを意味し、表に対して水平方向の部分をグループ化します。

<th>はtable headerを意味し、表の見出しおよびタイトルとなる部分を作成します。

<td>はtable dataを意味し、見出しおよびタイトルに対応する内容(データ)を作成します。

マークダウンでは以下のような形式でテーブルを出力することが可能です。

|a  |b  |c  |
|---|---|---|
|1  |2  |3  |
|4  |5  |6  |

出力結果はこうなります。テーブルは手打ちで行うと非常に面倒なので、マークダウン対応可能だとかなり手間が省けます。

abc
123
456
ファイル名(この行はth)元サイズ(byte)gz圧縮後(byte)削減率((元サイズ-圧縮後)/元サイズ)
pr1sm-logo.svg(この行はtd)30220631.78%
favicon.ico(この行はtd)1,07822878.84%
manifest.min.webmanifest(この行はtd)56124057.21%
ファイル名(この行はth)サイズ(byte)
body.min.css.br(この行はtd)117
header.min.css.br(以下略)91
main.min.css.br138
markdown.min.css.br212
footer.min.css.br131
合計689

画像表示

画像は<picture>タグを用いて画像を分岐させながら表示します。

基本的にjpgを使いますが、ブラウザがwebpに対応していれば代わりにそれをクライアントに出力します。

AVIFはまだ対応できるブラウザが少ないため、今後大幅にシェアが増えた場合に追加します。

また、記事内の画像すべてに<figure>および<figcaption>を使用することで画像の補助を行います。

ここはfigcaption

ページ内で表示する画像サイズは最大widthが480px、aタグを経由して直接画像を表示する場合は最大width960pxを用います。

コード

コードは<code>を用いることで表示します。

マークダウンは`コード`です(`は半角を使う)。

また、3連続のバッククオート同士でコードを囲う(```コード```)ことで<pre>も適用され、複数行に渡って表示することが可能になります。

test.html

<p>テスト</p>
<p>テスト2</p>

おわり。