使用 JavaScript 改善中文伪斜体

• Notes

众所周知,中文没有所谓的「斜体字形」(italic font shape), 因此在与有斜体的西文字体配合时效果不佳。 中 有一套较复杂的字体框架,其下可以通过选择不同字体来对中、西文的斜体造成不同效果;一般的 做法,是西文斜体保持默认设置(采用 italic font),中文则使用楷体、仿宋等接近手写体的 字体来表示原希望用斜体实现的强调引用效果。

在一般标记语言中,似乎还无法用简单的方式来实现这一效果。如在 HTML + CSS 体系下,整个元素 只能指定统一的 font-style: italic 样式规则,此时没有斜体字形的中文内容会被转换为别扭 的伪斜体。为了实现与 中相近的、在排版上也更加美观的效果, 只能走个弯路:

  • 找到各应用斜体的元素(对我的网站,只会出先在 emblockquote 元素中,对其他人可能 更加复杂),获取其 innerHTML
  • 用正则表达式将其中文部分筛出;
  • 将所有中文内容包裹在一个自定义元素,通过此元素的样式表来实现字体修正。

例如,将所有 em 标签中的中文筛出,并消除伪斜体、采用楷体,只需如下的 JavaScript 代码 (在内容加载完成时执行):

var em_list = document.querySelectorAll('em')
    for (item of em_list) {
        var reg = /[\u4e00-\u9fa5]+/g  // filter chinese (deprecated method)
        item.innerHTML = item.innerHTML.replace(reg, '<kaiti>$&</kaiti>')  // wrap
    }

并为上面包裹时用的自定义标签 kaiti 设置如下样式:

kaiti {
    font-style: normal;  /* remove fake italic shape */
    font-family: '楷体';  /* more and other fonts can be applied */
}

三个问题:

  • /\u4e00-\u9fa5/ 还可靠吗?——不很可靠了,你可以搜搜看最新的中文匹配方式,现在似乎有更好的方式。我是懒人,目前未看见例外,又怕新方式在某些浏览器中不兼容(比如 \p 在我习用的 Firefox 中还不支持),所以这样敷衍了事了。(此外,你可以在正则匹配名单中加入中文标点、英文标点等更多内容,都是可行的。
  • 直接处理 innerHTML 是否安全?——这里由正则表达式操作的仅是中文内容,一般来说不会碰到文本以外的内容(除非某些元素有中文属性)。
  • 移动端怎么办?——移动端系统上默认没有楷体、仿宋之类的备选字体,实在没辙。