Font configuration/Examples

From ArchWiki

See Font configuration for the main article.

Configurations can vary to a degree. Please post Fontconfig configurations with an explanation for why they were done.

Hinted fonts

~/.config/fontconfig/fonts.conf
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
  <match target="font">
    <edit mode="assign" name="antialias">
      <bool>true</bool>
    </edit>
    <edit mode="assign" name="embeddedbitmap">
      <bool>false</bool>
    </edit>
    <edit mode="assign" name="hinting">
      <bool>true</bool>
    </edit>
    <edit mode="assign" name="hintstyle">
      <const>hintslight</const>
    </edit>
    <edit mode="assign" name="lcdfilter">
      <const>lcddefault</const>
    </edit>
    <edit mode="assign" name="rgba">
      <const>rgb</const>
    </edit>
  </match>
</fontconfig>

No hinting for italic or bold

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
  <match target="font">
    <edit mode="assign" name="autohint">
      <bool>true</bool>
    </edit>
    <edit mode="assign" name="hinting">
      <bool>false</bool>
    </edit>
    <edit mode="assign" name="lcdfilter">
      <const>lcddefault</const>
    </edit>
    <edit mode="assign" name="hintstyle">
      <const>hintslight</const>
    </edit>
    <edit mode="assign" name="antialias">
      <bool>true</bool>
    </edit>
    <edit mode="assign" name="rgba">
      <const>rgb</const>
    </edit>
  </match>
  <match target="font">
    <test name="pixelsize" qual="any" compare="more">
      <double>15</double>
    </test>
    <edit mode="assign" name="lcdfilter">
      <const>lcdlight</const>
    </edit>
    <edit mode="assign" name="hintstyle">
      <const>hintnone</const>
    </edit>
  </match>
  <match target="font">
    <test name="weight" compare="more">
      <const>medium</const>
    </test>
    <edit mode="assign" name="hintstyle">
      <const>hintnone</const>
    </edit>
    <edit mode="assign" name="lcdfilter">
      <const>lcdlight</const>
    </edit>
  </match>
  <match target="font">
    <test name="slant" compare="not_eq">
      <double>0</double>
    </test>
    <edit mode="assign" name="hintstyle">
      <const>hintnone</const>
    </edit>
    <edit mode="assign" name="lcdfilter">
      <const>lcdlight</const>
    </edit>
  </match>
</fontconfig>

Enable anti-aliasing only for bigger fonts or certain fonts

Some users prefer the sharper rendering that anti-aliasing does not offer:

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
  <match target="font">
    <edit name="antialias" mode="assign">
      <bool>false</bool>
    </edit>
  </match>
  <match target="font">
    <test name="size" qual="any" compare="more">
      <double>12</double>
    </test>
    <edit name="antialias" mode="assign">
      <bool>true</bool>
    </edit>
  </match>
  <match target="font">
    <test name="pixelsize" qual="any" compare="more">
      <double>16</double>
    </test>
    <edit name="antialias" mode="assign">
      <bool>true</bool>
    </edit>
  </match>
</fontconfig>

You might also want to disable anti-aliasing only for fonts that look well without anti-aliasing. See Font configuration/Examples/No anti-aliasing.

Disable bold font

For when a font does not present itself well in bold and you cannot disable bold fonts in the application (st for example).

...
<match target="pattern">
  <test qual="any" name="family">
    <string>Envy Code R</string>
  </test>
  <test name="weight" compare="more">
    <const>medium</const>
  </test>
  <edit name="weight" mode="assign" binding="same">
    <const>medium</const>
  </edit>
</match>

...

Disable ligatures for monospaced fonts

This prevents letter combinations like "ffi" from being squashed into a single-width character in some monospaced fonts. The whole <match> block needs to be duplicated to include extra fonts.

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
  <description>Disable ligatures for monospaced fonts to avoid ff, fi, ffi, etc. becoming only one character wide</description>
  <match target="font">
    <test name="family" compare="eq" ignore-blanks="true">
      <string>Nimbus Mono PS</string>
    </test>
    <edit name="fontfeatures" mode="append">
      <string>liga off</string>
      <string>dlig off</string>
    </edit>
  </match>
</fontconfig>

Some other fonts may also require disabling features such as calt and/or clig.

You can test the effectiveness of this with the following command:

$ echo -e "| worksheet |\n| buffering |\n| difficult |\n| finishing |\n| different |\n| efficient |" | pango-view --font="Nimbus Mono PS" /dev/stdin

Some programs do not support the fontfeatures tag, so for those replacing the font with another is the only option. See Font configuration#Set default or fallback fonts for details.

Enable typographic features

Some fonts like inter-font support many useful typographic features that are not enabled by default.

Those features can be managed system-wide (for all users) or per user using fontconfig, and/or per application, using applications internal setting. (For those programs which support configuring them internally, like LibreOffice.)

Below is an example of enabling dlig, tnum, ccmp, ss01 and ss02 features for the Inter font. You can substitute them with any other feature of any other font supporting them. A complete list of all possible typographic features can be found at Wikipedia:List of typographic features, but check if your font of choice supports a feature, before trying to enable it.

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:font.dtd">
<fontconfig>
        <description>Enable some typographic features of Inter font, for all applications.</description>
        <match target="font">
                <test name="family" compare="eq" ignore-blanks="true">
                        <string>Inter</string>
                </test>
                <edit name="fontfeatures" mode="append">
                        <string>dlig on</string>
                        <string>tnum on</string>
                        <string>ccmp on</string>
                        <string>ss01 on</string>
                        <string>ss02 on</string>
                </edit>
        </match>
</fontconfig>

Verification of those features being enabled can be done both visually or using fc-match -v fontfamilyname command.

Default fonts

For font consistency, all applications should be set to use the serif, sans-serif, and monospace aliases, which are mapped to particular fonts by fontconfig. See Metric-compatible fonts for options and examples.

The standard names

The standard names are the aliases serif, sans-serif, and monospace. Setting custom values for these aliases will change the defaults for almost all applications, including sway, alacritty, and firefox. This example prefers gnu-free-fonts for everything except fixed-width fonts, for which Source Code Pro is preferred.

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
  <alias>
    <family>serif</family>
    <prefer><family>FreeSerif</family></prefer>
  </alias>
  <alias>
    <family>sans-serif</family>
    <prefer><family>FreeSans</family></prefer>
  </alias>
  <alias>
    <family>monospace</family>
    <prefer><family>Source Code Pro</family></prefer>
  </alias>
</fontconfig>

Arabic

Example fonts.conf which specifies a default font for the Arabic language and keeps western style fonts for Latin letters. You will require either ttf-arabeyes-fontsAUR or noto-fonts for the below to work. You can also choose to install any other Arabic fonts and accordingly change the font name below based on your preference

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
  <!-- Default font for the Arabic language (no fc-match pattern) -->
  <match>
    <test compare="contains" name="lang">
      <string>ar</string>
    </test>
    <edit mode="prepend" name="family">
      <string>Tholoth</string>
    </edit>
  </match>
</fontconfig>

The above should work for most applications but some applications like Chromium do not work with the language match test. If you find some applications not using your selected fonts, you can use the below alias and prefer tags which seems to work.

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
  <!-- Fallback fonts preference order -->
  <alias>
    <family>sans-serif</family>
    <prefer>
      <family>Noto Sans</family>
      <family>Open Sans</family>
      <family>Droid Sans</family>
      <family>Roboto</family>
      <family>Tholoth</family>
      <family>Noto Sans Arabic</family>
    </prefer>
  </alias>
  <alias>
    <family>serif</family>
    <prefer>
      <family>Noto Serif</family>
      <family>Droid Serif</family>
      <family>Roboto Slab</family>
      <family>Tholoth</family>
      <family>Noto Sans Arabic</family>
    </prefer>
  </alias>
  <alias>
    <family>monospace</family>
    <prefer>
      <family>Noto Sans Mono</family>
      <family>Inconsolata</family>
      <family>Droid Sans Mono</family>
      <family>Roboto Mono</family>
    </prefer>
  </alias>
</fontconfig>

Excluding Arabic script from other languages

Fonts using Arabic script but are of other languages can be excluded. For example, the Nastaliq Urdu fonts could be chosen by default for Arabic. Use the following configuration to blacklist them, ensuring the system uses a proper Arabic font.

/etc/fonts/conf.d/66-noto-reject-nastaliq.conf
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
  <selectfont>
    <rejectfont>
      <glob>/usr/share/fonts/noto/NotoNastaliq*</glob>
    </rejectfont>
  </selectfont>
</fontconfig>

Japanese

Example fonts.conf which also specifies a default font for the Japanese locale (ja_JP) and keeps western style fonts for Latin letters.

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
  <!-- Default font (no fc-match pattern) -->
  <match>
    <edit mode="prepend" name="family">
      <string>Noto Sans</string>
    </edit>
  </match>
  <!-- Default font for the ja_JP locale (no fc-match pattern) -->
  <match>
    <test compare="contains" name="lang">
      <string>ja</string>
    </test>
    <edit mode="prepend" name="family">
      <string>Noto Sans CJK JP</string>
    </edit>
  </match>
  <!-- Default sans-serif font -->
  <match target="pattern">
    <test qual="any" name="family">
      <string>sans-serif</string>
    </test>
    <!--<test qual="any" name="lang"><string>ja</string></test>-->
    <edit name="family" mode="prepend" binding="same">
      <string>Noto Sans</string>
    </edit>
  </match>
  <!-- Default serif fonts -->
  <match target="pattern">
    <test qual="any" name="family">
      <string>serif</string>
    </test>
    <edit name="family" mode="prepend" binding="same">
      <string>Noto Serif</string>
    </edit>
    <edit name="family" mode="append" binding="same">
      <string>IPAPMincho</string>
    </edit>
    <edit name="family" mode="append" binding="same">
      <string>HanaMinA</string>
    </edit>
  </match>
  <!-- Default monospace fonts -->
  <match target="pattern">
    <test qual="any" name="family">
      <string>monospace</string>
    </test>
    <edit name="family" mode="prepend" binding="same">
      <string>Noto Sans Mono</string>
    </edit>
    <edit name="family" mode="append" binding="same">
      <string>Inconsolatazi4</string>
    </edit>
    <edit name="family" mode="append" binding="same">
      <string>IPAGothic</string>
    </edit>
  </match>
  <!-- Fallback fonts preference order -->
  <alias>
    <family>sans-serif</family>
    <prefer>
      <family>Noto Sans</family>
      <family>Open Sans</family>
      <family>Droid Sans</family>
      <family>Ubuntu</family>
      <family>Roboto</family>
      <family>NotoSansCJK</family>
      <family>Source Han Sans JP</family>
      <family>IPAPGothic</family>
      <family>VL PGothic</family>
      <family>Koruri</family>
    </prefer>
  </alias>
  <alias>
    <family>serif</family>
    <prefer>
      <family>Noto Serif</family>
      <family>Droid Serif</family>
      <family>Roboto Slab</family>
      <family>IPAPMincho</family>
    </prefer>
  </alias>
  <alias>
    <family>monospace</family>
    <prefer>
      <family>Noto Sans Mono</family>
      <family>Inconsolatazi4</family>
      <family>Ubuntu Mono</family>
      <family>Droid Sans Mono</family>
      <family>Roboto Mono</family>
      <family>IPAGothic</family>
    </prefer>
  </alias>
</fontconfig>

Chinese

~/.config/fontconfig/fonts.conf
or
/etc/fonts/local.conf
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
  <match target="font">
    <edit name="embeddedbitmap" mode="assign">
      <bool>false</bool>
    </edit>
  </match>
  <match>
    <test qual="any" name="family">
      <string>serif</string>
    </test>
    <edit name="family" mode="prepend" binding="strong">
      <string>Noto Serif</string>
    </edit>
  </match>
  <match target="pattern">
    <test qual="any" name="family">
      <string>sans-serif</string>
    </test>
    <edit name="family" mode="prepend" binding="strong">
      <string>Roboto</string>
    </edit>
  </match>
  <match target="pattern">
    <test qual="any" name="family">
      <string>monospace</string>
    </test>
    <edit name="family" mode="prepend" binding="strong">
      <string>DejaVu Sans Mono</string>
    </edit>
  </match>
  <match>
    <test name="lang" compare="contains">
      <string>zh</string>
    </test>
    <test name="family">
      <string>serif</string>
    </test>
    <edit name="family" mode="prepend">
      <string>Source Han Serif CN</string>
    </edit>
  </match>
  <match>
    <test name="lang" compare="contains">
      <string>zh</string>
    </test>
    <test name="family">
      <string>sans-serif</string>
    </test>
    <edit name="family" mode="prepend">
      <string>Source Han Sans CN</string>
    </edit>
  </match>
  <match>
    <test name="lang" compare="contains">
      <string>zh</string>
    </test>
    <test name="family">
      <string>monospace</string>
    </test>
    <edit name="family" mode="prepend">
      <string>Noto Sans Mono CJK SC</string>
    </edit>
  </match>
  <!--Windows & Linux Chinese fonts. -->
  <match target="pattern">
    <test qual="any" name="family">
      <string>WenQuanYi Zen Hei</string>
    </test>
    <edit name="family" mode="assign" binding="same">
      <string>Source Han Sans CN</string>
    </edit>
  </match>
  <match target="pattern">
    <test qual="any" name="family">
      <string>WenQuanYi Micro Hei</string>
    </test>
    <edit name="family" mode="assign" binding="same">
      <string>Source Han Sans CN</string>
    </edit>
  </match>
  <match target="pattern">
    <test qual="any" name="family">
      <string>WenQuanYi Micro Hei Light</string>
    </test>
    <edit name="family" mode="assign" binding="same">
      <string>Source Han Sans CN</string>
    </edit>
  </match>
  <match target="pattern">
    <test qual="any" name="family">
      <string>Microsoft YaHei</string>
    </test>
    <edit name="family" mode="assign" binding="same">
      <string>Source Han Sans CN</string>
    </edit>
  </match>
  <match target="pattern">
    <test qual="any" name="family">
      <string>SimHei</string>
    </test>
    <edit name="family" mode="assign" binding="same">
      <string>Source Han Sans CN</string>
    </edit>
  </match>
  <match target="pattern">
    <test qual="any" name="family">
      <string>SimSun</string>
    </test>
    <edit name="family" mode="assign" binding="same">
      <string>Source Han Serif CN</string>
    </edit>
  </match>
  <match target="pattern">
    <test qual="any" name="family">
      <string>SimSun-18030</string>
    </test>
    <edit name="family" mode="assign" binding="same">
      <string>Source Han Serif CN</string>
    </edit>
  </match>
</fontconfig>

Chinese in Noto Fonts

Apply Noto Fonts while replacing Microsoft Fonts with WenQuanYi Micro Hei

~/.config/fontconfig/fonts.conf
or
/etc/fonts/local.conf
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
  <match target="font">
    <edit name="embeddedbitmap" mode="assign">
      <bool>false</bool>
    </edit>
  </match>
  <match>
    <test qual="any" name="family">
      <string>serif</string>
    </test>
    <edit name="family" mode="prepend" binding="strong">
      <string>Noto Serif</string>
    </edit>
  </match>
  <match target="pattern">
    <test qual="any" name="family">
      <string>sans-serif</string>
    </test>
    <edit name="family" mode="prepend" binding="strong">
      <string>Noto Sans</string>
    </edit>
  </match>
  <match target="pattern">
    <test qual="any" name="family">
      <string>monospace</string>
    </test>
    <edit name="family" mode="prepend" binding="strong">
      <string>Noto Sans Mono</string>
    </edit>
  </match>
  <match>
    <test name="lang" compare="contains">
      <string>zh</string>
    </test>
    <test name="family">
      <string>serif</string>
    </test>
    <edit name="family" mode="prepend">
      <string>Noto Serif CJK SC</string>
    </edit>
  </match>
  <match>
    <test name="lang" compare="contains">
      <string>zh</string>
    </test>
    <test name="family">
      <string>sans-serif</string>
    </test>
    <edit name="family" mode="prepend">
      <string>Noto Sans CJK SC</string>
    </edit>
  </match>
  <match>
    <test name="lang" compare="contains">
      <string>zh</string>
    </test>
    <test name="family">
      <string>monospace</string>
    </test>
    <edit name="family" mode="prepend">
      <string>Noto Sans Mono CJK SC</string>
    </edit>
  </match>
  <!--WenQuanYi Zen Hei -> WenQuanYi Micro Hei -->
  <match target="pattern">
    <test qual="any" name="family">
      <string>WenQuanYi Zen Hei</string>
    </test>
    <edit name="family" mode="assign" binding="same">
      <string>WenQuanYi Micro Hei</string>
    </edit>
  </match>
  <match target="pattern">
    <test qual="any" name="family">
      <string>WenQuanYi Zen Hei Lite</string>
    </test>
    <edit name="family" mode="assign" binding="same">
      <string>WenQuanYi Micro Hei Lite</string>
    </edit>
  </match>
  <match target="pattern">
    <test qual="any" name="family">
      <string>WenQuanYi Zen Hei Mono</string>
    </test>
    <edit name="family" mode="assign" binding="same">
      <string>WenQuanYi Micro Hei Mono</string>
    </edit>
  </match>
  <!--Microsoft YaHei, SimHei, SimSun -> WenQuanYi Micro Hei -->
  <match target="pattern">
    <test qual="any" name="family">
      <string>Microsoft YaHei</string>
    </test>
    <edit name="family" mode="assign" binding="same">
      <string>WenQuanYi Micro Hei</string>
    </edit>
  </match>
  <match target="pattern">
    <test qual="any" name="family">
      <string>SimHei</string>
    </test>
    <edit name="family" mode="assign" binding="same">
      <string>WenQuanYi Micro Hei</string>
    </edit>
  </match>
  <match target="pattern">
    <test qual="any" name="family">
      <string>SimSun</string>
    </test>
    <edit name="family" mode="assign" binding="same">
      <string>WenQuanYi Micro Hei</string>
    </edit>
  </match>
  <match target="pattern">
    <test qual="any" name="family">
      <string>SimSun-18030</string>
    </test>
    <edit name="family" mode="assign" binding="same">
      <string>WenQuanYi Micro Hei</string>
    </edit>
  </match>
</fontconfig>

CJK, but other Latin fonts are preferred

Requires noto-fonts-cjk.

You can replace PT Serif/Roboto/Cascadia Code PL with your favorite serif/sans-serif/monospace fonts.

~/.config/fontconfig/fonts.conf
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig: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>

  <!-- 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>

Alternate stylistic sets for fonts

Certain fonts come with alternate stylistic sets for characters through an OpenType feature. Generally these stylistic sets are named ss0x and contain small changes to individual characters. This shows how to change the default dotted zero to a slashed zero for the monospace version of ttf-ibm-plex.

~/.config/fontconfig/fonts.conf
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
  <match target="font">
    <test name="fontformat" compare="not_eq">
      <string />
    </test>
    <test name="family">
      <string>IBM Plex Mono</string>
    </test>
    <edit name="fontfeatures" mode="assign_replace">
      <string>ss03</string>
    </edit>
  </match>
</fontconfig>

See What are "Stylistic Sets?" for more information on this.

See also