Fix CJK fonts again and misc. font issues (#14575)
* Push system-ui further down the stack, fix #12966 * Fix Firefox showing U+300x in emoji font and more * Revert emoji font and fix long-standing Safari bug * Exclude Safari emoji fix above 1.25x zoom * Minor correctness/typo fix, affects only legacy platforms * Emoji consistency for monospace (e.g. EasyMDE) * Override paradigm; macOS/iOS-specific metric fix * Move whitespace fix to font-face * Handle metric calculation errors with Firefox * One last workaround for aliased fonts in Linux
This commit is contained in:
		
							parent
							
								
									c0c052bdbb
								
							
						
					
					
						commit
						0e5c6c4498
					
				
					 6 changed files with 187 additions and 40 deletions
				
			
		|  | @ -1,5 +1,5 @@ | ||||||
| <!DOCTYPE html> | <!DOCTYPE html> | ||||||
| <html lang="{{.Language}}" class="theme-{{.SignedUser.Theme}}"> | <html lang="{{.Lang}}" class="theme-{{.SignedUser.Theme}}"> | ||||||
| <head data-suburl="{{AppSubUrl}}"> | <head data-suburl="{{AppSubUrl}}"> | ||||||
| 	<meta charset="utf-8"> | 	<meta charset="utf-8"> | ||||||
| 	<meta name="viewport" content="width=device-width, initial-scale=1"> | 	<meta name="viewport" content="width=device-width, initial-scale=1"> | ||||||
|  |  | ||||||
|  | @ -26,7 +26,7 @@ import {initNotificationsTable, initNotificationCount} from './features/notifica | ||||||
| import {initStopwatch} from './features/stopwatch.js'; | import {initStopwatch} from './features/stopwatch.js'; | ||||||
| import {createCodeEditor, createMonaco} from './features/codeeditor.js'; | import {createCodeEditor, createMonaco} from './features/codeeditor.js'; | ||||||
| import {svg, svgs} from './svg.js'; | import {svg, svgs} from './svg.js'; | ||||||
| import {stripTags} from './utils.js'; | import {stripTags, mqBinarySearch} from './utils.js'; | ||||||
| 
 | 
 | ||||||
| const {AppSubUrl, StaticUrlPrefix, csrf} = window.config; | const {AppSubUrl, StaticUrlPrefix, csrf} = window.config; | ||||||
| 
 | 
 | ||||||
|  | @ -2519,6 +2519,19 @@ $(document).ready(async () => { | ||||||
|       .attr('title', ''); |       .attr('title', ''); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|  |   // Undo Safari emoji glitch fix at high enough zoom levels
 | ||||||
|  |   if (navigator.userAgent.match('Safari')) { | ||||||
|  |     $(window).resize(() => { | ||||||
|  |       const px = mqBinarySearch('width', 0, 4096, 1, 'px'); | ||||||
|  |       const em = mqBinarySearch('width', 0, 1024, 0.01, 'em'); | ||||||
|  |       if (em * 16 * 1.25 - px <= -1) { | ||||||
|  |         $('body').addClass('safari-above125'); | ||||||
|  |       } else { | ||||||
|  |         $('body').removeClass('safari-above125'); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   // Semantic UI modules.
 |   // Semantic UI modules.
 | ||||||
|   $('.dropdown:not(.custom)').dropdown({ |   $('.dropdown:not(.custom)').dropdown({ | ||||||
|     fullTextSearch: 'exact' |     fullTextSearch: 'exact' | ||||||
|  |  | ||||||
|  | @ -28,3 +28,16 @@ export function uniq(arr) { | ||||||
| export function stripTags(text) { | export function stripTags(text) { | ||||||
|   return text.replace(/<[^>]*>?/gm, ''); |   return text.replace(/<[^>]*>?/gm, ''); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // searches the inclusive range [minValue, maxValue].
 | ||||||
|  | // credits: https://matthiasott.com/notes/write-your-media-queries-in-pixels-not-ems
 | ||||||
|  | export function mqBinarySearch(feature, minValue, maxValue, step, unit) { | ||||||
|  |   if (maxValue - minValue < step) { | ||||||
|  |     return minValue; | ||||||
|  |   } | ||||||
|  |   const mid = Math.ceil((minValue + maxValue) / 2 / step) * step; | ||||||
|  |   if (matchMedia(`screen and (min-${feature}:${mid}${unit})`).matches) { | ||||||
|  |     return mqBinarySearch(feature, mid, maxValue, step, unit); // feature is >= mid
 | ||||||
|  |   } | ||||||
|  |   return mqBinarySearch(feature, minValue, mid - step, step, unit); // feature is < mid
 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -1,10 +1,9 @@ | ||||||
| :root { | :root { | ||||||
|   /* documented customizable variables */ |   /* documented customizable variables */ | ||||||
|   --fonts-proportional: system-ui, -apple-system, "BlinkMacSystemFont", "Segoe UI", "Roboto", "Helvetica Neue", "Arial", "Noto Sans", "Liberation Sans", sans-serif; |   --fonts-proportional: -apple-system, "Segoe UI", system-ui, "Roboto", "Helvetica Neue", "Arial"; | ||||||
|   --fonts-monospace: "SFMono-Regular", "Menlo", "Monaco", "Consolas", "Liberation Mono", "Courier New", monospace; |   --fonts-monospace: "SFMono-Regular", "Menlo", "Monaco", "Consolas", "Liberation Mono", "Courier New", monospace, var(--fonts-emoji); | ||||||
|   --fonts-emoji: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", "Twemoji Mozilla"; |   --fonts-emoji: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", "Twemoji Mozilla"; | ||||||
|   /* other variables */ |   /* other variables */ | ||||||
|   --fonts-regular: var(--fonts-proportional), var(--fonts-emoji); |  | ||||||
|   --border-radius: .28571429rem; |   --border-radius: .28571429rem; | ||||||
|   --opacity-disabled: .55; |   --opacity-disabled: .55; | ||||||
|   --color-primary: #4183c4; |   --color-primary: #4183c4; | ||||||
|  | @ -115,36 +114,8 @@ | ||||||
|   --checkbox-mask-indeterminate: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2 7.75A.75.75 0 012.75 7h10a.75.75 0 010 1.5h-10A.75.75 0 012 7.75z"></path></svg>'); |   --checkbox-mask-indeterminate: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2 7.75A.75.75 0 012.75 7h10a.75.75 0 010 1.5h-10A.75.75 0 012 7.75z"></path></svg>'); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| :root:lang(ja) { | :root * { | ||||||
|   --fonts-proportional: "Hiragino Kaku Gothic ProN", "Yu Gothic", "Source Han Sans JP", "Noto Sans CJK JP", "Droid Sans Japanese", "Meiryo", "MS PGothic"; |   --fonts-regular: var(--fonts-override, var(--fonts-proportional)), "Noto Sans", "Liberation Sans", var(--fonts-emoji), sans-serif; | ||||||
| } |  | ||||||
| 
 |  | ||||||
| :root:lang(zh-CN) { |  | ||||||
|   --fonts-proportional: "PingFang SC", "Hiragino Sans GB", "Source Han Sans CN", "Source Han Sans SC", "Noto Sans CJK SC", "Microsoft YaHei", "Heiti SC", "SimHei"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| :root:lang(zh-TW) { |  | ||||||
|   --fonts-proportional: "PingFang TC", "Hiragino Sans TC", "Source Han Sans TW", "Source Han Sans TC", "Noto Sans CJK TC", "Microsoft JhengHei", "Heiti TC", "PMingLiU"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| :root:lang(zh-HK) { |  | ||||||
|   --fonts-proportional: "PingFang HK", "Hiragino Sans TC", "Source Han Sans HK", "Source Han Sans TC", "Noto Sans CJK TC", "Microsoft JhengHei", "Heiti TC", "PMingLiU_HKSCS", "PMingLiU"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| :root:lang(ko) { |  | ||||||
|   --fonts-proportional: "Apple SD Gothic Neo", "NanumBarunGothic", "Malgun Gothic", "Gulim", "Dotum", "Nanum Gothic", "Source Han Sans KR", "Noto Sans CJK KR"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| @font-face { |  | ||||||
|   font-family: "Yu Gothic"; |  | ||||||
|   src: local("Yu Gothic Medium"); |  | ||||||
|   font-weight: 400; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| @font-face { |  | ||||||
|   font-family: "Yu Gothic"; |  | ||||||
|   src: local("Yu Gothic Bold"); |  | ||||||
|   font-weight: 500; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| textarea { | textarea { | ||||||
|  | @ -1151,12 +1122,20 @@ footer { | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .ui.language .menu { |   .ui.language { | ||||||
|  |     .menu { | ||||||
|       max-height: 500px; |       max-height: 500px; | ||||||
|       overflow-y: auto; |       overflow-y: auto; | ||||||
|       margin-bottom: 7px; |       margin-bottom: 7px; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     .svg { | ||||||
|  |       margin-right: .15em; | ||||||
|  |       vertical-align: top; | ||||||
|  |       margin-top: calc(2em - 16px); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   .ui { |   .ui { | ||||||
|     &.left, |     &.left, | ||||||
|     &.right { |     &.right { | ||||||
|  | @ -1885,6 +1864,17 @@ table th[data-sortt-desc] { | ||||||
|   font-style: normal !important; |   font-style: normal !important; | ||||||
|   font-weight: normal !important; |   font-weight: normal !important; | ||||||
|   vertical-align: -.075em; |   vertical-align: -.075em; | ||||||
|  | 
 | ||||||
|  |   @supports (-webkit-hyphens:none) { | ||||||
|  |     body:not(.safari-above125) & { | ||||||
|  |       font-size: inherit; | ||||||
|  |       vertical-align: inherit; | ||||||
|  |       img { | ||||||
|  |         font-size: 1.25em; | ||||||
|  |         vertical-align: -.225em !important; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .emoji img, | .emoji img, | ||||||
|  |  | ||||||
							
								
								
									
										130
									
								
								web_src/less/_font_i18n.less
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								web_src/less/_font_i18n.less
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,130 @@ | ||||||
|  | /* font i18n */ | ||||||
|  | :root { | ||||||
|  |   /* customizable localized variables */ | ||||||
|  |   :lang(ja) { | ||||||
|  |     --fonts-override: var(--fonts-default-override-ja); | ||||||
|  |   } | ||||||
|  |   :lang(zh-CN) { | ||||||
|  |     --fonts-override: var(--fonts-default-override-zh-cn); | ||||||
|  |   } | ||||||
|  |   :lang(zh-TW) { | ||||||
|  |     --fonts-override: var(--fonts-default-override-zh-tw); | ||||||
|  |   } | ||||||
|  |   :lang(zh-HK) { | ||||||
|  |     --fonts-override: var(--fonts-default-override-zh-hk); | ||||||
|  |   } | ||||||
|  |   :lang(ko) { | ||||||
|  |     --fonts-override: var(--fonts-default-override-ko); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | [lang] { | ||||||
|  |   font-family: var(--fonts-regular); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | each(@fonts, { | ||||||
|  |   @weights: .gen-weights-all(@value); | ||||||
|  |   @locale: replace(@key, "@", "-"); | ||||||
|  |   .font-face-cjk(~"system-ui@{locale}", @weights[@light], 300); | ||||||
|  |   .font-face-cjk(~"system-ui@{locale}", @weights[@regular], 400); | ||||||
|  |   .font-face-cjk(~"system-ui@{locale}", @weights[@medium], 500); | ||||||
|  |   .font-face-cjk(~"system-ui@{locale}", @weights[@bold], 700); | ||||||
|  |   /* Safari on macOS/iOS */ | ||||||
|  |   @font-face { | ||||||
|  |     font-family: ~"system-ui@{locale}"; | ||||||
|  |     src: local("HelveticaNeue"); | ||||||
|  |     unicode-range: U+A0; | ||||||
|  |   } | ||||||
|  |   /* Other browsers on macOS/iOS */ | ||||||
|  |   @supports not (-webkit-hyphens:none) { | ||||||
|  |     @font-face { | ||||||
|  |       font-family: ~"system-ui@{locale}"; | ||||||
|  |       src: local("HelveticaNeue"); | ||||||
|  |       unicode-range: U+20; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   :root { | ||||||
|  |     /* Special handling for Firefox on Windows/Linux */ | ||||||
|  |     @supports (-moz-appearance:none) { | ||||||
|  |       --fonts-default-override@{locale}: ~"var(--fonts-proportional), system-ui@{locale}"; | ||||||
|  |     } | ||||||
|  |     --fonts-default-override@{locale}: ~"system-ui@{locale}, var(--fonts-proportional)"; | ||||||
|  |   } | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | @fonts: { | ||||||
|  |   @ja: | ||||||
|  |     "HiraginoSans-:{W2,W4,W5,W6}", "HiraKakuProN-:{W3,W6}", "Hiragino Kaku Gothic ProN :{W3,W6}", | ||||||
|  |     .shs("JP")[], .shs("J")[], .noto("JP")[], .shs("")[], | ||||||
|  |     /* https://acetaminophen.hatenablog.com/entry/2016/02/15/225009 */ | ||||||
|  |     "Yu Gothic :{Regular,Medium,Bold}", "YuGothic :{Regular,Medium,Bold}", | ||||||
|  |     "Droid Sans Japanese:{}", "Meiryo:{, Bold}", "MS PGothic:{}"; | ||||||
|  |   @zh-cn: | ||||||
|  |     .pingfang("SC")[], | ||||||
|  |     .shs("CN")[], .shs("SC")[], .noto("SC")[], | ||||||
|  |     "HiraginoSansGB-:{W3,W6}", "Hiragino Sans GB :{W3,W6}", | ||||||
|  |     "Microsoft YaHei:{ Light,, Bold}", "Heiti SC :{Light,Medium}", "SimHei:{}"; | ||||||
|  |   @zh-tw: | ||||||
|  |     .pingfang("TC")[], | ||||||
|  |     .shs("TW")[], .shs("TC")[], .noto("TC")[], | ||||||
|  |     "HiraginoSansTC-:{W3,W6}", "Hiragino Sans TC :{W3,W6}", | ||||||
|  |     "Microsoft JhengHei:{ Light,, Bold}", "Heiti TC :{Light,Medium}", "PMingLiU:{}"; | ||||||
|  |   @zh-hk: | ||||||
|  |     .pingfang("HK")[], | ||||||
|  |     .shs("HK")[], .shs("HC")[], .noto("HK")[], .shs("TC")[], .noto("TC")[], | ||||||
|  |     "HiraginoSansTC-:{W3,W6}", "Hiragino Sans TC :{W3,W6}", | ||||||
|  |     "Microsoft JhengHei:{ Light,, Bold}", "Heiti TC :{Light,Medium}", "PMingLiU_HKSCS:{}", "PMingLiU:{}"; | ||||||
|  |   @ko: | ||||||
|  |     "AppleSDGothicNeo-:{Light,Regular,Medium,SemiBold}", | ||||||
|  |     .shs("KR")[], .shs("K")[], .noto("KR")[], | ||||||
|  |     "NanumBarunGothic:{ Light,, Bold}", | ||||||
|  |     "Malgun Gothic:{ Semilight,, Bold}", "Nanum Gothic:{, Bold}", "Dotum:{}"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .noto(@suffix) { @value: "Noto Sans CJK @{suffix} ", "NotoSansCJK@{suffix}-"; } | ||||||
|  | .shs(@suffix) { @value: replace("Source Han Sans @{suffix} ", "  ", " "), "SourceHanSans@{suffix}-"; } | ||||||
|  | .pingfang(@suffix) { @value: "PingFang@{suffix}-:{Light,Regular,Medium,Semibold}"; } | ||||||
|  | .font-face-cjk(@family, @src, @weight) { | ||||||
|  |   @font-face { | ||||||
|  |     font-family: @family; | ||||||
|  |     src: @src; | ||||||
|  |     font-weight: @weight; | ||||||
|  |     unicode-range: ~"U+11??, U+2E80-4DBF, U+4E00-9FFF, U+A960-A97F, U+AC00-D7FF, U+F900-FAFF, U+FE00-FE6F, U+FF00-FFEF, U+1F2??, U+2????"; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .gen-weights(@family) when (isstring(@family)) { | ||||||
|  |   @family-str: replace(@family, ":\{.*\}$", ""); | ||||||
|  |   // apply standard style names if none is given | ||||||
|  |   // should the font have no styles, use :{}, as in "SimHei:{}" | ||||||
|  |   @weights-str: if(@family = @family-str, "Light,Regular,Medium,Bold", replace(@family, ".*:\{(.*)\}$", "$1")); | ||||||
|  |   @lightest: replace(@weights-str, ",.*", ""); | ||||||
|  |   @boldest: replace(@weights-str, ".*,", ""); | ||||||
|  |   @2ndboldest: replace(@weights-str, "(?:.*,|)([^,]*),.*$", "$1"); | ||||||
|  |   @2ndlightest: if(@2ndboldest = @lightest, @lightest, replace(@weights-str, "^.*?,([^,]*).*", "$1")); | ||||||
|  | 
 | ||||||
|  |   @light: local("@{family-str}@{lightest}"); | ||||||
|  |   @regular: local("@{family-str}@{2ndlightest}"); | ||||||
|  |   @medium: local("@{family-str}@{2ndboldest}"); | ||||||
|  |   @bold: local("@{family-str}@{boldest}"); | ||||||
|  | } | ||||||
|  | .gen-weights(@family) when not (isstring(@family)) { | ||||||
|  |   .gen-weights-all(@family); | ||||||
|  | } | ||||||
|  | .gen-weights(@family, @last) { | ||||||
|  |   @this: .gen-weights(@family); | ||||||
|  | 
 | ||||||
|  |   @light: @last[@light], @this[@light]; | ||||||
|  |   @regular: @last[@regular], @this[@regular]; | ||||||
|  |   @medium: @last[@medium], @this[@medium]; | ||||||
|  |   @bold: @last[@bold], @this[@bold]; | ||||||
|  | } | ||||||
|  | .gen-weights-all(@family) when not (isstring(@family)) { | ||||||
|  |   .gen-weights-all(@family, length(@family)); | ||||||
|  | } | ||||||
|  | .gen-weights-all(@family, 1) when not (isstring(@family)) { | ||||||
|  |   .gen-weights(extract(@family, 1)); | ||||||
|  | } | ||||||
|  | .gen-weights-all(@family, @ctr) when not (isstring(@family)) and (@ctr > 1) and (@ctr <= length(@family)) { | ||||||
|  |   .gen-weights(extract(@family, @ctr), .gen-weights-all(@family, @ctr - 1)); | ||||||
|  | } | ||||||
|  | @ -13,6 +13,7 @@ | ||||||
| 
 | 
 | ||||||
| @import "_svg"; | @import "_svg"; | ||||||
| @import "_tribute"; | @import "_tribute"; | ||||||
|  | @import "_font_i18n"; | ||||||
| @import "_base"; | @import "_base"; | ||||||
| @import "_markdown"; | @import "_markdown"; | ||||||
| @import "_home"; | @import "_home"; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue