Custom Fontは、デベロッパーがデフォルトのシステムフォントを置き換えるためにモバイルアプリケーションに追加するフォントファイル(TTF、OTF、WOFF2)です。カスタムフォントは、ユニークなビジュアルスタイルの作成、ブランドの一貫性の維持、さまざまな言語での可読性の向上に使用されます。Apple Fontsによると、カスタムフォントはすべてのAppleプラットフォームでサポートされており、AndroidはFont Familyメカニズムを提供して読み込みを簡素化しています。適切なフォント統合は、タイポグラフィとアプリケーションの全体的な印象に重要な影響を与えます。
重要ポイント
Custom Font(カスタムフォント)は、オペレーティングシステムのデフォルトフォントセットに含まれない書体ファイルです。デベロッパーは、ブランドに一貫した独自のタイポグラフィを実現するために、このようなフォントをプロジェクトに追加します。カスタムフォントは、有料の商用書体の場合もあれば、Inter、Montserrat、カスタムバージョンのRobotoなどの無料のオープンソースフォントの場合もあります。
カスタムフォントの典型的なユースケースには、ブランドアプリのロゴや見出し、特定のタイポグラフィ要件を持つ読書アプリ、テーマフォントを使用したゲーム、システムフォントが目的のグリフをサポートしていない非ラテン言語のアプリケーションなどがあります。Google Fontsによると、トップ100アプリの60%以上が視覚的な差別化のためにフォントをカスタマイズしています。
システムフォント(iOSのSan Francisco、AndroidのRoboto)はインターフェース向けに最適化されていますが、ブランドのタイポグラフィには適していません。カスタムフォントはブランド認知を強化し、特殊文字(アイコンフォント)を含めることができ、特定のユーザーにとっての可読性を向上させます。ただし、異なるフォントを過剰に使用するとユーザー体験が低下するため、アプリケーションあたり2〜3ファミリー以下にすることをお勧めします。
モバイルプラットフォームはいくつかのフォント形式をサポートしています。TrueType(TTF)は最も一般的な形式で、iOSとAndroidのすべてのバージョンと互換性があります。OpenType(OTF)はTTFの拡張版で、合字、代替グリフ、OpenType機能をサポートしています。どちらの形式も.ttfと.otfの拡張子を持ち、モバイルプラットフォームで同じように動作します。
WOFF2(Web Open Font Format 2)はウェブ向けの圧縮形式で、Androidバージョン10以降でサポートされています。WOFF2はTTFと比較して30〜50%の圧縮率を提供します。iOSでは、WOFF2はSafariを介してサポートされますが、ネイティブアプリケーションではTTF/OTFへの変換が必要です。バリアブルフォント(Variable Fonts)は、すべてのウェイトを1つのファイルに格納する最新の形式です。
| 形式 | iOS | Android | 圧縮 | 特徴 |
|---|---|---|---|---|
| TTF | 対応 | 対応 | なし | 標準形式、幅広い互換性 |
| OTF | 対応 | 対応 | なし | OpenType機能、合字、代替グリフ |
| WOFF2 | Safari経由 | API 29+ | 30〜50% | 圧縮済み、APKサイズを削減 |
| Variable | iOS 11+ | API 29+ | 高い | 全ウェイトを1ファイルに |
モバイル開発では、主要な形式としてOTFを使用することをお勧めします。TTFと同じサイズでOpenType機能をサポートします。APKの容量を節約するには、woff2による圧縮またはオンデマンドのフォント読み込みを使用します。
iOSでカスタムフォントを統合するプロセスは、ファイルをプロジェクトバンドルに追加し、Info.plistに登録するという2つのステップで構成されます。フォントファイルはプロジェクトディレクトリ(通常はResources/Fonts)に配置され、ターゲットに含まれます。Info.plistには、拡張子を含むフォントファイル名を指定してUIAppFonts配列(Fonts provided by application)が追加されます。
登録後、フォントはPostScript名を使用してUIFont(name:size:)でアクセス可能になります。PostScript名はUIFont.familyNamesとUIFont.fontNames(forFamilyName:)で確認できます。名前が間違っている場合、UIFont(name:size:)はnilを返します。デバッグのためには、初回起動時に登録されたすべてのフォントを画面に表示することをお勧めします。
SwiftでiOSプロジェクトにMontserratフォントを統合する全サイクルを見てみましょう。Montserrat-Regular.ttfファイルがプロジェクトに追加され、Info.plistで宣言され、UIFontを介して読み込まれ、UILabelに適用されます。各ウェイト(regular、bold、italic)には個別のファイルとInfo.plistへの個別のエントリが必要です。
// 1. Info.plist: UIAppFonts → "Montserrat-Regular.ttf"
// 2. コードでフォントを読み込む
guard let customFont = UIFont(name: "Montserrat-Regular", size: 16) else {
// システムフォントにフォールバック
label.font = UIFont.systemFont(ofSize: 16)
return
}
label.font = customFont
// 3. NSAttributedStringで使用
let attributes = [NSAttributedString.Key.font: customFont]
let attributed = NSAttributedString(string: "Text", attributes: attributes)
フォントが読み込まれない場合(UIFontがnilを返す)の処理は必須です。アプリケーションをクラッシュさせる代わりに、システムフォントをフォールバックとして使用します。これは、ネットワークから読み込まれたフォントやオプショナルモジュールに追加されたフォントで特に重要です。
オンデマンドでダウンロードされるフォントには、CTFontManagerRegisterGraphicsFontが使用されます。このメソッドはメモリ内のデータ(Data)からフォントを登録し、UIFontで使用可能にします。使用後は、CTFontManagerUnregisterGraphicsFontでフォントの登録を解除できます。動的読み込みは、すべてを即座に必要としない大規模なフォントセットを持つアプリケーションに役立ちます。
Androidでは、カスタムフォントはres/fontリソースシステムを介して追加されます。TTFまたはOTFファイルはres/font/に配置され、その後、ウェイトをグループ化するためのXML Font Familyリソースが作成されます。Android 8.0(API 26)以降、これが唯一の推奨方法です。古いバージョンでは、assetsとTypeface.createFromAssetが使用されます。
XML Font Familyは、ウェイト(regular、bold、italic)とフォントファイルの間のマッピングを記述します。XMLレイアウトでは、属性android:fontFamily="@font/my_font"が、対応するスタイルでsetTypefaceが呼び出されたときに自動的に正しいファイルを選択します。これによりタイポグラフィが簡素化されます。テーマでファミリーを指定するだけで、setTypeface(textView, Typeface.BOLD)が呼び出されたときにAndroidが自動的にboldバージョンを選択します。
res/font/my_font.xmlにXMLファイルを作成し、異なるウェイトのすべてのフォントファイルをリストします。各要素にはfontStyle(normal/italic)とfontWeight(100〜900)の属性があります。次に、レイアウトでandroid:fontFamily="@font/my_font"を指定します。textStyle="bold"が使用されると、Androidは自動的にfontWeight 700のファイルを選択します。
<!-- res/font/my_font.xml -->
<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:app="http://schemas.android.com/apk/res-auto">
<font
android:fontStyle="normal"
android:fontWeight="400"
app:font="@font/my_font_regular" />
<font
android:fontStyle="normal"
android:fontWeight="700"
app:font="@font/my_font_bold" />
</font-family>
Font Familyを使用する場合、リソースアプローチは自動的にフォントをキャッシュし、正しいウェイトを選択します。必要なウェイトがファミリーにない場合、Androidは最も近い利用可能なウェイトから合成します。フォントを正確に制御するには、明示的なファイル参照を指定してTypeface.create()を使用します。
クロスプラットフォームフレームワークでは、フォント統合が統一されています。Flutterはpubspec.yamlを使用してフォントを宣言します。ファイルはプロジェクトのfonts/フォルダに配置され、ファミリーとウェイトを指定してfontsセクションにリストされます。その後、フォントはTextStyle(fontFamily: 'Montserrat')またはアプリのテーマを介して適用されます。FlutterはTTFとOTFをサポートしています。
React Nativeは2つのアプローチを使用します。ネイティブ(Info.plistとres/font経由)またはreact-native-vector-iconsや@expo-google-fontsなどのライブラリを介する方法です。Expoはプロセスを簡素化します。フォントはexpo-fontを介して読み込まれます:Font.loadAsync({ 'Montserrat': require('./assets/fonts/Montserrat.ttf') })。React Navigationとテーマを使用すると、フォントをグローバルに設定できます。
pubspec.yamlでのフォント宣言とMaterialAppテーマでの適用。Montserrat-Regular.ttfとMontserrat-Bold.ttfのファイルはfonts/に配置されます。宣言後、フォントはアプリケーション全体でTextStyleを介してアクセス可能になります。fontWeight: FontWeight.boldが指定されると、Flutterは自動的にboldファイルを使用します。
// pubspec.yaml
flutter:
fonts:
- family: Montserrat
fonts:
- asset: fonts/Montserrat-Regular.ttf
- asset: fonts/Montserrat-Bold.ttf
weight: 700
// テーマでの使用
MaterialApp(
theme: ThemeData(
textTheme: TextTheme(
headlineLarge: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.bold,
fontSize: 28
)
)
)
)
Flutterが指定されたパスでフォントを見つけられない場合、アプリケーションはエラーなしでシステムのフォールバックフォントを使用します。デバッグのためには、MaterialAppでcheckConsistencyを有効にします。これによりフォントの可用性がチェックされ、フォントがない場合にコンソールに警告が表示されます。
APKとIPAのサイズは、含まれるフォントの数に直接依存します。1つのTTFファイルは、ラテン文字セットで50〜500KB、キリル文字、CJK文字、その他の拡張セットをサポートするフォントで最大2〜5MBになります。10個のフォントはアプリケーションのサイズに10〜20MB追加する可能性があり、モバイルダウンロードにとって重要です。
最適化には、サブセッティング(フォントファイルから未使用の文字を削除すること)を使用します。glyphhanger、fonttools(pyftsubset)、Google Webfont Optimizerなどのツールは、必要なグリフ(ラテン文字+キリル文字+数字+句読点)のみを含むフォントバージョンを作成します。これによりサイズが50〜80%削減されます。iOSでは、初回起動時に必要のないフォントにオンデマンドリソースを使用できます。
バリアブルフォントは、ThinからBlack、CondensedからExpandedまでのすべてのウェイトを含む単一のファイルです。1つのバリアブルフォントで、異なるウェイトの10〜20個の個別ファイルを置き換えることができます。このようなファイルのサイズは、約1〜2個の静的ファイルに相当します。対応状況:iOS 11+、Android 10+、Flutter(FontVariation経由)、React Native(カスタムライブラリ経由)。
フォントサイズを30〜50%削減するにはWOFF2を使用します。API 29のAndroidでは、WOFF2を直接使用できます。iOSでは、登録前にWOFF2をTTFに変換する必要があります。オンボーディング時や特定の画面でのみ使用されるフォントは、オンデマンドリソース(iOS)またはDynamic Feature(Android)を介して読み込む必要があります。これらはベースAPKには含まれません。
カスタムフォントは、読み込み時間とメモリの2つの方法でパフォーマンスに影響を与えます。最初のアクセス時に、システムはディスクからファイルを読み取り、フォントテーブルを解析し、レンダリング用の内部構造を作成します。1MBのフォントの場合、これには20〜50msかかります。初回読み込み後のキャッシュにより、後続のアクセス時の遅延が解消されます。
メモリ:読み込まれた各フォントはプロセスキャッシュに保存されます。システムフォントはプリロードされています。カスタムフォントは最初の使用時に読み込まれます。メモリ内では、解析された構造(cmap、glyf、head、hmtxテーブル)のため、フォントはディスク上の約2〜3倍の容量を占有します。平均サイズの5つのカスタムフォント(合計3MB)には、約6〜9MBのRAMが必要です。
カスタムフォントはアプリケーションあたり2〜3ファミリーに制限します。複数のウェイトを置き換えるにはバリアブルフォントを使用します。UI要素(ボタン、ラベル、リスト)にはシステムフォントを適用し、アクセントタイポグラフィ(見出し、バナー)にのみカスタムフォントを使用します。AndroidではMapを介してTypefaceをキャッシュし、iOSでは静的変数を介してUIFontをキャッシュします。
object FontCache {
private val cache = mutableMapOf<String, Typeface>()
fun get(context: Context, fontId: Int): Typeface {
return cache.getOrPut(fontId.toString()) {
ResourcesCompat.getFont(context, fontId)
}
}
}
// RecyclerViewでの使用
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.textView.typeface = FontCache.get(context, R.font.montserrat_regular)
}
onBindViewHolderでのTypefaceの読み込みは、キャッシュがある場合にのみ許容されます。キャッシュがない場合、createFromAssetが呼び出されるたびに新しいオブジェクトが作成され、ディスクからファイルが読み取られます。RecyclerViewのスクロール中に、これにより顕著な遅延が発生します。キャッシュはフォントが一度読み込まれて再利用されるため、問題を解決します。
よくある質問
OTFがモバイルアプリケーションに最適な選択です。TTFと同じサイズでOpenType機能(合字、代替グリフ)をサポートします。容量を節約するには、サブセッティングを施したバリアブルフォント(TTXまたはOTF)を使用します。WOFF2はAndroid 10+にのみ適しており、ネイティブアプリケーションのiOSではサポートされていません。
はい。Google Fontsは商用利用向けにOFL(Open Font License)の下でフォントを提供しています。フォントはfonts.google.comからダウンロードしてプロジェクトに追加できます。AndroidはGoogle Play Servicesを介してダウンロード可能フォントをサポートしており、フォントファイルをAPKに含めずに初回使用時に読み込むことができます。
最も一般的な原因:ファイルがターゲットに追加されていない(iOS)、Info.plistで宣言されていない(iOS)、ファイルがres/fontにない(Android)、PostScript名が間違っている、ファイルが破損している。iOSでの診断には、コンソールにUIFont.familyNamesを出力します。Androidでは、FontLoaderを使用してassetsからのフォント読み込みをデバッグします。
サブセッティング(pyftsubset)を使用して未使用の文字を削除します。サイズが50〜80%削減されます。10個の個別ファイルの代わりにバリアブルフォントを使用します。Android 10+にはWOFF2圧縮を使用します。ProGuardを設定してフォントパスを難読化します。iOSにはオンデマンドリソースを使用します。
2〜3ファミリー(異なるウェイトを含む)に制限することをお勧めします。各ファミリーはアプリケーションのサイズに200KB〜3MB追加します。システムフォントはアプリに負荷をかけないため、UI要素にはシステムフォントを使用し、見出しやアクセントブロックにはカスタムフォントを残します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。