CSSで、日本語と英字のフォントの大きさをそろえる方法

​​CSS​Playwright,フォント,日本語組版

英字は英字フォント、日本語は日本語フォントで表示すると、同じ font-size でも英字の小文字が日本語より小さく見えることがあります。CSS の font-size-adjust を使うと、小文字の x の高さ(x ハイト)が文字サイズの決まった割合になるように、フォントごとに表示の大きさを変えられます。ただし Chromium では、font-family に英字フォントと日本語フォントを並べただけの書き方では、英字と日本語の大きさの差は縮まりませんでした。

補足

検証環境は Ubuntu 24.04、Node.js 22.23.4、Playwright 1.63.0、Chromium 153 です。フォントは Noto Serif CJK JP と Noto Sans CJK JP(日本語)、Liberation Serif、Liberation Sans、DejaVu Sans(英字)で、どれも検証環境にあるフォントを local() やフォント名で使いました。Web フォント(url() で読み込むフォント)、Firefox と Safari、Windows や macOS に入っているフォントでは試していません。各ブラウザーの対応バージョンは、互換性データ(@mdn/browser-compat-data 8.1.8)の値です。

フォントによって、x ハイトの割合が違う

CSS Fonts 5 の仕様では、font-size-adjust は「指定した寸法 ÷ 文字サイズ」の値をそろえるプロパティです。寸法を省略すると ex-height(x ハイト)が使われます。

font-size-adjust に from-font を書くと、その要素で最初に使えるフォントの値(数値)が計算値になります。検証環境で、フォントを1つだけ指定した要素の計算値を読むと、次のようになりました。

フォント x ハイトの割合(ex-height) 大文字の高さの割合(cap-height)
Noto Serif CJK JP 0.514 0.729
Noto Sans CJK JP 0.543 0.733
Liberation Serif 0.459 0.655
Liberation Sans 0.528 0.688
DejaVu Sans 0.547 0.729

明朝体の Noto Serif CJK JP に、英字の Liberation Serif を組み合わせると、英字の小文字の高さは日本語フォントの x ハイトの約89%(0.459 ÷ 0.514)になります。この差を font-size-adjust で埋めます。

英字を別の要素にして、日本語フォントの値を継承させる

検証環境でいちばん素直に効いたのは、段落の主なフォントを日本語フォントにして、英字だけを別の要素で英字フォントにする書き方です。

css
body {
  font-family: "Noto Serif CJK JP", serif;
  font-size-adjust: from-font;
}

.en {
  font-family: "Liberation Serif", serif;
}
html
<p>日本語と<span class="en">Typography</span>の文字</p>

検証環境では、body の計算値は 0.514(Noto Serif CJK JP の値)になり、.en にもこの数値が継承されました。

文字サイズ 40px で幅を測りました。日本語の部分は、「日本語の文字」の6文字で測りました。Typography は 192.72px から 215.75px に広がり、日本語の部分は 240.00px のままでした。仕様の計算式は「調整後の大きさ =(指定した値 ÷ そのフォントの値)× 文字サイズ」です。英字フォントは 0.514 ÷ 0.459 で約1.12倍に拡大され、日本語フォントは自分の値と同じなので1倍のままです。

2つの段落を縦に並べた画面。どちらも「日本語とTypographyの文字」で、Typography の部分だけ英字フォント。上の「指定なし」では、Typography の小文字の上端が、ピンクの破線より下にある。下の「親要素に font-size-adjust: from-font を書いた場合」では、小文字の上端がピンクの破線にそろい、Typography の幅も広がっている
ピンクの破線は、日本語フォント(Noto Serif CJK JP)の x ハイトの高さ。下の段では、英字の小文字がこの線にそろう

body に from-font を書く代わりに、.en { font-size-adjust: 0.514; } と数値を直接書いても、同じ 215.75px になりました。

font-size-adjust で変わるのは、表示に使う大きさだけです。検証環境では、拡大された .en の font-size の計算値は 40px のままで、.en の中に置いた幅 1em の箱も 40px のままでした。仕様にも、子要素に継承されるのは font-size-adjust の影響を受けない font-size の計算値で、font-size-adjust は em の大きさには影響しないと書かれています。

font-family に並べただけでは、日本語も一緒に拡大される

次は、英字フォントを先に、日本語フォントを後に font-family に並べた場合です。

css
p {
  font-family: "Liberation Serif", "Noto Serif CJK JP", serif;
  font-size-adjust: 0.514;
}

仕様では、使われるフォントごとに、そのフォントの値で大きさを計算します。0.514 は日本語フォントの値なので、仕様の計算では、日本語フォントは1倍のままです。ところが検証環境の Chromium 153 では、英字の Typography が 192.72px から 215.75px に、日本語の部分も 240.00px から 268.69px に広がりました。どちらも約1.12倍で、日本語フォントにも、先頭の英字フォントの倍率がそのまま掛かっています。

この書き方で font-size-adjust: from-font にすると、計算値は先頭の Liberation Serif の値(0.459)になり、英字も日本語も大きさは変わりませんでした。先頭を DejaVu Sans に替えて 0.514 を指定すると、英字も日本語も約0.94倍に縮みました。

Chromium で英字と日本語の大きさの比を変えたいときは、上のように要素を分けるか、次に説明する、unicode-range で @font-face を分ける方法を使います。

unicode-range で分けた @font-face なら、フォントごとに調整される

1つのファミリー名の中で、unicode-range で英字の範囲と日本語の範囲を別のフォントに割り当てると、Chromium 153 でもフォントごとに大きさが計算されました。

css
@font-face {
  font-family: "Mix";
  src: local("Liberation Serif");
  unicode-range: U+0000-00FF;
}

@font-face {
  font-family: "Mix";
  src: local("Noto Serif CJK JP");
  unicode-range: U+3000-9FFF;
}

p {
  font-family: "Mix";
  font-size-adjust: 0.514;
}

この範囲は、検証に使った文字(英字と、ひらがな・漢字)が収まる範囲の例です。全角の丸かっこ()や ?!、全角英数字など、範囲に入らない文字には、この2つのフォントは使われません(CSS Fonts 4 の仕様の unicode-range の節)。使う文字に合わせて範囲を決めます。

40px の段落で値を変えて測った結果です。

font-size-adjust Typography の幅 「日本語の文字」の幅
none 192.72px 240.00px
0.514 215.75px 240.00px
0.6 251.81px 280.14px
from-font 192.72px 214.23px

0.6 のとき、英字は約1.31倍(0.6 ÷ 0.459)、日本語は約1.17倍(0.6 ÷ 0.514)になっていて、それぞれのフォントの値で計算されているのが分かります。

この書き方では、from-font を使わず、日本語フォントの値を数値で書きます。from-font の計算値は Liberation Serif の値(0.459)になり、英字はそのままで、日本語が縮みました。半角スペースが英字フォントの範囲(U+0000-00FF)に入っているので、英字フォントが「最初に使えるフォント」になるためです。CSS Fonts 4 の仕様では、最初に使えるフォントは、font-family に並べたフォントのうち、unicode-range で半角スペース(U+0020)が外されていない最初のフォントと決められています。

注意

font-size-adjust を書いた要素やその子要素で、font: 16px/1.5 serif のような font の一括指定を使うと、font-size-adjust は初期値の none に戻ります(CSS Fonts 4 の仕様の font の節)。検証環境でも、親に 0.514 を書き、子に font の一括指定を書くと、子の計算値は none でした。子では font-size と font-family を個別に書くか、一括指定のあとに font-size-adjust: inherit; を書きます。

x ハイトと大文字の高さのどちらでそろえるか

font-size-adjust: cap-height 0.729 のように書くと、x ハイトの代わりに大文字の高さでそろえます。0.729 は Noto Serif CJK JP の値です。英字を別の要素に分けた書き方で測ると、x ハイトでそろえたときの Typography が 215.75px、大文字の高さでそろえたときが 214.48px で、Liberation Serif と Noto Serif CJK JP の組み合わせでは、ほとんど差がありませんでした。

組み合わせによっては差が出ます。上の表の値で計算すると、Liberation Sans を Noto Sans CJK JP に合わせる倍率は、x ハイトなら約1.03倍(0.543 ÷ 0.528)、大文字の高さなら約1.07倍(0.733 ÷ 0.688)です。小文字の高さをそろえたいなら ex-height、大文字の高さをそろえたいなら cap-height を使います。

漢字の「水」の幅や高さで合わせる ic-width と ic-height もあります。検証環境では、日本語フォントでも英字フォントでも、from-font の値はどれも1でした。どのフォントも値が1なので、倍率は1のままです。実際に ic-height 1 を指定しても、英字と日本語のどちらの幅も変わりませんでした。英字と日本語の大きさをそろえる目的には、ex-height か cap-height を使います。

@font-face の size-adjust で、英字フォントだけを倍率で拡大する方法もあります。倍率の 112% は、0.514 ÷ 0.459(約1.12)から決めました。

css
@font-face {
  font-family: "Latin Serif";
  src: local("Liberation Serif");
  size-adjust: 112%;
}

p {
  font-family: "Latin Serif", "Noto Serif CJK JP", serif;
}

検証環境では、font-family に日本語フォントと並べたこの書き方でも、Typography は 192.72px から 215.83px に広がり、日本語の部分は 240.00px のままでした。ただし仕様では、font-size-adjust は size-adjust のあとに適用されるので、両方を書くと size-adjust は効いていないように見えるとされています。どちらか一方を使います。

ブラウザーの対応

互換性データでの対応状況は次のとおりです。

ブラウザー 数値1つ(font-size-adjust: 0.514) 寸法の指定(cap-height 0.729 など) from-font
Chrome・Edge(Android の Chrome を含む) 127 から 127 から 127 から
Firefox(Android を含む) 3 から(Android は 4 から) 92 から 118 から
Safari(iOS を含む) 16.4 から 17 から 17 から

from-font や寸法の指定を Chrome・Firefox・Safari のどれでも使えるのは、Chrome 127、Firefox 118、Safari 17 からです。数値を1つ書く形なら、Safari 16.4 から使えます。

​Posted by 86