created_at
updated_at
tags
toc
headings

Noto Sans Hinted と font-feature-settings: 'palt'

Intro

Noto Sans のサブセット生成を見なおし、 Noto Sans Hinted から pyftsubset で生成し、ついでに font-feature-settings を有効にした。

作業と検証の記録を兼ねて、実施結果を記す。

fonttools

これまで、フォントのサブセットの生成には以下の 2 つのツールを使用していた。

しかし、 macOS を Catalina にあげたところ、これらが起動できなくなり、フォントが生成できなくなった。

これまで GUI で行なっていたが、せっかくなので自動化するために、代替コマンドを探し、プロセスを組んだ。

いくつかツールがあるが、今回は fonttools に同梱された pyftsubset を採用することとした。

pyftsubset

これまでは、使用しそうなフォントをリストアップし、そのリストを元にフォントを生成していた。

しかし、更新への追従も面倒になったので、やはり記事で利用している文字を全てリストアップするスクリプトを書くことにした。

ところが、単純に全ての文字を取ると、一度しか使用しない文字が増えてしまう。理由は以下のようなエントリがあるからだ。

通常、記事中に結合文字、絵文字、サロゲートペアなどは基本的に使わないが、それ自体を解説するこの 2 つのエントリはそれが含まれてしまう。

フォントに含まれない文字は、スタイルが変わってしまい違和感があるため、これまでは見つけ次第含むように更新していた。

しかし、そういった文字はほぼサンプルコードとしてコードブロック(<code>)に含まれており、かつそこには MONO font が当たっている。

そこで、コードブロックに含まれてない特殊な文字を全てコードブロックに含むように記事を修正し、 HTML から <code> を全て除いた文字群をサブセットの対象とした。

対象を subset.txt に保存し、変換は以下のようにした。

$ pyftsubset NotoSansCJKjp-Regular.otf --text-file=../subset.txt --layout-features='*' --flavor=woff2 --output-file=NotoSansCJKjp-Regular-Jxck-20191011.woff2

layout features

ところが、生成したフォントが従来の倍近いサイズになっていた。

  • 353.1K: 従来
  • 606.6K: 更新後

コマンドヘルプを見ながら適当につけた以下のオプションが問題である。

--layout-features='*'

この layout features は、 Open Type のフォントが含む、ヒント情報を含めるという指定だ。

Open Type がいくつかの情報を持っていることは薄々知っていたが、以下の理由から特に考えずにきた。

  • 従来使用していたツールは、この情報を全て削除していた。
  • 昔の Noto Sans はこの情報を含まなかった気がする

フォントが、ヒント(OpenType フォントの場合)、カーニング情報、ビットマップデータ、 OpenType 機能を持っている場合、それらは削除されます。

サブセットフォントメーカー

今は、 NotoSansCJKjp-hinted.zip を元にすれば、ヒント情報を含むサブセットが作れるため、 CSS の font-feature-settings が指定できる。

全て削れば従来通りだが、せっかくなので指定を検証することにした。

font-feature-settings

まず、以下を調査する。

  • Noto Sans CJK jp が含むヒント情報
  • CSS で指定可能なプロパティ

ところが、前者についてはリポジトリを見てもそれらしい情報にたどり着くことができなかった。

後者は、 font-feature-settings の CSS の仕様から、 MS にある Registered Features という一覧がリンクされていた。

140 近い機能があるようだが、このうちのどれが使えるのかがわからなかったため、以下の DEMO ページを用意し Chrome で試した。

恐らく検証するための妥当な文字や、ブラウザの実装などといった変数もあるだろうが、その辺まで網羅するのはコストが高い。

そこで、適当なサンプル文章をベースに、プロパティを切り替えながら、明らかに見た目が変わる指定を把握するところまで行った。

  • aalt: Access
  • dlig: Discretionary Ligatures
  • fwid: Full Widths
  • halt: Alternate Half Widths
  • hwid: Half Widths
  • palt: Proportional Alternate Widths
  • pwid: Proportional Widths
  • vert: Vertical Writing
  • vrt2: Vertical Alternates and Rotation

この中で、本サイトでの対応を検討すべきは halt, palt だろうと判断した。

字詰(palt)

halt, palt はいずれも字詰に関するプロパティだ。

以下のような違いがある。

  • halt: 約物類(句読点など)を半角幅にする
  • palt: 字体を置き換えずプロポーショナル幅にする

DEMO でみた halt は割と良さそうに見えたが、ブログ全体に適用したところあまり良くなかったため不採用とした。

palt とは別に、字体を置き換える pwid があるが、そちらは Chrome か Noto Sans CJK JP が対応してないようだ。

そこで結果として palt のみを指定してフォントをビルドすることにした。

$ pyftsubset NotoSansCJKjp-Regular.otf --text-file=../All.txt --layout-features='palt' --flavor=woff2 --output-file=NotoSansCJKjp-Regular-Jxck-20191011.woff2

結果は以下である。

  • 353.1K: 従来
  • 606.6K: layout-feature='*'
  • 293.9K: layout-feature='palt'

サブセット生成のロジックを変えたため、不要な文字も減り、トータルでは layout-features を入れても、改善前より小さくなっている。

またこのヒントを有効にするため、 CSS に以下を追加した。

body {
  font-feature-settings: "palt"
}

before/after は以下のようになる。

font-feature-settings で palt を切り替えた時の字詰めの変化

Outro

以下のことを行なった。

  • 不要文字をコードブロックに移すように記事を更新
  • subset 対象の文字を記事から取得
  • pyftsubset でサブセット生成を自動化
  • layout-feature を検証し palt を採用
  • css に font-feature-settings を追加

正直フォントについては素人であり、色々と雰囲気でやっているところもあるが、新しい機能を採用するという点ではよい改修ができた。

今後も、おもしろい font-feature-settings があれば採用し、 Noto Sans が対応していなければ、対応しているフォントへの変更も視野に入れて、検証していきたい。

その他 WebFont に関連する検証は web font タグにまとまっている。