Playwrightの中華フォントを修正してNotoフォントにする
目次
Docker上でPlaywrightを使ってテストしようとすると、いわゆる中華フォントでレンダリングされてしまうことがある。これをIPAフォントに修正したりNotoフォントに修正したりする方法を記載する。また、どのフォントを使ってるかの確認方法も合わせて紹介する。
症状
Docker上でこのようにPlaywrightを--with-deps
でインストールして、Webフォントを使っていないようなページ、例えばMDNを開くと画像のように中華フォントになってしまうことがある。
1FROM ubuntu:24.04
2RUN apt-get update && apt-get install -y \
3 pipx \
4 && \
5 apt-get clean && \
6 rm -rf /var/lib/apt/lists/*
7ENV PATH=/root/.local/bin:${PATH}
8RUN pipx install uv playwright && \
9 playwright install --with-deps && \
10 apt-get clean && \
11 rm -rf /var/lib/apt/lists/*
12RUN mkdir /test
13WORKDIR /test
14COPY . /test/
15# pytest-playwright をPythonプロジェクトの依存関係に含む
16RUN uv venv && uv pip install . && uv run playwright install
17CMD ["uv", "run", "pytest"]
この画像では例えば結
の糸へんや与
の字が日本語フォントっぽくないことが確認できると思う。これはPlaywrightの依存関係の定義にfonts-wqy-zenhei
が含まれていて、これが日本語フォントより優先されてしまうためこのような表示になってしまう。
使用されているフォントを確認する
Playwrightで実際にレンダリングで使われているフォント情報を取得するの記事とStackOverflowを参考にして、iframe
内の#container
で使われているフォントを取得すると以下のようになっていた。
1import json
2
3from playwright.sync_api import Page
4
5def print_font(page: Page):
6 # このiframeは遅延読み込みなので表示待ちをする
7 container = page.frame_locator("#frame_monitoring_screen_resolution_or_zoom_level_changes").locator("#container")
8 container.wait_for()
9 # CDPセッションを作成
10 client = page.context.new_cdp_session(page)
11 # iframeのdocumentのnodeIdを取得
12 root = client.send("DOM.getDocument", {"depth": 0})
13 iframe_id = client.send("DOM.querySelector", {"nodeId": root["root"]["nodeId"], "selector": ".sample-code-frame"})
14 iframe_desc = client.send("DOM.describeNode", {"nodeId": iframe_id["nodeId"]})
15 iframe_res = client.send(
16 "DOM.resolveNode", {"backendNodeId": iframe_desc["node"]["contentDocument"]["backendNodeId"]}
17 )
18 iframe = client.send("DOM.requestNode", {"objectId": iframe_res["object"]["objectId"]})
19 # #containerのnodeIdを取得
20 container_id = client.send("DOM.querySelector", {"nodeId": iframe["nodeId"], "selector": "#container"})
21 # フォント情報を取得
22 client.send("CSS.enable")
23 fonts = client.send("CSS.getPlatformFontsForNode", {"nodeId": container_id["nodeId"]})
24 print(json.dumps(fonts, ensure_ascii=False, indent=2))
1{
2 "fonts": [
3 {
4 "familyName": "WenQuanYi Zen Hei",
5 "postScriptName": "WenQuanYiZenHei",
6 "isCustomFont": false,
7 "glyphCount": 95
8 },
9 {
10 "familyName": "Liberation Sans",
11 "postScriptName": "LiberationSans",
12 "isCustomFont": false,
13 "glyphCount": 5
14 }
15 ]
16}
IPAフォントにする
IPAフォントにするには、単にfonts-wqy-zenhei
をアンインストールすればよい。結
の糸へんや与
の字が日本語の漢字になっていることが確認できる。Fontconfigの優先度調整を頑張ればアンインストールせずに済むかもしれないが、大抵アンインストールで対応してる印象。
1FROM ubuntu:24.04
2RUN apt-get update && apt-get install -y \
3 pipx \
4 && \
5 apt-get clean && \
6 rm -rf /var/lib/apt/lists/*
7ENV PATH=/root/.local/bin:${PATH}
8RUN pipx install uv playwright && \
9 playwright install --with-deps && \
10 # fonts-wqy-zenheiを削除する
11 apt-get purge -y fonts-wqy-zenhei && \
12 apt-get clean && \
13 rm -rf /var/lib/apt/lists/*
14RUN mkdir /test
15WORKDIR /test
16COPY . /test/
17# pytest-playwright をPythonプロジェクトの依存関係に含む
18RUN uv venv && uv pip install . && uv run playwright install
19CMD ["uv", "run", "pytest"]
1{
2 "fonts": [
3 {
4 "familyName": "IPAGothic",
5 "postScriptName": "IPAGothic",
6 "isCustomFont": false,
7 "glyphCount": 47
8 },
9 {
10 "familyName": "IPAPGothic",
11 "postScriptName": "IPAPGothic",
12 "isCustomFont": false,
13 "glyphCount": 48
14 },
15 {
16 "familyName": "Liberation Sans",
17 "postScriptName": "LiberationSans",
18 "isCustomFont": false,
19 "glyphCount": 6
20 }
21 ]
22}
Notoフォントにする
NotoフォントよりもIPAフォントの方が優先度が高いらしく、次の例のように単純にfonts-noto
をインストールしてもIPAフォントのままになってしまう。
1FROM ubuntu:24.04
2RUN apt-get update && apt-get install -y \
3 # fonts-notoを追加する
4 fonts-noto \
5 pipx \
6 && \
7 apt-get clean && \
8 rm -rf /var/lib/apt/lists/*
9ENV PATH=/root/.local/bin:${PATH}
10RUN pipx install uv playwright && \
11 playwright install --with-deps && \
12 # fonts-wqy-zenheiを削除する
13 apt-get purge -y fonts-wqy-zenhei && \
14 apt-get clean && \
15 rm -rf /var/lib/apt/lists/*
16RUN mkdir /test
17WORKDIR /test
18COPY . /test/
19# pytest-playwright をPythonプロジェクトの依存関係に含む
20RUN uv venv && uv pip install . && uv run playwright install
21CMD ["uv", "run", "pytest"]
確実にNotoフォントを適用したい場合は、Notoフォント以外のフォントをすべてアンインストールすればよい。Dockerなのでそれぐらい思い切ったことができるし、Notoフォントで消費している容量の削減にもなる。APTで範囲的にアンインストールするには、apt-patternsにあるように?name()
と正規表現を使う。先読みアサーションを使えば1個の正規表現で済むが、試したところ正規表現に(
を使えないようなので?and()
や?not()
を組み合わせた。
1FROM ubuntu:24.04
2RUN apt-get update && apt-get install -y \
3 # fonts-notoを追加する
4 fonts-noto \
5 pipx \
6 && \
7 apt-get clean && \
8 rm -rf /var/lib/apt/lists/*
9ENV PATH=/root/.local/bin:${PATH}
10RUN pipx install uv playwright && \
11 playwright install --with-deps && \
12 # fonts-noto*以外のfonts-*を削除する
13 apt-get purge -y '?and(?name(^fonts-),?not(?name(^fonts-noto)))' && \
14 apt-get clean && \
15 rm -rf /var/lib/apt/lists/*
16RUN mkdir /test
17WORKDIR /test
18COPY . /test/
19# pytest-playwright をPythonプロジェクトの依存関係に含む
20RUN uv venv && uv pip install . && uv run playwright install
21CMD ["uv", "run", "pytest"]
すると以下のようにNoto Sans CJK JPで表示できるようになる。
1{
2 "fonts": [
3 {
4 "familyName": "Noto Sans CJK JP",
5 "postScriptName": "NotoSansCJKjp-Regular",
6 "isCustomFont": false,
7 "glyphCount": 95
8 },
9 {
10 "familyName": "Noto Sans",
11 "postScriptName": "NotoSans-Regular",
12 "isCustomFont": false,
13 "glyphCount": 6
14 }
15 ]
16}