♨️

Material Symbols他、アイコンフォント形式のアイコンをFigmaで扱う方法

に公開

タイミーのプロダクトデザイナーの横田です。

サービスのUIアイコンの選定は重要でありながら、Figma等でアイコンをどのように扱えるかが影響します。今回は小ネタとして、アイコンフォントをFigmaで利用可能なsvgとして出力し、Figma Componentとして扱うTipsです。

UIアイコンを取り巻く悩みとしては、以下がよく聞かれます。

  • 特にGoogleのMaterial Symbolsは、ウェイトやスタイル(Fill, Optical Sizeなど)を細かく調整できる点が非常に魅力的です。
    • しかし、Material Symbolは個別のスタイルのFigmaを配布していません
    • Figma Communityで配布されているファイルは、特定のウェイトに対応していなかったり、使いたいグリフ(アイコン)が足りなかったりすることがあります。
  • Iconifyのようなプラグインは非常に便利ですが、Figmaコンポーネントとして一元管理しにくかったり、意図せず使ったフォントが実装と乖離したりと、悩ましい点もあります。

この課題は、これまでいくつかの会社で直面してきました。
そのたびに思い出して実行してきたのが今回の手法です。フォントファイルからFigmaで快適に扱えるアイコンコンポーネントを半自動で生成する手法をご紹介します。

全体の流れ

手順は大きく3ステップです。フォントをダウンロードし、PythonでSVGに分解、最後にFigmaでコンポーネント化します。

  1. フォントの準備:Variable Fontから特定のスタイルを切り出す
  2. 自動化の核心:Pythonで全グリフをSVGに変換する
  3. 仕上げとベストプラクティス:Figmaでコンポーネントライブラリを構築する

1 | フォントの準備

まず、GitHubからMaterial Symbolsフォントをダウンロードします。手に入るのは可変ウェイトなどに対応したVariable Fontです。
これをwoff2形式からttf形式へ各種ツールで変換してください。

このままではFigmaで扱いにくいため、特定のスタイルを持つフォントファイルを切り出します。ここで活躍するのがfonttoolsというライブラリです。このfonttoolsを2段階で活用するのが、今回の手法のポイントです。

まず1段階目として、ターミナルで以下のコマンドを実行します。ここでは例として、Weight=700(Bold)、Fill=1(塗りつぶし)のフォントを生成しています。

fonttools varLib.instancer MaterialSymbols.ttf wght=700 FILL=1 -o material-symbols-bold-filled.ttf

これで、特定のスタイルを持つ material-symbols-bold-filled.ttf が手に入りました。

2 | Pythonで全グリフをSVGに変換する

次に、このttfファイルから全てのアイコン(グリフ)を個別のSVGファイルとして抽出します。ここが自動化の肝です。

以下のPythonスクリプトを実行すると、svg_glyphsというディレクトリに、全てのグリフがSVGとして書き出されます。※ファイル名等は適宜変更してください。

from fontTools.ttLib import TTFont
from fontTools.pens.boundsPen import BoundsPen
from fontTools.pens.transformPen import TransformPen
from fontTools.pens.svgPathPen import SVGPathPen
import os

# TTFファイルを読み込む
font = TTFont('material-symbols-bold-filled.ttf')

# SVGファイルを保存するディレクトリを作成
output_dir = 'svg_glyphs'
os.makedirs(output_dir, exist_ok=True)

# フォント内の各グリフをSVGファイルに変換
for glyphName in font.getGlyphOrder():
    if not glyphName.startswith('.'): # .notdefのようなシステムグリフをスキップ
        glyph = font['glyf'][glyphName]

        # グリフのバウンディングボックスを計算
        bounds_pen = BoundsPen(font.getGlyphSet())
        glyph.draw(bounds_pen, font['glyf'])
        bbox = bounds_pen.bounds

        if bbox is None:
            print(f"Skipping glyph '{glyphName}' due to None bounding box")
            continue

        # グリフのパスを取得し、Y軸を反転
        path_pen = SVGPathPen(font.getGlyphSet())
        # フォント空間はY軸が上向きなので、SVG標準に合わせて反転させる
        transform_pen = TransformPen(path_pen, (1, 0, 0, -1, 0, font['head'].yMax))
        glyph.draw(transform_pen, font['glyf'])

        # SVGファイルの内容を生成
        # viewBoxはフォントのユニットサイズ(em square)に合わせる
        svg_content = f'''<svg xmlns="<http://www.w3.org/2000/svg>" viewBox="0 0 {font['head'].unitsPerEm} {font['head'].unitsPerEm}" fill="currentColor">
  <path d="{path_pen.getCommands()}"/>
</svg>
'''

        # SVGファイルを保存
        with open(os.path.join(output_dir, f'{glyphName}.svg'), 'w') as f:
            f.write(svg_content)

print("SVG generation complete.")

スクリプトを実行すると、checkbox.svghome.svgといったファイル名でSVGが大量に生成されます。Material Symbolsの場合は3000以上あります。

3 | Figmaでコンポーネントを構築する

最後のステップはFigmaでの作業です。ただコンポーネント化するだけでなく、管理しやすい構造にすることが重要です。

  1. SVGを一括インポート
    生成されたSVGファイルを全て選択し、Figmaのキャンバスにドラッグ&ドロップします。
  2. コンポーネント化
    インポートした全てのベクターを選択した状態で、Batch Create Components のようなプラグインを実行し、一括で個別のコンポーネントに変換します。
  3. Variantsとして統合
    作成された全コンポーネントを選択し、右サイドバーの「Combine as variants」をクリックします。これにより、3000以上のバリアントを持つ巨大なコンポーネントセットが完成します。これを Material Symbols のように命名しましょう。

グリフ管理とインスタンスを分離する

ここで一つ、重要なプラクティスを紹介します。先ほど作成した巨大なコンポーネントセットを直接デザインに使うのではなく、「グリフ(形状)を管理するコンポーネント」と「サイズや色を規定する表示用コンポーネント」を分離することを推奨します。

  • グリフ管理用コンポーネント (Material Symbols)
    • 3000以上のアイコン形状を持つ、バリアントの塊。
    • このコンポーネントの役割は「形状の管理」のみに特化させます。
  • 表示用コンポーネント (Icon / S, Icon / M など)
    • 実際にデザインで使用するコンポーネントです。
    • このコンポーネントの中に、グリフ管理用コンポーネントのインスタンスを配置します。
    • フレームサイズを24pxや32pxなどにバリエーションをもたせ、色のスタイルを適用します。

この構成にすることで、以下のようなメリットが生まれます。

  • メンテナンス性の向上: アイコンの色やサイズ体系を変更したくなった場合、表示用コンポーネントを修正するだけで済みます。3000以上のバリアントを一つひとつ修正する必要はありません。
  • 利用者の混乱を防ぐ: デザイナーは表示用コンポーネントを使うだけでよく、巨大なグリフ管理コンポーネントを直接触る必要がなくなります。

おわりに

fontToolsを使うアイデアは、昔英字のVariable Fontsをつくったときに得たものでした。
アイコンの整備は社内で一度整理してそれきりなので、いろんな会社で自分がこっそり15分で整備してきた。お悩みの方への解決につながればよいなと思います。

Discussion