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

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

相关推荐
Jiaberrr2 小时前
前端实战:使用JS和Canvas实现运算图形验证码(uniapp、微信小程序同样可用)
前端·javascript·vue.js·微信小程序·uni-app
everyStudy3 小时前
JS中判断字符串中是否包含指定字符
开发语言·前端·javascript
城南云小白3 小时前
web基础+http协议+httpd详细配置
前端·网络协议·http
前端小趴菜、3 小时前
Web Worker 简单使用
前端
web_learning_3213 小时前
信息收集常用指令
前端·搜索引擎
tabzzz3 小时前
Webpack 概念速通:从入门到掌握构建工具的精髓
前端·webpack
200不是二百3 小时前
Vuex详解
前端·javascript·vue.js
滔滔不绝tao3 小时前
自动化测试常用函数
前端·css·html5
码爸4 小时前
flink doris批量sink
java·前端·flink
深情废杨杨4 小时前
前端vue-父传子
前端·javascript·vue.js