mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	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:
		@@ -1,5 +1,5 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="{{.Language}}" class="theme-{{.SignedUser.Theme}}">
 | 
			
		||||
<html lang="{{.Lang}}" class="theme-{{.SignedUser.Theme}}">
 | 
			
		||||
<head data-suburl="{{AppSubUrl}}">
 | 
			
		||||
	<meta charset="utf-8">
 | 
			
		||||
	<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 {createCodeEditor, createMonaco} from './features/codeeditor.js';
 | 
			
		||||
import {svg, svgs} from './svg.js';
 | 
			
		||||
import {stripTags} from './utils.js';
 | 
			
		||||
import {stripTags, mqBinarySearch} from './utils.js';
 | 
			
		||||
 | 
			
		||||
const {AppSubUrl, StaticUrlPrefix, csrf} = window.config;
 | 
			
		||||
 | 
			
		||||
@@ -2519,6 +2519,19 @@ $(document).ready(async () => {
 | 
			
		||||
      .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.
 | 
			
		||||
  $('.dropdown:not(.custom)').dropdown({
 | 
			
		||||
    fullTextSearch: 'exact'
 | 
			
		||||
 
 | 
			
		||||
@@ -28,3 +28,16 @@ export function uniq(arr) {
 | 
			
		||||
export function stripTags(text) {
 | 
			
		||||
  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 {
 | 
			
		||||
  /* documented customizable variables */
 | 
			
		||||
  --fonts-proportional: system-ui, -apple-system, "BlinkMacSystemFont", "Segoe UI", "Roboto", "Helvetica Neue", "Arial", "Noto Sans", "Liberation Sans", sans-serif;
 | 
			
		||||
  --fonts-monospace: "SFMono-Regular", "Menlo", "Monaco", "Consolas", "Liberation Mono", "Courier New", monospace;
 | 
			
		||||
  --fonts-emoji: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", "Twemoji Mozilla";
 | 
			
		||||
  --fonts-proportional: -apple-system, "Segoe UI", system-ui, "Roboto", "Helvetica Neue", "Arial";
 | 
			
		||||
  --fonts-monospace: "SFMono-Regular", "Menlo", "Monaco", "Consolas", "Liberation Mono", "Courier New", monospace, var(--fonts-emoji);
 | 
			
		||||
  --fonts-emoji: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", "Twemoji Mozilla";
 | 
			
		||||
  /* other variables */
 | 
			
		||||
  --fonts-regular: var(--fonts-proportional), var(--fonts-emoji);
 | 
			
		||||
  --border-radius: .28571429rem;
 | 
			
		||||
  --opacity-disabled: .55;
 | 
			
		||||
  --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>');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
:root:lang(ja) {
 | 
			
		||||
  --fonts-proportional: "Hiragino Kaku Gothic ProN", "Yu Gothic", "Source Han Sans JP", "Noto Sans CJK JP", "Droid Sans Japanese", "Meiryo", "MS PGothic";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
: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;
 | 
			
		||||
:root * {
 | 
			
		||||
  --fonts-regular: var(--fonts-override, var(--fonts-proportional)), "Noto Sans", "Liberation Sans", var(--fonts-emoji), sans-serif;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
textarea {
 | 
			
		||||
@@ -1151,10 +1122,18 @@ footer {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .ui.language .menu {
 | 
			
		||||
    max-height: 500px;
 | 
			
		||||
    overflow-y: auto;
 | 
			
		||||
    margin-bottom: 7px;
 | 
			
		||||
  .ui.language {
 | 
			
		||||
    .menu {
 | 
			
		||||
      max-height: 500px;
 | 
			
		||||
      overflow-y: auto;
 | 
			
		||||
      margin-bottom: 7px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .svg {
 | 
			
		||||
      margin-right: .15em;
 | 
			
		||||
      vertical-align: top;
 | 
			
		||||
      margin-top: calc(2em - 16px);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .ui {
 | 
			
		||||
@@ -1885,6 +1864,17 @@ table th[data-sortt-desc] {
 | 
			
		||||
  font-style: normal !important;
 | 
			
		||||
  font-weight: normal !important;
 | 
			
		||||
  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,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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 "_tribute";
 | 
			
		||||
@import "_font_i18n";
 | 
			
		||||
@import "_base";
 | 
			
		||||
@import "_markdown";
 | 
			
		||||
@import "_home";
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user