From ccc0f81d33e2388b465a5e22466b124aacb762f8 Mon Sep 17 00:00:00 2001 From: Tatsunori Uchino Date: Sun, 13 Sep 2026 22:05:07 +0900 Subject: [PATCH 1/2] fix: update font-family settings for improved language support - Prefers Noto Sans CJK to good old Microsoft fonts - Respects Traditional Chinese locales - Reflects internal lang change - Adjusts Yu Gothic weights for non-Japanese Windows --- scripts/subsetFonts.py | 105 ++++++++++++++++++---- src/client/theme-default/styles/base.css | 8 +- src/client/theme-default/styles/fonts.css | 82 ++++++++++++++--- 3 files changed, 164 insertions(+), 31 deletions(-) diff --git a/scripts/subsetFonts.py b/scripts/subsetFonts.py index dbcf3d89c..e9e363e35 100755 --- a/scripts/subsetFonts.py +++ b/scripts/subsetFonts.py @@ -45,11 +45,47 @@ PUA = range(0xE000, 0xF8FF + 1) BASE_VAR = """\ :root { --vp-font-family-base: - 'Inter', -apple-system, BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Inter', BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; } """ +LOCAL_BASE_VAR = """\ +:root, [lang]:where(:not(:lang(zh, ja, ko))) { + --vp-font-family-base: + 'Inter', BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; +} +""" + +# From https://github.com/tats-u/yu-othic-css/ v1.0.0 +# (officially donated by its author) +YU_GOTHIC_WEIGHT_FIXED = """\ +@font-face { + font-family: 'Yu Gothic Weight Fixed'; + font-weight: 200; + src: local('Yu Gothic Light'); +} + +@font-face { + font-family: 'Yu Gothic Weight Fixed'; + font-weight: 300; + src: local('Yu Gothic Regular'); +} + +@font-face { + font-family: 'Yu Gothic Weight Fixed'; + font-weight: 400; + src: local('Yu Gothic Medium'); +} + +@font-face { + font-family: 'Yu Gothic Weight Fixed'; + font-weight: 600; + src: local('Yu Gothic Bold'); +} +""" + # The 'Inter Core' faces leave the `cjkExclusions` characters uncovered so that # they fall through to the next family in the stack, which therefore must be # an explicit CJK font: a Latin system font (or `sans-serif`) would claim most @@ -62,13 +98,11 @@ BASE_VAR = """\ # cascade list and walks that list with each font's full character map, which # on macOS 26 / iOS 26 hands the symbols missing from the reduced PingFang # (U+FF5C, ①, ★, ※, ...) to Apple Symbols or the Japanese UI font at a -# single weight. The CJK_FALLBACK_ANCHOR faces route them through the -# language-aware system fallback instead. Bare zh means Hans per BCP 47 -# likely subtags, and with no Traditional Chinese rule it also covers -# zh-Hant/zh-TW/zh-HK/zh-MO pages. If Hant handling is ever requested, add -# after the zh rule (same specificity, so the later rule wins; the region -# tags must be enumerated because `:lang(zh-Hant)` cannot match e.g. -# `lang="zh-TW"`): +# single weight. Bare zh means Hans per BCP 47 likely subtags, and with no +# Traditional Chinese rule it also covers zh-Hant/zh-TW/zh-HK/zh-MO pages. +# If Hant handling is ever requested, add after the zh rule (same specificity, +# so the later rule wins; the region tags must be enumerated because +# `:lang(zh-Hant)` cannot match e.g. `lang="zh-TW"`): # [lang]:where(:lang(zh-Hant), :lang(zh-TW), :lang(zh-HK), :lang(zh-MO)) { # --vp-font-family-base: # 'Inter Core', 'PingFang TC', 'Microsoft JhengHei', 'Noto Sans CJK TC', @@ -78,23 +112,57 @@ BASE_VAR = """\ CJK_BASE_VAR = """\ [lang]:where(:lang(zh)) { --vp-font-family-base: - 'Inter Core', 'PingFang SC', 'Microsoft YaHei', 'Noto Sans CJK SC', - BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol', 'Noto Color Emoji'; + 'Inter Core', 'PingFang SC', 'Noto Sans CJK SC', 'Noto Sans SC', 'Microsoft YaHei', + BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; +} + +/* Traditional Chinese */ +/* https://github.com/unicode-org/cldr-json/blob/main/cldr-json/cldr-core/supplemental/likelySubtags.json */ +/* Tentative: for regions that belong to neither PRC nor ROC, leave Chinese fonts to the user. */ +/* :lang(zh-[REGION]) matches zh-Hans-[REGION], which is unwanted, so we prefer [lang|=zh-[REGION]] instead. */ +[lang]:where(:lang(zh-Hant)), [lang|=zh-AU i], [lang|=zh-BN i], [lang|=zh-GB i], [lang|=zh-GF i], [lang|=zh-ID i], [lang|=zh-PA i], [lang|=zh-PF i], [lang|=zh-PH i], [lang|=zh-SR i], [lang|=zh-TH i], [lang|=zh-US i], [lang|=zh-VN i] { + --vp-font-family-base: + 'Inter Core', BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; +} + +/* We can't cover cases that don't contain region subtag but contain extension subtags, such as -t-en due to CSS's limitation as of 2026-09 */ +[lang=zh-Hant i], [lang|=zh-TW i], :lang(zh-Hant-TW, zh-Bopo, zh-Hanb) { + --vp-font-family-base: + 'Inter Core', 'PingFang TC', 'Noto Sans CJK TC', 'Noto Sans TC', 'Microsoft JhengHei', + BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; +} + +[lang]:where(:lang(zh-Hant-HK)), [lang|=zh-HK i] { + /* Microsoft JhengHei is optimized for Taiwan, so we should not prioritize it for PRC regions */ + --vp-font-family-base: + 'Inter Core', 'PingFang HK', 'Noto Sans CJK HK', 'Noto Sans HK', + BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; +} + +[lang]:where(:lang(zh-Hant-MO)), [lang|=zh-MO i] { + /* A Macao variant for Noto Sans CJK / Source Han Sans has not been released yet as of 2026-09. */ + --vp-font-family-base: + 'Inter Core', 'PingFang MO', 'PingFang HK', 'Noto Sans CJK HK', 'Noto Sans HK', + BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; } [lang]:where(:lang(ja)) { --vp-font-family-base: - 'Inter Core', 'Hiragino Sans', 'Meiryo', 'Yu Gothic', 'Noto Sans CJK JP', - BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol', 'Noto Color Emoji'; + 'Inter Core', 'Hiragino Sans', 'Noto Sans CJK JP', 'Noto Sans JP', 'Yu Gothic Weight Fixed', 'Meiryo', + BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; } [lang]:where(:lang(ko)) { --vp-font-family-base: - 'Inter Core', 'Apple SD Gothic Neo', 'Malgun Gothic', 'Noto Sans CJK KR', - BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol', 'Noto Color Emoji'; + 'Inter Core', 'Apple SD Gothic Neo', 'Noto Sans CJK KR', 'Noto Sans KR', 'Malgun Gothic', + BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; } """ @@ -290,8 +358,9 @@ def write_css(subsets: dict[str, str], cjk_exclusions: set[int]) -> None: + "\n".join(inter) + "\n" + "\n".join(cjk) + + f"\n{YU_GOTHIC_WEIGHT_FIXED}" + f"\n{CJK_FALLBACK_ANCHOR}" - + f"\n{BASE_VAR}\n{CJK_BASE_VAR}" + + f"\n{LOCAL_BASE_VAR}\n{CJK_BASE_VAR}" ) diff --git a/src/client/theme-default/styles/base.css b/src/client/theme-default/styles/base.css index 89fa8039b..3a33e257d 100644 --- a/src/client/theme-default/styles/base.css +++ b/src/client/theme-default/styles/base.css @@ -20,12 +20,18 @@ line-height: 1.5; -webkit-text-size-adjust: 100%; tab-size: 4; - font-family: var(--vp-font-family-base); font-feature-settings: normal; font-variation-settings: normal; -webkit-tap-highlight-color: transparent; } + /* [lang] is additionally specified to reflect changes to --vp-font-family-base */ + html, + :host, + [lang] { + font-family: var(--vp-font-family-base); + } + hr { height: 0; color: inherit; diff --git a/src/client/theme-default/styles/fonts.css b/src/client/theme-default/styles/fonts.css index 9e75a2bf0..0f959bfe5 100644 --- a/src/client/theme-default/styles/fonts.css +++ b/src/client/theme-default/styles/fonts.css @@ -3,7 +3,7 @@ :root { --vp-font-family-base: - 'Inter', -apple-system, BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Inter', BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; } /* webfont-marker-end */ @@ -298,6 +298,30 @@ unicode-range: U+0302, U+0306-0307, U+030A, U+030C, U+030F, U+0313, U+0315, U+031B, U+0326-0328, U+032C, U+0337-0338, U+0342-0343, U+0346-036F, U+0E3F, U+1DC0-1DF5, U+1DFC-1DFF, U+2070-2071, U+2075-207E, U+2080, U+2085-208E, U+2090-209C, U+20DB-20DE, U+20E8, U+20F0, U+2100-2101, U+2106, U+2117, U+211E-2120, U+212A, U+212E, U+2132, U+213B, U+214D, U+2150-2152, U+2155-215A, U+215F, U+216C-216F, U+217A-217F, U+2183-2186, U+21AA, U+21B0-21B1, U+21B3-21B5, U+21BA-21BB, U+21D0, U+21DE-21DF, U+21E4-21E5, U+21EA, U+2205-2206, U+2296-2298, U+2303-2305, U+2325-2327, U+232B, U+2380, U+2387, U+238B, U+23CE-23CF, U+2423, U+24EA, U+25A2, U+25AA, U+25BA-25BB, U+25C4-25C5, U+25CA, U+25E6, U+2600, U+263C, U+266B, U+26A0, U+2713, U+2717, U+2756, U+2764, U+2780-2788, U+27EF, U+27F5-27FA, U+2913, U+2A38, U+2B06, U+2B12-2B13, U+2B24, U+2E18, U+A92E, U+1F12F, U+1F16A-1F16B, U+1F850, U+1F852; } +@font-face { + font-family: 'Yu Gothic Weight Fixed'; + font-weight: 200; + src: local('Yu Gothic Light'); +} + +@font-face { + font-family: 'Yu Gothic Weight Fixed'; + font-weight: 300; + src: local('Yu Gothic Regular'); +} + +@font-face { + font-family: 'Yu Gothic Weight Fixed'; + font-weight: 400; + src: local('Yu Gothic Medium'); +} + +@font-face { + font-family: 'Yu Gothic Weight Fixed'; + font-weight: 600; + src: local('Yu Gothic Bold'); +} + @font-face { font-family: 'Inter Core'; font-style: normal; @@ -314,29 +338,63 @@ unicode-range: U+10FFFF; } -:root { +:root, [lang]:where(:not(:lang(zh, ja, ko))) { --vp-font-family-base: - 'Inter', -apple-system, BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Inter', BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; } [lang]:where(:lang(zh)) { --vp-font-family-base: - 'Inter Core', 'PingFang SC', 'Microsoft YaHei', 'Noto Sans CJK SC', - BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol', 'Noto Color Emoji'; + 'Inter Core', 'PingFang SC', 'Noto Sans CJK SC', 'Noto Sans SC', 'Microsoft YaHei', + BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; +} + +/* Traditional Chinese */ +/* https://github.com/unicode-org/cldr-json/blob/main/cldr-json/cldr-core/supplemental/likelySubtags.json */ +/* Tentative: for regions that belong to neither PRC nor ROC, leave Chinese fonts to the user. */ +/* :lang(zh-[REGION]) matches zh-Hans-[REGION], which is unwanted, so we prefer [lang|=zh-[REGION]] instead. */ +[lang]:where(:lang(zh-Hant)), [lang|=zh-AU i], [lang|=zh-BN i], [lang|=zh-GB i], [lang|=zh-GF i], [lang|=zh-ID i], [lang|=zh-PA i], [lang|=zh-PF i], [lang|=zh-PH i], [lang|=zh-SR i], [lang|=zh-TH i], [lang|=zh-US i], [lang|=zh-VN i] { + --vp-font-family-base: + 'Inter Core', BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; +} + +/* We can't cover cases that don't contain region subtag but contain extension subtags, such as -t-en due to CSS's limitation as of 2026-09 */ +[lang=zh-Hant i], [lang|=zh-TW i], :lang(zh-Hant-TW, zh-Bopo, zh-Hanb) { + --vp-font-family-base: + 'Inter Core', 'PingFang TC', 'Noto Sans CJK TC', 'Noto Sans TC', 'Microsoft JhengHei', + BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; +} + +[lang]:where(:lang(zh-Hant-HK)), [lang|=zh-HK i] { + /* Microsoft JhengHei is optimized for Taiwan, so we should not prioritize it for PRC regions */ + --vp-font-family-base: + 'Inter Core', 'PingFang HK', 'Noto Sans CJK HK', 'Noto Sans HK', + BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; +} + +[lang]:where(:lang(zh-Hant-MO)), [lang|=zh-MO i] { + /* A Macao variant for Noto Sans CJK / Source Han Sans has not been released yet as of 2026-09. */ + --vp-font-family-base: + 'Inter Core', 'PingFang MO', 'PingFang HK', 'Noto Sans CJK HK', 'Noto Sans HK', + BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; } [lang]:where(:lang(ja)) { --vp-font-family-base: - 'Inter Core', 'Hiragino Sans', 'Meiryo', 'Yu Gothic', 'Noto Sans CJK JP', - BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol', 'Noto Color Emoji'; + 'Inter Core', 'Hiragino Sans', 'Noto Sans CJK JP', 'Noto Sans JP', 'Yu Gothic Weight Fixed', 'Meiryo', + BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; } [lang]:where(:lang(ko)) { --vp-font-family-base: - 'Inter Core', 'Apple SD Gothic Neo', 'Malgun Gothic', 'Noto Sans CJK KR', - BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol', 'Noto Color Emoji'; + 'Inter Core', 'Apple SD Gothic Neo', 'Noto Sans CJK KR', 'Noto Sans KR', 'Malgun Gothic', + BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; } From d0695cf21354c3ae6d918642e3495f664585b78b Mon Sep 17 00:00:00 2001 From: Tatsunori Uchino Date: Sun, 20 Sep 2026 11:49:25 +0900 Subject: [PATCH 2/2] restore -apple-system for non-CJK locales --- scripts/subsetFonts.py | 2 +- src/client/theme-default/styles/fonts.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/subsetFonts.py b/scripts/subsetFonts.py index e9e363e35..d5149e8dd 100755 --- a/scripts/subsetFonts.py +++ b/scripts/subsetFonts.py @@ -45,7 +45,7 @@ PUA = range(0xE000, 0xF8FF + 1) BASE_VAR = """\ :root { --vp-font-family-base: - 'Inter', BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Inter', -apple-system, BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; } """ diff --git a/src/client/theme-default/styles/fonts.css b/src/client/theme-default/styles/fonts.css index 0f959bfe5..d2d7611cf 100644 --- a/src/client/theme-default/styles/fonts.css +++ b/src/client/theme-default/styles/fonts.css @@ -3,7 +3,7 @@ :root { --vp-font-family-base: - 'Inter', BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', + 'Inter', -apple-system, BlinkMacSystemFont, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; } /* webfont-marker-end */