错位之谜:网站简体中文何以变繁?

事情的经过是这样的。前段时间,看到Deno官网改版了: 但是当我习惯性点击『谷歌翻译』为中文简体时,发现页面不对劲,怎么是繁体字呢: 当时以为找到了『谷歌翻译』的Bug,后来看到其它网页的翻译都正常,就知道自己想多了。

下来问题来了,Deno官网是怎么做到的(相信它不是故意的)呢?

追凶

在网络里可以看到,点击了翻译后,主要是这个接口请求: 从参数上看,传递的是对的,zh-CN是中文简体: 响应也没毛病,全是简体: 那么问题只能出在页面展示上了,我第一反应是字体引起的,是不是Deno用了什么特殊的字体呢?在网络里只看到这两位: 从预览上看也不是中文字体,没什么特殊的: 好在Deno的官网是开源的,到GitHub上找到项目地址github.com/denoland/de...,拉到本地。看package.json中的配置项,发现这是一个Node.js的项目,用的是docusaurus框架: 好吧,意料之中,就像我的deno_nest文档用Umi一样,都是图省事。然后使用.github/workflows/deploy.yml配置了GitHub流水线,将打包后的产物(build目录)使用Deno Deploy平台部署:

yaml 复制代码
name: Deploy
on:
  push:
    branches: main
  pull_request:
    branches: main

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-22.04-xl
    permissions:
      id-token: write # Needed for auth with Deno Deploy
      contents: read # Needed to clone the repository

    steps:
      - name: Clone repository
        uses: actions/checkout@v4

      - name: Install Node.js
        uses: actions/setup-node@v3
        with:
          node-version: lts/*

      - name: Build step
        run: npm install && npm run build

      - name: Upload to Deno Deploy
        uses: denoland/deployctl@v1
        with:
          project: "deno-docs"
          entrypoint: "server.ts"
          root: "build"

扯远了。

我们接着探案。

将项目启动之后,在本地访问http://localhost:3000/,再点谷歌翻译,效果是一样的: 我尝试着搜索了下woff文件,就两个文件里有: 但将这些字体内容都注释掉后,没有任何变化,说明这个猜测是错误的。那就有些懵圈了,还能有什么原因呢?

好在我能确定的一点是,之前Deno官网的翻译是绝对没有问题的,于是使用『二分法』,在Git记录中先找到23年8月的某个版本,运行了一下,看到翻译是OK的,再一步步缩减范围,最终找到了罪魁祸首,是12月5号的一个提交:

这个提交里,有我们刚才搜索到的index.jsinter.css文件。这又说明,与字体还是有关联的?

这是index.js的部分代码,其实就是核心布局。

jsx 复制代码
export default function Layout(props) {
  const {
    children,
    noFooter,
    wrapperClassName,
    // Not really layout-related, but kept for convenience/retro-compatibility
    title,
    description,
  } = props;
  useKeyboardNavigation();
  return (
    <LayoutProvider>
      <Head>
        <link
          rel="preload"
          href="/fonts/inter/Inter-Regular.woff2"
          as="font"
          type="font/woff2"
          crossOrigin="true"
        />
        <link
          rel="preload"
          href="/fonts/inter/Inter-SemiBold.woff2"
          as="font"
          type="font/woff2"
          crossOrigin="true"
        />
        <script src="/trackjs.js"></script>
        <script src="https://cdn.trackjs.com/releases/current/tracker.js"></script>
        <link rel="stylesheet" href="/fonts/inter.css" />
      </Head>
    	...
    </LayoutProvider>
  );
}

inter.css的内容如下:

css 复制代码
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/inter/Inter-Regular.woff2") format("woff2");
}

@font-face {
  font-family: "Inter";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/inter/Inter-Italic.woff2") format("woff2");
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/fonts/inter/Inter-SemiBold.woff2") format("woff2");
}

@font-face {
  font-family: "Inter";
  font-style: italic;
  font-weight: 700;
  font-display: swap;
  src: url("/fonts/inter/Inter-SemiBoldItalic.woff2") format("woff2");
}

:root {
  font-feature-settings: "cv05" on, "cv08" on, "cv10" on, "ss01" on, "ss08" on;
}

之前测试时,仅注释了index.js中两个字体文件的link,和CSS文件中这几个font-face。这次把漏网之鱼:root也注释掉,发现居然正常了。

探底

这一行代码有什么魔力呢? 我写了一个最简单的页面进行测试,经过排查,发现与font-feature-settings配置的cv10有关。

html 复制代码
<!DOCTYPE html>
<html>
  <head>
    <style>
      :root {
        font-feature-settings: "cv10" on;
      }
    </style>
  </head>

  <body>
    <h2>我是中国人</h2>
  </body>

</html>

可这玩意儿是什么呢?遇事不决问GPT:

Q:font-feature-settings的配置项"cv10 on"代表什么意思?它为什么将网页中本身的中文简体显示为繁体?

A:"cv10 on" 是 OpenType 字体特性设置的一种形式,它表示启用了 Contextual Variant Feature(上下文变体特性)的第10个变体。这通常用于处理字形的上下文相关变体,例如在特定语境中显示不同的字形形状。

关于为什么在网页中会将中文简体显示为繁体,这可能是因为网页作者使用了特定的字体特性设置,例如"cv10 on",以实现一些特定的设计效果。如果您在浏览网页时遇到这种情况,可以尝试联系网页作者或者检查网页的样式表和字体设置,看是否有类似的特性被应用。

另外,浏览器也可能会根据系统和用户首选项来进行字体替代,所以检查浏览器设置也是一个解决问题的途径。

好吧,这段回答中,可能有用的是,我们知道了它与字体特性有关。 MDN也这么说:

font-feature-settings属性用于控制 OpenType 字体中的高级印刷功能。

在Google上以这几个关键字搜索时,找到一篇文章,是讲移动端开发的。

什么是 FontFeature? 简单来说就是影响字体形状的一个属性 ,在前端的对应领域里应该是 font-feature-settings,它有别于 FontFamily ,是用于指定字体内字的形状参数。

在iOS的段落里找到一部分: 我冒出一个想法,这个问题搞不好可能只有iOS上才有。于是修改了下HTML的代码(放在了CDN上,有兴趣的朋友可以点击验证下):

html 复制代码
<!DOCTYPE html>
<html>

<head>
  <title>font feature settings</title>
  <style>
  h2 {
    font-feature-settings: "cv10" on;
  }
  </style>
  <script>
    window.onload = function () {
      var app = document.getElementById('app');
      var computedStyle = getComputedStyle(app);
      var fontFamily = computedStyle.getPropertyValue("font-family");
      document.getElementById('text').innerHTML = "当前文本使用的字体为:" + fontFamily;
    }
  </script>
</head>

<body>
  <h2 id="app">我是中国人</h2>
  <span id="text">文档</span>
</body>

</html>

在Chrome和Edge上显示,果然用的是『苹方』字体:

又在我的安卓机上访问,看到的是简体:

回过头,试了下Safari浏览器,居然也是正常的:

这么说来,就是『苹方』字体的锅了!

我再修改用例,给h2添加一个『简宋』字体:

css 复制代码
h2 {
  font-family: "简宋";
  font-feature-settings: "cv10" on;
}

这次在Chrome里也正常了:

你可能会疑惑,为什么选择了一个『简宋』呢?其实我一开始用的是『宋体』,但是一个德性。

后来在字体集里一看,才意识到是不是这些成双成对的都不行?

而这几位单身狗都没问题:

现象已经很明显了:在Chrome里,当配置font-feature-settings: "cv10" on后,会优先匹配当前字体的繁体集。

为什么要强调是Chrome呢(Edge与它穿一条裤子,就不提了)?因为在Safari里不受这个影响:

我猜测是这个特性没有被实现有关。有兴趣的同学看看这篇字体特性的介绍,我是没兴趣研究它了。

总结

我们从Deno官网使用谷歌翻译为中文简体,但页面却展示为中文繁体开始查起,通过『二分法』,最终确定了罪魁祸首为font-feature-settings: "cv10" on这个字体特性,它会影响字体形状,但在Chrome下表现为会优先匹配当前字体的繁体字集。

至于为什么会有这样的效果,我猜测是字体变形到某种程度引起的。将cv10调整为临近的cv09就没有问题。嗯,这也是我提交合并请求的思路,已经合并了。

相关推荐
懒羊羊我小弟14 分钟前
包管理工具npm、yarn、pnpm、cnpm详解
前端·npm·node.js·yarn·cnpm
ppo_wu18 分钟前
更改 pnpm 的全局存储位置
前端·vue
"追风者"30 分钟前
前端(八)js介绍(1)
前端·javascript
博客zhu虎康38 分钟前
用 ElementUI 的日历组件 Calendar 自定义渲染
前端·javascript·elementui
叶浩成52039 分钟前
elementUI——upload限制图片或者文件只能上传一个——公开版
前端·javascript·elementui
yqcoder43 分钟前
同源策略详解
xml·前端·javascript
rkmhr_sef1 小时前
Web API基本认知
前端
姬嘉晗-19期-河北工职大1 小时前
Ajax中的axios
前端·javascript·ajax
zhenryx1 小时前
微涉全栈(react,axios,node,mysql)
前端·mysql·react.js
xcLeigh1 小时前
HTML5实现好看的圣诞节网站源码
前端·html·html5·圣诞节