😎

AndroidのTypographyと格闘した話

2024/12/20に公開

本記事は株式会社ココナラ Advent Calendar 2024 21日目の記事です。
こんにちは。株式会社ココナラアプリ開発グループ Androidチームの藤永です。

大掃除の季節ですね。
ココナラのAndroidアプリにも過去の負債が色々と存在しており、様々な機能開発と並行して随時お掃除を進めています。

ココナラでは最近新しいデザインシステムに切り替える動きがあり、Typographyの刷新にあたって改めてAndroidのTypographyについて調査をしたので、今回はその内容をかいつまんでご紹介します。

Typographyとは

Typographyとは、HeadlineやBodyなどのように、文章の見た目を決めるための設定です。
文字サイズや行間などの様々な属性値を、サービス内やアプリ内であらかじめ定義することで統一的な見た目を提供できます。

ココナラAndroidアプリのデザイン実装のベースはMaterial 2であり、標準で定義されているTypographyは以下のURLで確認できます。
https://m2.material.io/design/typography/the-type-system.html#type-scale

Material 2のTypography

Line Heightについて

ココナラのデザインシステムの定義はFigmaで作成されています。
また、AndroidでのTypographyはTextStyleというクラスで表現されます。

問題となるのは行の高さを表現するLine Heightという値です。これはデザインツールのLine HeightとAndroidアプリのLine Heightが、それぞれのテキストのバウンディングボックス(以下bbox)へ与える影響が異なることに起因しています。

FigmaのLine Height

FigmaにおけるLine Heightは、単純に1行のテキストを内包するbboxの高さに一致します。
極端な例ですが、テキストサイズ14px、Line Height 8pxと定義した場合、以下のようになります。

Figmaのbbox

Android (Jetpack Compose) のLine Height

AndroidアプリにおけるLine HeightはBaseline間の距離であり、テキストのbboxの高さとは一致しません。
先ほどと同様に、テキストサイズ14px、Line Height 8pxと定義した場合、以下のようになります。
(フォント自体や文字の太さ等は揃えていませんので、文字自体の見た目の差分は無視してください)

Androidのbbox

Androidのテキストのbboxは、内包するテキストが収まるように自動的に調節されます。基本的にはフォントが持つAscentとDescentの範囲を内包するように設定され、高さが大きい文字列であっても見切れないように更に追加でpaddingが自動的に確保されるようになっています。

フォントとbbox

何が問題になるのか

先ほどのテキストが2つのコンポーネントの間に存在し、上下に8dpの余白が設定されているケースを考えます。
コンポーネント間の余白は、多くの場合、bboxの上下辺を起点として適用されるため、見た目に大きな差が生まれます。

Figmaのmargin反映
Androidのmargin反映

一方で、bbox内の複数行の見た目は以下のように一致します。このことから、問題となるのは主に1行目上部と末尾行下部の余白であることがわかります。

Figmaのmargin反映

自動設定されるpaddingの存在によって、AndroidとFigmaとの間では見た目の齟齬が生まれやすいです。余分なpaddingを削減するための属性値として、includeFontPaddingというものがあります。

includeFontPaddingとは

Androidの初期から存在する属性値で、デフォルトはtrueです。falseに設定することで前述のpaddingを削減することができます。

ただし、Typographyとは別でコンポーネントがもつ属性値のため、テキストを配置するたびに毎回この設定を記述する必要がありました。

Jetpack Composeではv1.2.0から、下位互換用のAPIとしてincludeFontPaddingが導入されました。デフォルト値はtrueで、Typographyごとに設定することができます。また、falseに設定すると、Line Heightをどのように扱うかを定義するLineHeightStyleクラスと組み合わせて、より細かい制御をできるようになりました。

Compose UI v1.6.0-alpha01以降では、デフォルト値がfalseへ変更となりました。

実際に使用して比較すると英数字においては効果があるものの、日本語文字列においてはあまり効果がありませんでした。
includeFontPadding比較

ただし、実機で動作を確認したところ、Android 8までは効果があることがわかりました。この点は深堀りしていませんが、Android 9でフォールバックフォントの扱いが変わったためではないかと推測しています。
また、英数字においても結局のところAscent-Descent分の高さが確保される点は変わりません。

残るギャップについて

結局、(調査が足りていないという可能性はあるものの)includeFontPaddingによって余分なpaddingを削減するように設定しても、Figmaと同じ見た目を再現することはできないという結論に至りました。

デザインと実機の間のギャップを埋めるための方針として、大きく以下の3つが考えられます。

  • デザインのTypography定義をAndroidで完全再現可能なものに更新する
  • ギャップを許容する
  • Figmaの見た目に合うように、実装箇所ごとにmargin、padding、offset等をその都度調整する

デザイナさんとも相談し、実現したいデザインと工数を鑑みて原則(2)で共通コンポーネントや重要な部分については(3)を検討する方針となりました。

まとめ

今回は、AndroidのTypographyについて、特にデザインツールとAndroidアプリの見た目の差が生じる問題について解説しました。

本当のところは「Android Viewだとまた別のパラメータもあって…」や「OSバージョンによってはこういう見た目になって…」などもあるのですが、今回は割愛しました。

AndroidアプリのTypographyについてはつい先日(2024/12/11)にリリースされた1.8.0-alpha07で新しいLineHeightStyle.Modeが登場するなど、直近でも進化が続いています。今後も動向を注視し、知見を深めていきたいと思います。

参考URL

最後に

明日は@coco-ichiさんによる、 [2024年版]Baseline機能振り返り です。

ココナラでは積極的にエンジニアを採用しています。

採用情報はこちら。
https://coconala.co.jp/recruit/engineer/

カジュアル面談希望の方はこちら。
https://open.talentio.com/r/1/c/coconala/pages/70417

Discussion