Skip to content

Instantly share code, notes, and snippets.

@akiirui
Last active December 11, 2023 15:46
Show Gist options
  • Save akiirui/b3f36e8bdf9a9f5636a98113960bc7f4 to your computer and use it in GitHub Desktop.
Save akiirui/b3f36e8bdf9a9f5636a98113960bc7f4 to your computer and use it in GitHub Desktop.
Customize fontconfig. CJK, but other Latin fonts are preferred
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- Default serif font -->
<alias binding="strong">
<family>serif</family>
<prefer>
<family>PT Serif</family>
</prefer>
</alias>
<!-- Default sans-serif font -->
<alias binding="strong">
<family>sans-serif</family>
<prefer>
<family>Roboto</family>
</prefer>
</alias>
<!-- Default monospace font -->
<alias binding="strong">
<family>monospace</family>
<prefer>
<family>Cascadia Code PL</family>
</prefer>
</alias>
<!-- Default system-ui font -->
<alias binding="strong">
<family>system-ui</family>
<prefer>
<family>Roboto</family>
</prefer>
</alias>
<!-- Replace some fonts by sans-serif -->
<match target="pattern">
<test qual="any" name="family">
<string>Arial</string>
</test>
<edit name="family" mode="assign" binding="strong">
<string>Roboto</string>
</edit>
</match>
<match target="pattern">
<test qual="any" name="family">
<string>Cantarell</string>
</test>
<edit name="family" mode="assign" binding="strong">
<string>Roboto</string>
</edit>
</match>
</fontconfig>
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- Serif CJK -->
<!-- Default serif when the "lang" attribute is not given -->
<!-- You can change this font to the language variant you want -->
<match target="pattern">
<test name="family">
<string>serif</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Serif CJK SC</string>
</edit>
</match>
<!-- Japanese -->
<!-- "lang=ja" or "lang=ja-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>ja</string>
</test>
<test name="family">
<string>serif</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Serif CJK JP</string>
</edit>
</match>
<!-- Korean -->
<!-- "lang=ko" or "lang=ko-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>ko</string>
</test>
<test name="family">
<string>serif</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Serif CJK KR</string>
</edit>
</match>
<!-- Chinese -->
<!-- "lang=zh" or "lang=zh-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh</string>
</test>
<test name="family">
<string>serif</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Serif CJK SC</string>
</edit>
</match>
<!-- "lang=zh-hans" or "lang=zh-hans-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-hans</string>
</test>
<test name="family">
<string>serif</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Serif CJK SC</string>
</edit>
</match>
<!-- "lang=zh-hant" or "lang=zh-hant-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-hant</string>
</test>
<test name="family">
<string>serif</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Serif CJK TC</string>
</edit>
</match>
<!-- Compatible -->
<!-- "lang=zh-cn" or "lang=zh-cn-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-cn</string>
</test>
<test name="family">
<string>serif</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Serif CJK SC</string>
</edit>
</match>
<!-- "lang=zh-tw" or "lang=zh-tw-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-tw</string>
</test>
<test name="family">
<string>serif</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Serif CJK TC</string>
</edit>
</match>
<!-- Sans CJK -->
<!-- Default sans-serif when the "lang" attribute is not given -->
<!-- You can change this font to the language variant you want -->
<match target="pattern">
<test name="family">
<string>sans-serif</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK SC</string>
</edit>
</match>
<!-- Japanese -->
<!-- "lang=ja" or "lang=ja-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>ja</string>
</test>
<test name="family">
<string>sans-serif</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK JP</string>
</edit>
</match>
<!-- Korean -->
<!-- "lang=ko" or "lang=ko-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>ko</string>
</test>
<test name="family">
<string>sans-serif</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK KR</string>
</edit>
</match>
<!-- Chinese -->
<!-- "lang=zh" or "lang=zh-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh</string>
</test>
<test name="family">
<string>sans-serif</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK SC</string>
</edit>
</match>
<!-- "lang=zh-hans" or "lang=zh-hans-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-hans</string>
</test>
<test name="family">
<string>sans-serif</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK SC</string>
</edit>
</match>
<!-- "lang=zh-hant" or "lang=zh-hant-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-hant</string>
</test>
<test name="family">
<string>sans-serif</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK TC</string>
</edit>
</match>
<!-- "lang=zh-hant-hk" or "lang=zh-hant-hk-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-hant-hk</string>
</test>
<test name="family">
<string>sans-serif</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK HK</string>
</edit>
</match>
<!-- Compatible -->
<!-- "lang=zh-cn" or "lang=zh-cn-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-cn</string>
</test>
<test name="family">
<string>sans-serif</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK SC</string>
</edit>
</match>
<!-- "lang=zh-tw" or "lang=zh-tw-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-tw</string>
</test>
<test name="family">
<string>sans-serif</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK TC</string>
</edit>
</match>
<!-- "lang=zh-hk" or "lang=zh-hk-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-hk</string>
</test>
<test name="family">
<string>sans-serif</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK HK</string>
</edit>
</match>
<!-- Mono CJK -->
<!-- Default monospace when the "lang" attribute is not given -->
<!-- You can change this font to the language variant you want -->
<match target="pattern">
<test name="family">
<string>monospace</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans Mono CJK SC</string>
</edit>
</match>
<!-- Japanese -->
<!-- "lang=ja" or "lang=ja-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>ja</string>
</test>
<test name="family">
<string>monospace</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans Mono CJK JP</string>
</edit>
</match>
<!-- Korean -->
<!-- "lang=ko" or "lang=ko-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>ko</string>
</test>
<test name="family">
<string>monospace</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans Mono CJK KR</string>
</edit>
</match>
<!-- Chinese -->
<!-- "lang=zh" or "lang=zh-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh</string>
</test>
<test name="family">
<string>monospace</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans Mono CJK SC</string>
</edit>
</match>
<!-- "lang=zh-hans" or "lang=zh-hans-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-hans</string>
</test>
<test name="family">
<string>monospace</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans Mono CJK SC</string>
</edit>
</match>
<!-- "lang=zh-hant" or "lang=zh-hant-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-hant</string>
</test>
<test name="family">
<string>monospace</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans Mono CJK TC</string>
</edit>
</match>
<!-- "lang=zh-hant-hk" or "lang=zh-hant-hk-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-hant-hk</string>
</test>
<test name="family">
<string>monospace</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans Mono CJK HK</string>
</edit>
</match>
<!-- Compatible -->
<!-- "lang=zh-cn" or "lang=zh-cn-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-cn</string>
</test>
<test name="family">
<string>monospace</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans Mono CJK SC</string>
</edit>
</match>
<!-- "lang=zh-tw" or "lang=zh-tw-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-tw</string>
</test>
<test name="family">
<string>monospace</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans Mono CJK TC</string>
</edit>
</match>
<!-- "lang=zh-hk" or "lang=zh-hk-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-hk</string>
</test>
<test name="family">
<string>monospace</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans Mono CJK HK</string>
</edit>
</match>
<!-- System UI CJK -->
<!-- Default system-ui when the "lang" attribute is not given -->
<!-- You can change this font to the language variant you want -->
<match target="pattern">
<test name="family">
<string>system-ui</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK SC</string>
</edit>
</match>
<!-- Japanese -->
<!-- "lang=ja" or "lang=ja-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>ja</string>
</test>
<test name="family">
<string>system-ui</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK JP</string>
</edit>
</match>
<!-- Korean -->
<!-- "lang=ko" or "lang=ko-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>ko</string>
</test>
<test name="family">
<string>system-ui</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK KR</string>
</edit>
</match>
<!-- Chinese -->
<!-- "lang=zh" or "lang=zh-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh</string>
</test>
<test name="family">
<string>system-ui</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK SC</string>
</edit>
</match>
<!-- "lang=zh-hans" or "lang=zh-hans-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-hans</string>
</test>
<test name="family">
<string>system-ui</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK SC</string>
</edit>
</match>
<!-- "lang=zh-hant" or "lang=zh-hant-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-hant</string>
</test>
<test name="family">
<string>system-ui</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK TC</string>
</edit>
</match>
<!-- "lang=zh-hant-hk" or "lang=zh-hant-hk-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-hant-hk</string>
</test>
<test name="family">
<string>system-ui</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK HK</string>
</edit>
</match>
<!-- Compatible -->
<!-- "lang=zh-cn" or "lang=zh-cn-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-cn</string>
</test>
<test name="family">
<string>system-ui</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK SC</string>
</edit>
</match>
<!-- "lang=zh-tw" or "lang=zh-tw-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-tw</string>
</test>
<test name="family">
<string>system-ui</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK TC</string>
</edit>
</match>
<!-- "lang=zh-hk" or "lang=zh-hk-*" -->
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-hk</string>
</test>
<test name="family">
<string>system-ui</string>
</test>
<edit name="family" mode="append" binding="strong">
<string>Noto Sans CJK HK</string>
</edit>
</match>
</fontconfig>
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- Append emoji font -->
<match target="pattern">
<test name="family">
<string>serif</string>
</test>
<edit name="family" mode="append_last" binding="strong">
<string>Noto Color Emoji</string>
</edit>
</match>
<match target="pattern">
<test name="family">
<string>sans-serif</string>
</test>
<edit name="family" mode="append_last" binding="strong">
<string>Noto Color Emoji</string>
</edit>
</match>
<match target="pattern">
<test name="family">
<string>monospace</string>
</test>
<edit name="family" mode="append_last" binding="strong">
<string>Noto Color Emoji</string>
</edit>
</match>
<match target="pattern">
<test name="family">
<string>system-ui</string>
</test>
<edit name="family" mode="append_last" binding="strong">
<string>Noto Color Emoji</string>
</edit>
</match>
</fontconfig>

Note

Requirement Fonts

Optional

Troubleshooting

Chromium

Chromium (and Google Chrome) only use first match font in the list, and always fallback this font missing characters to Chromium Standard fonts.

Google Chrome for Android also have this issues.

Example

Fonts settings in Chromium:

Standard font    : sans-serif
Serif font       : serif
Sans-serif font  : sans-serif
Fixed-width font : monospace

Query order:

  1. 你好 (serif)
  2. PT Serif (missing)
  3. Standard font (sans-serif)
  4. Roboto (missing)
  5. Search in fontconfig without style mark (like fc-match -a)
  6. 你好 (Noto Sans CJK JP)

Now, you lost serif style for these characters.

Not perfect solution

Extension Advanced Font Settings to set per languages fonts to show.

Firefox

Firefox working with fontconfig perfectly, but have a little issues need care.

Not follow fontconfig sometimes?

Firefox limit font query number in fontconfig. in about:config:

gfx.font_rendering.fontconfig.max_generic_substitutions = 3 (Default)

Increase this value, Firefox will query more fonts in fontconfig list.

Emoji not following system

Firefox ships with Twemoji Mozilla font, in about:config

font.name-list.emoji

Change Twemoji Mozilla to your wanna emoji fonts.

User Interface shown wrong fonts?

Firefox User Interface follow GTK 3.0 fonts settings.

View in dconf database:

gsettings get org.gnome.desktop.interface font-name

You can easily set these fonts by gnome-tweaks or gsettings.

But, be careful! When that font not have some character, Firefox will scan fonts in system by itself, and use first match font have these character.

Recommend to set Sans Regular or Serif Regular, let Firefox query follow this fontconfig.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment