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

事情的经过是这样的。前段时间,看到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就没有问题。嗯,这也是我提交合并请求的思路,已经合并了。

相关推荐
y先森4 小时前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy4 小时前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189114 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿5 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡6 小时前
commitlint校验git提交信息
前端
虾球xz7 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇7 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒7 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员7 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐7 小时前
前端图像处理(一)
前端