イラレの合成フォントを Web 上で再現する

6 min read読了の目安(約5800字

はじめに

Web 上で合成フォント、使いたいですよね。英語と日本語の擬似的な混植であれば CSS の font-family でできなくもないですが、「欧文と和文の大きさを揃えたい…」「ひらがなだけ別の書体にしたい…」といった要望がどうしても出てきます。今回の記事ではそのあたりを力技で解決していきます。

準備

イラレ上で合成フォントを作成

今回は Adobe Fonts にある書体で合成フォントを作っていきます。まずは Adobe Illustrator 上で合成フォントを作ります。漢字、かな、欧文でそれぞれ書体を変えています。欧文は小さめなので、サイズを 118% に拡大しています。

Adobe Fonts で Web プロジェクトを作成

Adobe Fonts で Web プロジェクトを作成し、今回使用する書体を追加しておきます。

必要な処理

漢字やひらがな、英語、数字といった文字カテゴリーにそれぞれ CSS を当てることができれば、Web 上でも合成フォントで表現することが可能です。

こんな風に区分けをしたい
具体的には、このような HTML があったとして、

<p>ドイツから来たSweynheim</p>

こうなればいいということです。

<p><span class="katakana">ドイツ</span><span class="hiragana">から</span><span class="kanji"></span><span class="hiragana"></span><span class="latin">Sweynheim</span></p>

span 地獄を作る

HTML と JS はこんな感じです。上述の通り、文字カテゴリーごとに span タグで囲いまくっていきます。日本語/英語はデフォルトのフォントスタイルを付けたいので、jaenclass に付与していきます。記号や数字は zen_han_ の接頭辞を付けて全角と半角を区別します。

index.html
<!DOCTYPE html>
<html lang="ja" dir="ltr">

<head>
  <meta charset="utf-8">
  <title>demo</title>
  <script src="script.js"></script>
</head>

<body>
    <p id="text">
      国LINE国Word国character国type国123国456国$1,789円国「合成フォントの見本」国国1日2月3年4個5時6分7秒8人9件0度1丁目2番地3階4号グーテンベルクが活版印刷術を発明したのは1440年代後半といわれています。それから約20年後の1465年、その新しい技術はアルプスを越え、イタリアに伝わりました。ドイツから来たSweynheimとPannartzという二人がローマの北にあるSubiacoという村の修道院に滞在し、そこでイタリア最初の印刷物をつくったのです。
    </p>
</body>

</html>
script.js
document.addEventListener("DOMContentLoaded", (event) => {
  const TYPES = [
    { lang: "latin en", range: /[a-zA-Z]/g },
    { lang: "han_digit en", range: /^\d/g },
    { lang: "han_kigou en", range: /^[!-/:-@¥[-`{-~]*$/g },
    { lang: "kanji ja", range: /^\p{sc=Han}/gu },
    { lang: "hiragana ja", range: /^\p{sc=Hiragana}/gu },
    { lang: "katakana ja", range: /^\p{sc=Katakana}/gu },
    { lang: "zen_latin ja", range: /[a-zA-Z]/g },
    { lang: "zen_digit ja", range: /[0-9]/g },
    { lang: "zen_kigou ja", range: /[!-/ー:-@[-`{-~、-〜”’・]+/g },
  ];

  const text = document.getElementById("text").innerHTML;
  let new_text_inner = "";

  const chars = [...text];
  let text_array = [];
  let new_chunk = "";
  let lang = "";

  // 一文字ずつ走査していく
  chars.forEach((char, index) => {
    let current_lang = "";

    // 文字が TYPES のどれに当てはまるか
    for (const type of TYPES) {
      if (char.match(type.range)) {
        current_lang = type.lang;
        break;
      }
    }

    // ひとつ前の文字と同じカテゴリかどうか
    if (lang === current_lang) {
      new_chunk += char;
    } else {
      if (new_chunk !== "") {
        text_array.push({ lang: lang, chunk: new_chunk });
      }
      new_chunk = char;
      lang = current_lang;
    }

    // 最後の文字の場合
    if (index === chars.length - 1) {
      text_array.push({ lang: lang, chunk: new_chunk });
    }
  });

  for (const set of text_array) {
    if (set.lang) {
      new_text_inner +=
        "<span class='" + set.lang + "'>" + set.chunk + "</span>";
    } else {
      new_text_inner += set.chunk;
    }
  }

  document.getElementById("text").innerHTML = new_text_inner;
});

Chrome のデベロッパーツールで見てみると、span タグが勢いよく生成されていることがわかります。

ちなみに今回のスクリプトでは、簡略化のため p タグ中に HTML タグ(例えば astrong など)があるパターンを想定していません。そのようなケースでは、正規表現を使用してタグを迂回する必要があります。

各文字カテゴリーにフォントスタイルを設定する

Adobe Fonts の Web プロジェクトを HTML の head 内で読み込み、css を書いていきます。Adobe Fonts の kitId は各々入れてください。

index.html
<!DOCTYPE html>
<html lang="ja" dir="ltr">

<head>
  <meta charset="utf-8">
  <title>demo</title>
  <link rel="stylesheet" href="style.css">
  <script src="script.js"></script>
  <script>
    (function(d) {
      var config = {
        kitId: '',  // YOUR KIT ID HERE
        scriptTimeout: 3000,
        async: true
      },
      h=d.documentElement,t=setTimeout(function(){h.className=h.className.replace(/\bwf-loading\b/g,"")+" wf-inactive";},config.scriptTimeout),tk=d.createElement("script"),f=false,s=d.getElementsByTagName("script")[0],a;h.className+=" wf-loading";tk.src='https://use.typekit.net/'+config.kitId+'.js';tk.async=true;tk.onload=tk.onreadystatechange=function(){a=this.readyState;if(f||a&&a!="complete"&&a!="loaded")return;f=true;clearTimeout(t);try{Typekit.load(config)}catch(e){}};s.parentNode.insertBefore(tk,s)
    })(document);
  </script>
</head>

<body>
    <p id="text">
      国LINE国Word国character国type国123国456国$1,789円国「合成フォントの見本」国国1日2月3年4個5時6分7秒8人9件0度1丁目2番地3階4号グーテンベルクが活版印刷術を発明したのは1440年代後半といわれています。それから約20年後の1465年、その新しい技術はアルプスを越え、イタリアに伝わりました。ドイツから来たSweynheimとPannartzという二人がローマの北にあるSubiacoという村の修道院に滞在し、そこでイタリア最初の印刷物をつくったのです。
    </p>
</body>

</html>
style.css
* {
  margin: 0;
  padding: 0;
}

body {
  background-color: #515252;
  color: #ffffff;
  padding: 15px;
}

/* デフォルトのフォントスタイルを設定 */
p {
  -webkit-font-smoothing: antialiased;
  font-size: 30px;
  line-height: 46px;
  font-family: a-otf-ryumin-pr6n, serif; 
  font-style: normal;
  font-weight: 300;
}

/* 日本語のデフォルトのフォントスタイルを設定 */
.ja {
  font-family: a-otf-ryumin-pr6n, serif; 
  font-style: normal;
  font-weight: 300;
}

/* 英語のデフォルトのフォントスタイルを設定 */
.en {
  font-family: garamond-premier-pro-display, serif;
  font-style: normal;
  font-weight: 300;
  font-size: 118%;
}

/* 個別にフォントスタイルを設定 */
.hiragana, .katakana {
  font-family: yu-mincho-36p-kana, sans-serif;
  font-style: normal;
  font-weight: 400;
  font-size: 99%;
}

これで完成です。

先ほどの合成フォントパネルと見比べてみましょう。かなりの再現度であることがわかります。