Fontconfig (10日目) - serif =========================== .. post:: Dec 10, 2022 :tags: fontconfig sans-serifとくればserifです。 といいましてもセリフ体/明朝体はUI用に使われることはないでしょうし本文用フォントとして自ら設定しないと見ることすら稀ではないでしょうか。 Fontconfigに対してserifという名前でデフォルトフォントを問い合わせるアプリケーションは非常に少ないと思います。 セリフ体/明朝体を使うWebサイトは無いことはないです。 (Safariのデフォルトがsans-serifではなくserifなのは有名な話です。 またAlabasterテーマのフォントはGeorgiaですのでSphinx製ドキュメントでよく見ます。 :doc:`このブログではinitialに戻してます `\ 。) しかしその場合はブラウザの中で設定したserif用フォントが使われるはずです。 というわけでFontconfigでserifを設定する意味はフォールバックフォントのほうにあります。 .. compound:: 昨日も見ましたようにこうしてserif系フォントを指定した際に :: $ fc-match -s 'Noto Serif' | head NotoSerif-Regular.ttf: "Noto Serif" "Regular" NotoSansCJK-Regular.ttc: "Noto Sans CJK JP" "Regular" Ubuntu-R.ttf: "Ubuntu" "Regular" Ubuntu-Th.ttf: "Ubuntu" "Thin" NotoSansArabic-Regular.ttf: "Noto Sans Arabic" "Regular" NotoSansThai-Regular.ttf: "Noto Sans Thai" "Regular" NotoSansDevanagari-Regular.ttf: "Noto Sans Devanagari" "Regular" NotoSansTamil-Regular.ttf: "Noto Sans Tamil" "Regular" NotoSansHebrew-Regular.ttf: "Noto Sans Hebrew" "Regular" NotoSansBengali-Regular.ttf: "Noto Sans Bengali" "Regular" 2番目以降がsans-serifになってしまっているのを直そう、というわけです。 このままですとNoto Serifを表示しているはずなのにNoto Sans CJK JPをはじめとするsans-serifフォントの文字が混じってしまいます。 パターンにserifを追加する ------------------------- まずは ``family`` 属性にserifを追加してみます。 .. code-block:: xml :caption: ~/.config/fontconfig/conf.d/40-serif.conf Noto Serif serif ``accept`` (append)によってリスト上のNoto Serifの直後にserifを挿入します。 `/etc/fonts/conf.d/49-sansserif.conf `_ のほうがユーザーの設定よりも先に実行されていますので ``family`` 属性は Noto Serif → Noto Serif, sans-serif → Noto Serif, serif, sans-serif となってserifが優先されるはずです。 確かめてみましょう。 :: $ fc-match -s 'Noto Serif' | head NotoSerif-Regular.ttf: "Noto Serif" "Regular" NotoSerifCJK-Regular.ttc: "Noto Serif CJK JP" "Regular" NotoSansCJK-Regular.ttc: "Noto Sans CJK JP" "Regular" NotoNaskhArabic-Regular.ttf: "Noto Naskh Arabic" "Regular" NotoSerifThai-Regular.ttf: "Noto Serif Thai" "Regular" NotoSerifArmenian-Regular.ttf: "Noto Serif Armenian" "Regular" NotoSerifGeorgian-Regular.ttf: "Noto Serif Georgian" "Regular" NotoSerifDevanagari-Regular.ttf: "Noto Serif Devanagari" "Regular" NotoSerifHebrew-Regular.ttf: "Noto Serif Hebrew" "Regular" NotoSerifGujarati-Regular.ttf: "Noto Serif Gujarati" "Regular" serifに反応して `/etc/fonts/conf.d/56-neon-noto.conf `_ がNotoファミリーのserif系フォントを沢山追加してくれました。 でもまだNoto Sans CJK JPが3番目に居座ってますね。 strongは強いです。 パターンからsans-serifを取り除く -------------------------------- そもそもserif系フォントなのにリスト上にsans-serifが入ってしまっているのが原因です。 *49-sansserif.conf* はリスト上にserifがある場合はsans-serifを追加しませんが、ユーザーの設定ファイルよりも早く実行されてしまうので事前に防ぐ手立てはありません。 後から取り除いてしまいましょう。 .. code-block:: xml :caption: ~/.config/fontconfig/conf.d/40-serif.conf (修正後1) Noto Serif serif sans-serif Noto Serif 実行結果。 :: $ fc-match -s 'Noto Serif' | head NotoSerif-Regular.ttf: "Noto Serif" "Regular" NotoSerifCJK-Regular.ttc: "Noto Serif CJK JP" "Regular" NotoNaskhArabic-Regular.ttf: "Noto Naskh Arabic" "Regular" NotoSerifThai-Regular.ttf: "Noto Serif Thai" "Regular" NotoSerifArmenian-Regular.ttf: "Noto Serif Armenian" "Regular" NotoSerifGeorgian-Regular.ttf: "Noto Serif Georgian" "Regular" NotoSerifDevanagari-Regular.ttf: "Noto Serif Devanagari" "Regular" NotoSerifHebrew-Regular.ttf: "Noto Serif Hebrew" "Regular" NotoSerifGujarati-Regular.ttf: "Noto Serif Gujarati" "Regular" NotoSerifKannada-Regular.ttf: "Noto Serif Kannada" "Regular" うまくいきました。 ついでに ``accept`` を ``default`` (append_last)に修正しています。 */etc/fonts/conf.d/* 以下のファイルを見ると総称ファミリー名をリストに追加するときは ``default`` が使われていますのでそれに倣いました。 ``accpet`` (append)ですと既に複数のファミリー名がリストにあった場合に割り込んでしまうからだと思います。 ``$ fc-pattern -c 'Noto Serif' | grep 'sans-serif'`` でもsans-serifが入っていないことを確認できます。 もう少し汎用的に書く ++++++++++++++++++++ Noto Serif以外にもserif系フォントは複数インストールされています。 他のフォントにも対応していきましょう。 DejaVu SerifやFreeSerifは既に */etc/fonts/conf.d/* 以下で対応されています。 IPA P明朝がまだ対応されていないようです。 :: $ fc-match -s 'IPA P明朝' | head ipamp.ttf: "IPA P明朝" "Regular" NotoSansCJK-Regular.ttc: "Noto Sans CJK JP" "Regular" Ubuntu-R.ttf: "Ubuntu" "Regular" Ubuntu-Th.ttf: "Ubuntu" "Thin" NotoSans-Regular.ttf: "Noto Sans" "Regular" NotoSansArabic-Regular.ttf: "Noto Sans Arabic" "Regular" NotoSansThai-Regular.ttf: "Noto Sans Thai" "Regular" NotoSansDevanagari-Regular.ttf: "Noto Sans Devanagari" "Regular" NotoSansTamil-Regular.ttf: "Noto Sans Tamil" "Regular" NotoSansHebrew-Regular.ttf: "Noto Sans Hebrew" "Regular" 対応といっても上のNoto Serif用の記述をコピー&ペーストしてIPA P明朝に書き換えるだけですが……もう少し短くできないでしょうか。 上半分のserifを追加している ```` はフォント毎に書く必要がありますが、下半分のsans-serifを削除している ```` はまとめることができます。 リストにsans-serifとserifの両方がある場合にsans-serifを削除する、というので良いわけです。 .. code-block:: xml :caption: ~/.config/fontconfig/conf.d/40-serif.conf (修正後2) Noto Serif serif IPA P明朝 serif sans-serif serif 実行結果。 :: $ fc-match -s 'IPA P明朝' | head ipamp.ttf: "IPA P明朝" "Regular" NotoSerifCJK-Regular.ttc: "Noto Serif CJK JP" "Regular" NotoSerif-Regular.ttf: "Noto Serif" "Regular" NotoNaskhArabic-Regular.ttf: "Noto Naskh Arabic" "Regular" NotoSerifThai-Regular.ttf: "Noto Serif Thai" "Regular" NotoSerifArmenian-Regular.ttf: "Noto Serif Armenian" "Regular" NotoSerifGeorgian-Regular.ttf: "Noto Serif Georgian" "Regular" NotoSerifDevanagari-Regular.ttf: "Noto Serif Devanagari" "Regular" NotoSerifHebrew-Regular.ttf: "Noto Serif Hebrew" "Regular" NotoSerifGujarati-Regular.ttf: "Noto Serif Gujarati" "Regular" 個別のフォールバック設定 ------------------------ IPA P明朝からNoto Serif CJK JPにフォールバックしているところを見てみましょう。 .. image:: 2022_12_10_1_IPAPMincho_NotoSerifCJKJP.png :alt: IPA P明朝, Noto Serif CJK JP Notoのほうが縦長で太字ですので目立ちますよね。 IPA系で収録文字数の多い `IPAmj明朝 `_ をフォールバック先にしましょう。 (Debian/Ubuntu系であればパッケージfonts-ipamj-minchoです。) .. code-block:: xml :caption: ~/.config/fontconfig/conf.d/60-fallback.conf IPA P明朝 IPAmj明朝 IPA P明朝に限りIPAmj明朝をフォールバック先として優先します。 :: $ fc-match -s 'IPA P明朝' | head ipamp.ttf: "IPA P明朝" "Regular" ipamjm.ttf: "IPAmj明朝" "Regular" NotoSerifCJK-Regular.ttc: "Noto Serif CJK JP" "Regular" NotoSerif-Regular.ttf: "Noto Serif" "Regular" NotoNaskhArabic-Regular.ttf: "Noto Naskh Arabic" "Regular" NotoSerifThai-Regular.ttf: "Noto Serif Thai" "Regular" NotoSerifArmenian-Regular.ttf: "Noto Serif Armenian" "Regular" NotoSerifGeorgian-Regular.ttf: "Noto Serif Georgian" "Regular" NotoSerifDevanagari-Regular.ttf: "Noto Serif Devanagari" "Regular" NotoSerifHebrew-Regular.ttf: "Noto Serif Hebrew" "Regular" KCharSelectを起動しなおして見てみましょう。 .. image:: 2022_12_10_1_IPAPMincho_IPAmjMincho_2.png :alt: IPA P明朝, IPAmj明朝(hintmedium) 文字の高さが同じぐらいになりました。 .. role:: serif 右上の例示字形にも注目。 「\ :serif:`丳`\ 」の上下が詰まってますよね。 行間の広いNotoと比べてIPAmj明朝とIPA P明朝の行間は同じぐらいです。 ただ、IPAmj明朝のほうが濃くて目立つのは変わらないですね。 これは `/etc/fonts/conf.d/65-fonts-ipafont-mincho.conf `_ がIPA P明朝のヒンティングをなしにしているのに対してIPAmj明朝は通常のヒンティングがなされているからです。 IPAmj明朝もhintnoneにしてみました。 .. image:: 2022_12_10_1_IPAPMincho_IPAmjMincho_0.png :alt: IPA P明朝, IPAmj明朝(hintnone) 違和感はなくなりました。 ブラウザのフォント探索順 ------------------------ もうフォールバックフォントを自由に設定できますよね! ということで余談です。 次のようなCSSに対してブラウザは文字を収録しているフォントをどう探すのでしょうか。 .. code-block:: css font-family: XXX yyy ZZZ serif; 環境にはXXXとZZZがインストールされていてyyyは存在していないとします。 Firefox +++++++ XXX → そのフォールバックフォント → ZZZ → そのフォールバックフォント → ブラウザ設定でserifに設定されたフォント → そのフォールバックフォント、のようです。 ですのでXXXに対してフォールバックフォントをFontconfigできちんと設定しておけば、一貫性のある表示が得られます。 Chromium ++++++++ XXX → ZZZ → ブラウザ設定でserifに設定されたフォント → そのフォールバックフォント、のようです。 ですのでXXXがNotoファミリー、游、IBM Plex、Zenのような縦長のフォント、ZZZがArial/Times系(Liberations/Arimo/Tinos他)、MS系(HG他)、IPA、BIZ UD、ヒラギノのような昔ながらのスタイルのフォントだった場合、不揃いな表示になりがちです。 新しくて綺麗とされるフォントを前に前に付け足していってクソCSSになってるサイトは結構あります……。 **↑は行幅しか見てないあまりにもざっくりとした分類です。 游は行間は広いですが文字自体はそんな縦長ではないですし、ヒラギノは行間は狭いですが文字自体は割と縦長です。** それとChromiumは `langを渡してこない `_ みたいな話もあります。 謝辞 ---- @eeveeさんの `my fonts.conf `_ を参考にさせていただきました。 本当に、本当にありがとうございます。 私が“fonts.conf”言語を理解できたのは@eeveeさんのおかげです。