3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Vivliostyle でテーマのフォントを変更する

Last updated at Posted at 2024-11-01

技術書典などで技術同人誌を書くとき、私は Vivliostyle 1 を利用しています。Web 技術や CSS を利用して組版する OSS です。本や原稿の製作に、日々の仕事で使っている Web 知識を活用できるので、とても重宝しています。技術書典のほかに、iOSDC Japan のパンフレット寄稿記事にも利用しており、いくつか執筆テンプレートを Vivliostyle で作成して、いつでも書けるようにしています。

生成される PDF のフォント

Vivliostyle で生成される PDF は、利用するテーマにもよりますが、一般にビルドコマンドを実行する環境のフォントが利用されます。MacBook であれば macOS のシステムフォント、Linux マシンであれば Linux のシステムフォントが使われます。執筆を MacBook で行い、印刷用 PDF の生成を公式推奨の Docker で実行すると、それぞれで利用されるフォントは異なります。これまで段落やページ数が変わるほどの大きな違いや問題は無かったので、「フォントが違うなぁ」と軽く思う程度でした。

2024/11/04 追記
気付いていなかっただけで、段落の配置が実際に異なってました。全体のページ数が変わらなかったので気付かず、見落としてた。フォントを揃えるのは大事!

執筆テンプレートを作成する際に、記事追加の PR で PDF が自動作成ができたら、レビューの助けになるだろうなと GitHub Actions 上で PDF を作成しました。無事に PDF が作成されて満足してたところ、実際にファイルを開いたらフォントが豆腐(文字化け)になっていました。困った。GitHub Actions 上で動作させる Ubuntu に日本語フォントが入っていないからです。

Actions を実行するたびに sudo apt install fonts-noto-cjk などフォントインストールを実行すれば解決しそうですが、毎回インストールするのはさすがにパフォーマンスが悪い。CI や自動化などを考えている場合に、フォントがコマンドを実行する環境に依存するのは、あまりよろしくないですね。それならば、執筆のプロジェクトにフォントを組み込んで、執筆環境が異なっても同じフォントを利用しましょう。

ローカルフォントの選定

フォントデータは Google Fonts の Noto Sans JP および Noto Sans Mono を利用しました。通常の本文には Noto Sans JP、ソースコードなどの等倍フォントには Noto Sans Mono です。Google Fonts は商用利用できる、印刷物にも利用できると、ライセンス的に問題のないフォントです。ありがとうございます。

ローカルフォントを適用させる(失敗した例)

さっそくフォントをプロジェクト内に保存して、CSS でそのフォントを設定します。

fonts.css
@font-face {
  font-family: 'Noto Sans JP';
  src: url('./Noto_Sans_JP/static/NotoSansJP-Regular.ttf') format('truetype');
}

* {
  font-family: 'Noto Sans JP';
}

そして、この fonts.css をビルド設定に加えました。

vivliostyle.config.js
module.exports = {
  theme: [
    '@vivliostyle/theme-techbook',
    'fonts.css',
  ],

対応終わった!と意気揚々にビルドしたところ、このフォント設定は有効にはなりませんでした。それどころ、コンソールに A network error occurred. と不吉なエラーメッセージが表示されました。なお、フォント適用を除いて PDF は正常に生成されています。

ちなみに、ローカルフォントではなく、Web フォントで指定するとエラーメッセージは表示されることなく、そのフォントが PDFに適用されました。不思議。

web-fonts.css
@import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');

* {
  font-family: "Roboto", sans-serif;
}

ローカルフォント適用失敗の原因

この問題を呟いたところ、Vivliostyle 開発者の MurakamiShinyu さん達に原因を教えてもらい、無事に解決しました。

theme オプションで CSS ファイルを指定する方法は、必要な外部ファイルの場所を解決できないため、フォントファイルの参照に失敗していました。そこで、フォントファイルを含めたローカルのパッケージとして定義する必要があると、教えてもらいました。

その理由から Web フォントが適用できたのは、Web URL という絶対パスなので、フォントファイルを問題なく参照できたからと考えられます。ちなみに、ローカルパスでも /Users/user/path/font.ttf のようなルートからの絶対パスなら表示できていました。

ローカルフォントを適用させる(成功した例)

私は次のような構成からなるフォントのローカルパッケージを作成しました。

フォントのローカルパッケージ
fonts
┣ package.json
┣ index.css
┣ noto-sans-jp.css
┣ Noto_Sans_JP/
┣ noto-sans-mono.css
┗ Noto_Sans_Mono/

pakage.json は次のとおりで、メインとなる index.css を参照しています。

pakage.json
{
  "name": "my-theme-fonts",
  "main": "index.css"
}

index.css は次のように、フォントの適用を行っています。このファイル内でフォント設定してもよいのですが、ファイルが肥大化してしまい可読性が下がるので、フォント設定用の CSS を作成して、それを import しています。なお、前節ではフォント適用に HTML タグを利用していましたが、Vivliostyle のフォント用の変数に修正しました。HTML タグでは柱(ページ右上)などの本文以外の文字列のフォントが適用されなかったためです。

index.css
@import url(./noto-sans-jp.css); 
@import url(./noto-sans-mono.css);

/* フォントを変更する */
:root {
  /* 本文のフォント */
  --vs-font-family: 'Noto Sans JP', sans-serif;

  /* 等幅フォント(コードブロックで利用される)のフォント */
  --vs--monospace-font-family: 'Noto Sans Mono', 'Noto Sans JP', monospace;
}

さて、フォントを設定している CSS は長くなるので後回しとして、準備が揃ったので、このローカルパッケージをビルド設定に追加しました。これでビルドすると、無事に Noto Sans JP になった PDF が生成されました。よかった。

vivliostyle.config.js
module.exports = {
  theme: [
  '@vivliostyle/theme-techbook',
  'fonts',
  ],

フォントを設定している noto-sans-jp.cssnoto-sans-mono.css は以下のとおりです。Noto Sans JP は本文に利用されるため、normal の font-weight だけでは対応できない場合があるので、font-weight それぞれのフォントを設定しました。約 50 MB ほどファイルサイズが大きくなりました。VariableFont を利用すれば、1つのフォントファイルで済みますが、それを利用して生成した PDF がフォントを埋め込んでいなかったので、やめました。

noto-sans-jp.css
@font-face {
  font-family: 'Noto Sans JP';
  src: url('./Noto_Sans_JP/static/NotoSansJP-Thin.ttf') format('truetype');
  font-weight: 100;
  font-style: normal;
}

@font-face {
  font-family: 'Noto Sans JP';
  src: url('./Noto_Sans_JP/static/NotoSansJP-ExtraLight.ttf') format('truetype');
  font-weight: 200;
  font-style: normal;
}

@font-face {
  font-family: 'Noto Sans JP';
  src: url('./Noto_Sans_JP/static/NotoSansJP-Light.ttf') format('truetype');
  font-weight: 300;
  font-style: normal;
}

@font-face {
  font-family: 'Noto Sans JP';
  src: url('./Noto_Sans_JP/static/NotoSansJP-Regular.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
}

@font-face {
  font-family: 'Noto Sans JP';
  src: url('./Noto_Sans_JP/static/NotoSansJP-Medium.ttf') format('truetype');
  font-weight: 500;
  font-style: normal;
}

@font-face {
  font-family: 'Noto Sans JP';
  src: url('./Noto_Sans_JP/static/NotoSansJP-SemiBold.ttf') format('truetype');
  font-weight: 600;
  font-style: normal;
}

@font-face {
  font-family: 'Noto Sans JP';
  src: url('./Noto_Sans_JP/static/NotoSansJP-Bold.ttf') format('truetype');
  font-weight: 700;
  font-style: normal;
}

@font-face {
  font-family: 'Noto Sans JP';
  src: url('./Noto_Sans_JP/static/NotoSansJP-ExtraBold.ttf') format('truetype');
  font-weight: 800;
  font-style: normal;
}

@font-face {
  font-family: 'Noto Sans JP';
  src: url('./Noto_Sans_JP/static/NotoSansJP-Black.ttf') format('truetype');
  font-weight: 900;
  font-style: normal;
}

Noto Sans Mono は主にソースコードの表示にしか使われない想定なので、font-weight が normal のフォントのみを設定しました。すべての font-weight を設定した方が安全ですが、Noto Sans JP で増えたファイルサイズがさらに増えるのか…と日和ったのが半分本音です。

noto-sans-mono.css
@font-face {
  font-family: 'Noto Sans Mono';
  src: url('./Noto_Sans_Mono/static/NotoSansMono-Regular.ttf') format('truetype');
  font-weight: normal;
  font-style: normal;
}

まとめ

Vivliostyle は雰囲気で利用していたので、theme オプションでパッケージの概念があったとは知りませんした。勉強になりました。

今回作成したフォントのローカルパッケージは Vivliostyle のテーマとして公開しようかとも思いましたが、再配布可能な Google Fonts とはいえ、さすがに埋め込んでパッケージとして配るのはやり過ぎかなと止めました。が、実際はどうなんでしょうかね。毎回プロジェクトごとに設定するのは面倒なので、パッケージ化した方がよいのかな?

フォントを設定するテーマを作りました(2024/11/05 追記)

フォントを設定するテーマを作りました。その詳細は次の記事でまとめました。

  1. https://vivliostyle.org/ja/

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?