前几天在知乎上回答了一个问题,这里记录备份一下。
在回答“前端如何实现中文、英文、数字使用不同字体?”这个问题之前,其实应该先明确中文、英文、数字包括哪些字。 对于中文而言,是否只包括中文汉字、汉字部首、汉语注音符号、中文常用标点符号,不包括日本汉字,不包括假名、谚文、喃字,英文是否只包括英语字母,不包括法语、德语、西班牙语、汉语拼音字母中特殊字母,数字是否仅限阿拉伯数字。
实现方式
以下是两种实现方式:
- 使用 CSS
@font-face
规则和unicode-range
属性。 - 使用 CSS
:lang
伪类和 HTMLlang
属性。
第一种方式
这种方式设置 unicode-range
属性时需要明确字符的 Unicode 范围,一般仅针对少量字符做处理,适合处理中文双引号展示、人民币符号、等宽字体显示时间等问题。
用法可参考如下 antd 的代码:
/* 来源自 https://github.com/ant-design/ant-design 目前版本已经移除该部分样式 */
@font-face {
font-family: "Helvetica Neue For Number";
src: local("Helvetica Neue");
unicode-range: U+30-39;
}
@font-face {
font-family: "Monospaced Number";
src: local("Menlo"), local("Consolas");
unicode-range: U+30-39;
}
@font-face {
font-family: "Chinese Quote";
src: local("PingFang SC"), local("SimSun");
unicode-range: U+2018, U+2019, U+201c, U+201d;
}
body {
font-family: "Chinese Quote", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
其中指定 U+0030 - U+0039 的字符(即 0-9)使用 Helvetica Neue 字体,U+2018, U+2019, U+201C, U+201D(即单引号、双引号)使用苹方-简、中易宋体。
除此以外还可以参考 Google Fonts 的 CSS,如:
/* 来源自 https://fonts.googleapis.com/css?family=Open%20Sans:300,400,600,700&lang=en */
/* cyrillic */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 300;
src: local('Open Sans Light'), local('OpenSans-Light'), url(https://fonts.gstatic.com/s/opensans/v17/mem5YaGs126MiZpBA-UN_r8OVuhpKKSTj5PW.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 300;
src: local('Open Sans Light'), local('OpenSans-Light'), url(https://fonts.gstatic.com/s/opensans/v17/mem5YaGs126MiZpBA-UN_r8OUehpKKSTj5PW.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* latin */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 300;
src: local('Open Sans Light'), local('OpenSans-Light'), url(https://fonts.gstatic.com/s/opensans/v17/mem5YaGs126MiZpBA-UN_r8OUuhpKKSTjw.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
其中为西里尔字母、希腊字母、拉丁字母指定了不同的字体。
第二种方式
这种方式基于语言代码(Language Code),在处理国际化、本地化时常用,适合处理中英文混排。
可参考中文排版需求页面的代码:
/* 来源自 https://w3c.github.io/clreq/local.css */
[lang=zh-hant] {
font-family: 'PingFang TC', 'Noto Sans CJK TC', 'Heiti TC', 'Microsoft JhengHei', Helvetica, Segoe UI, Arial, sans-serif;
}
[lang=zh-hans] {
font-family: 'PingFang SC', 'Noto Sans CJK SC', 'Heiti SC', 'DengXian', 'Microsoft YaHei', Helvetica, Segoe UI, Arial, sans-serif;
}
<!-- 来源自 https://w3c.github.io/clreq/ -->
<p its-locale-filter-list="en" lang="en">Each cultural community has its own language, script and writing system. The transfer of each and every writing system into cyberspace is a task of utmost importance for information and communication technology.</p>
<p its-locale-filter-list="zh-hans" lang="zh-hans">每一个文化群体都拥有独自的语言、文字、书写系统。将个别书写系统在虚拟空间再现,对文化资产的承继而言,是信息传播技术的重要责任。</p>
<p its-locale-filter-list="zh-hant" lang="zh-hant">每一個文化群體都擁有獨自的語言、文字、書寫系統。將個別書寫系統在虛擬空間再現,對文化資產的承繼而言,是資訊傳播技術的重要責任。</p>
其中不同语言的 HTML 内容使用了不同的 lang
属性,并在 CSS 中为不同 lang
指定不同字体。
除此以外,以常见的苹果公司中文首页为例:
/* 来源自 https://www.apple.com.cn/v/home/er/built/styles/main.built.css */
html {
font-family: "SF Pro Text","SF Pro Icons","Helvetica Neue","Helvetica","Arial",sans-serif;
}
[lang]:lang(ja) {
font-family: "SF Pro JP","SF Pro Text","SF Pro Icons","Hiragino Kaku Gothic Pro","ヒラギノ角ゴ Pro W3","メイリオ","Meiryo","MS Pゴシック","Helvetica Neue","Helvetica","Arial",sans-serif
}
[lang]:lang(ko) {
font-family: "SF Pro KR","SF Pro Text","SF Pro Icons","Apple Gothic","HY Gulim","MalgunGothic","HY Dotum","Lexi Gulim","Helvetica Neue","Helvetica","Arial",sans-serif
}
[lang]:lang(zh-CN) {
font-family: "SF Pro SC","SF Pro Text","SF Pro Icons","PingFang SC","Helvetica Neue","Helvetica","Arial",sans-serif
}
[lang]:lang(zh-HK) {
font-family: "SF Pro HK","SF Pro Text","SF Pro Icons","PingFang HK","Helvetica Neue","Helvetica","Arial",sans-serif
}
[lang]:lang(zh-MO) {
font-family: "SF Pro HK","SF Pro TC","SF Pro Text","SF Pro Icons","PingFang HK","Helvetica Neue","Helvetica","Arial",sans-serif
}
[lang]:lang(zh-TW) {
font-family: "SF Pro TC","SF Pro Text","SF Pro Icons","PingFang TC","Helvetica Neue","Helvetica","Arial",sans-serif
}
其中的这段 CSS 同样是使用 :lang
伪类为不同语言、地区指定不同的字体。
最后,演示一下中英文混排,样式参见上面的 CSS:
<p lang="zh-hans">苹果公司联合创始人史蒂夫·乔布斯(<span lang="en">Steve Jobs</span>)在斯坦福大学2005年毕业典礼上的演讲中曾提到过一句名言“<span lang="en">Stay hungry, stay foolish.</span>”</p>
总结
这两种方式各有千秋,前者需要考虑中英文及数字的 Unicode 范围,后者需要为不同语言的 HTML 元素添加相应 lang
属性。
补充
上述两种实现方式比较精细,如果设计要求不高可以采用一种更简单粗暴的方法,利用浏览器字体的回退机制,将西文字体写在前面,中文字体写在后面,这样也可以实现字母数字渲染为西文字体,中文部分渲染为中文字体。
举两个例子:
.foo {
/* 西文部分使用 'Segoe UI',中文使用 'Microsoft YaHei' */
font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
}
.bar {
/* 西文部分使用 'Helvetica Neue'、Helvetica,中文使用 'PingFang SC' */
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', sans-serif;
}
实际项目中使用时注意考虑不同平台字体支持情况,做好回退处理。
以等宽字体为例,西文部分使用 Consolas, Menlo, Monaco, 'Courier New'
,中文使用 'PingFang SC', 'Microsoft YaHei'
,最后再加上 monospace
兜底。
.mono {
font-family: Consolas, Menlo, Monaco, 'Courier New', 'PingFang SC',
'Microsoft YaHei', monospace;
}