6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Webページで一部フォントの位置がOS依存になる問題に対処する

Last updated at Posted at 2025-04-17

DIN CondensedをVivliostyleで使用していたところ、WindowsとLinux(&macOS)で組版結果が異なることに気づきました。Playwrightを直接使用して確認してみても同様の問題が発生していたため、おそらくWindows版のChromiumのレンダリング実装周りに問題があるのではないかと推測します。

Linux Windows
before.linux.png before.win32.png
再現用ソースコード
<html>
  <head>
    <style>
      @font-face {
        font-family: "DIN Condensed Bold";
        src: url("DIN Condensed Bold.ttf");
      }
    </style>
  </head>
  <body style="margin: 0">
    <div
      style="
        margin: 0;
        width: 100px;
        height: 100px;
        background-color: lightgray;
      "
    ></div>
    <p
      style='
        margin: 0;
        font-family: "DIN Condensed Bold";
        font-size: 48px;
        position: absolute;
        left: 100px;
        top: 100px;
        border: solid black 1px;
      '
    >
      0
    </p>
  </body>
</html>
import os from "node:os";
import path from "node:path";
import * as url from "node:url";

import { chromium } from "playwright";

const indexPath = path.resolve(
  path.dirname(url.fileURLToPath(import.meta.url)),
  "index.html",
);
const indexUrl = url.pathToFileURL(indexPath).toString();

const browser = await chromium.launch();
try {
  const page = await browser.newPage();
  await page.goto(indexUrl);
  await page.screenshot({
    path: `screenshot.${os.platform()}.png`,
    clip: { x: 0, y: 0, width: 300, height: 300 },
  });
} finally {
  await browser.close();
}

メモ:

> docker run --rm --interactive --tty --mount type=bind,source=.,target=/workdir --entrypoint /bin/bash --workdir /workdir node:lts
# npm install && npx playwright install --with-deps chromium

CSSからフォントの設定値を上書きできれば解決できそうです。ascent-overridedescent-overrideline-gap-overrideプロパティが該当することがわかりました。

適切な値を設定するために、Pythonスクリプトでフォントのメトリクス情報を調べます。

import fontTools.ttLib

def get_font_metrics_for_override(path: str):
    font = fontTools.ttLib.TTFont(path)

    units_per_em = font["head"].unitsPerEm
    os2 = font["OS/2"]

    ascent = os2.sTypoAscender
    descent = abs(os2.sTypoDescender)
    line_gap = os2.sTypoLineGap

    ascent_override = 100 * ascent / units_per_em
    descent_override = 100 * descent / units_per_em
    line_gap_override = 100 * line_gap / units_per_em

    return [ascent_override, descent_override, line_gap_override]


[ascent_override, descent_override, line_gap_override] = get_font_metrics_for_override(
    "DIN Condensed Bold.ttf"
)
print(f"ascent-override: {ascent_override}%;")
print(f"descent-override: {descent_override}%;")
print(f"line-gap-override: {line_gap_override}%;")
$ .venv/bin/pip install fonttools
$ .venv/bin/python main.py
ascent-override: 71.2%;
descent-override: 28.8%;
line-gap-override: 20.0%;

上記で得られた値を使って、CSSの@font-faceルールを修正します。

  @font-face {
    font-family: "DIN Condensed Bold";
    src: url("DIN Condensed Bold.ttf");
+   ascent-override: 71.2%;
+   descent-override: 28.8%;
+   line-gap-override: 20.0%;
  }
Linux Windows
after.linux.png after.win32.png

完全一致とはいきませんが実用上問題ない程度に改善することができました。

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?