プラットフォーム事業本部のフロントエンドグループ(以降FEG)で技術支援をしているCTO室兼VPoE室の大村です。
今回は、FEGで構築しているデザインシステム「Turtle」のタイポグラフィーについての試行錯誤をご紹介します。
※Turtleは常にアップデートしているので記事公開時と実装は異なる場合がございます。
デザイントークンの簡単な説明
デザイントークンとは、デザインシステムにおける見た目(色、タイポグラフィー、余白など)において、あるパターンを取り出したものを表します。
例えば以下のようなものです。
- color.blue600というデザイントークンは #2A7E9Fを表します
- color.primaryというデザイントークンはcolor.blue600を表します
- color.primaryButtonというデザイントークンはcolor.primaryを表します
この例の場合、デザイントークン同士に以下のような関係があることにが分かります。
- color.primaryButton → color.primary → color.blue600 → #2A7E9F
すると、color.blue600を#166B8Fへ変えた場合に、その変更を多くのプロダクトに一括で反映できます。
このように、目的にあったデザイントークンを設計することで、変更に強いデザインシステムをつくることができ、保守観点で大きなメリットがあります。
私たちのデザインシステムでは、Adobe Spectrumにある Global Token、 Alias Token という概念を取り入れています。詳細は下記を参照していただければと思いますが、上記の例では、color.blue600をGlobal Token、color.primaryをAlias Tokenとして扱います。 https://spectrum.adobe.com/page/design-tokens/#Design-token-types
私たちが作るタイポグラフィー
私たちが作るデザインシステム「Turtle」では、1~15の段階のフォントサイズの情報を持ったGlobal Tokenを定義してます。
一番大きなサイズが3.247rem(51.96px相当)で、もっとも小さなサイズが0.624rem(9.99px相当)となっています。
pxで小数点以下の数が出ると設計時には厄介な印象を持つ人が多いかもしれません。ですが、さまざまなデバイスで実際にレンダリングされる際には、サブピクセルレンダリングによって小数点のある数だとしてもアンチエイリアスによって最適に処理されるため、小数点以下の数を気にしていません。
それよりも、レイアウトの設計時にバランスの良いGlobal Token全体のリズミカルなスケールの調和を大切にしています。
Global Token の定義
前述した内容はfont-size
のみとなるため、TurtleではGlobal Tokenとして扱っています。
Global Tokenはトークンがどのようにして使われて欲しいかの意図を持ちません。そのため、後述のように、より用途を限定したAlias Tokenを定義することで、利用者が簡単に使えるようにしています。
Alias Token の定義
Alias Tokenは今現在、 heading
body
buttonText
の3種類にとどめています。汎用的なTokenを用意して、デザイナーに階層を考慮してもらい、ドキュメントでカバーするような運用にしています。ドキュメントを一部抜粋します。
Alias Tokens | Description | Global Tokens |
---|---|---|
heading1 | line-height: 1.3; font-weight: 500; |
fontSize110 |
heading2 | line-height: 1.3; font-weight: 500; |
fontSize100 |
heading3 | line-height: 1.3; font-weight: 500; |
fontSize90 |
heading4 | line-height: 1.3; font-weight: 500; |
fontSize80 |
heading5 | line-height: 1.3; font-weight: 500; |
fontSize70 |
heading6 | line-height: 1.3; font-weight: 500; |
fontSize60 |
body1 | p, li, label...etc, line-height: 1.75; font-weight: normal; |
fontSize50 |
body2 | p, li, label...etc, line-height: 1.75; font-weight: normal; |
fontSize40 |
body3 | p, span line-height: 1.75; font-weight: normal; |
fontSize30 |
body4 | p, span line-height: 1.75; font-weight: normal; |
fontSize20 |
body5 | p, span line-height: 1.75; font-weight: normal; |
fontSize10 |
buttonText
はどちらかといえばComponent Specific Tokenのほうが適切かもしれませんが、TurtleではAlias Tokenとしてまとめてしまっています。むしろ、私たちが作るデザインシステムにはAlias Tokenからさらに詳細度の高いComponent Specific Tokenを定義していません。
たとえば、なんらかの入力欄に使うラベルのTokenを考えます。このとき、シンプルにlabel
というTokenで名付けたくなるかもしれませんが、それにはいくつか問題があります。
まず、label
と一口に言っても、入力欄につかうもの以外にも考えられることです。例を挙げると、下記の画像のような、必須項目であることを表すUIです。
これはlabel
でしょうか? それとも、状態を表すstate
と名付けたほうが良いでしょうか? デザインシステム側で指針を作ることも可能ですが、デザイナーや開発者の学習コストは上がってしまい、知識の差によって迷うケースが発生してしまいます。
また、さまざまなTokenを検討していましたが、詳細度を明確にしていくほどTokenの数が多くなりすぎてしまいます。DMMでは多くのサービスにTurtleを展開していく必要があるので、Tokenが多いと、提供側と利用側には大きなギャップが生じ、結果的に一貫性を保つことが難しくなってしまいます。
そこでTurtleでは、MUIなどのOSSとしてさまざまなサービスに使われるデザインシステムを参考にし、詳細度を高めないTokenを採用することにしました(前述のbody1
, body2
など)。
この設計だと自由すぎる制約にもみえますが、私たちの場合は、コンポーネントにベストプラクティスを集約し、そのまま使ってもらうことで緩和しています。また、Alais Tokenでは line-heigth
と font-size
がセットで提供されており、デザインシステムを利用する人が細かな調整を考える必要がないようにしています。
実際のコード上だと、以下のように使用できます。
const foo = (theme: TurtleTheme) => css(theme.turtle.typography.body1);
TurtleではCSSを書くのにEmotionを使っていて、関数として書くことでtheme
を暗黙的に解決できるようにしています。theme
からtypography.body1
を指定するだけで利用者側はタイポグラフィーを使用できます。
イレギュラーの対応
Global Tokenは15段階のスケールになっていますが、Global TokenのすべてをAlias Tokenとして扱っているわけではありません。
理由としては、DMMには多くのサービスがあることから、用途が限られるAlias Tokenでは不十分なケースが考えられるためです。たとえば、装飾として非常に大きなフォントをサービストップページのヒーローヘッダーに使いたい場合などが考えられます。そういったケースではGlobal Tokenを直接使ってもらうことができるようにしています。
まだまだこれがベストだとは思っていませんが、デザインシステムを実際に各サービスやシステムで導入していく中でさまざまな表現に柔軟に対応していきたい意向があります。 定めたAlias Tokenとは違う表現を利用したいときに、Global Tokenを利用してもらう運用にしています。
レスポンシブタイポグラフィー
Turtleでは、レスポンシブタイポグラフィーを導入することで、あらゆるデバイスでの見え方を最適化しています。
たとえば、PC向けのデザインをFigmaでつくったときに、SPでは同じフォントサイズだと大きすぎる印象を与えることがあります。すべてのブレークポイントでデザインと実装をつくるのはコストがかかりますし、その上でも、すべてのデバイスサイズで最適な見え方になるとは限りません。
そこでclamp()
を使用し、我々のユースケースで最適なフォントサイズをレスポンシブに可変させます。コードとしては以下のようになります。
@media (max-width: 44.9375em) {
html {
font-size: clamp(1rem / 1.125, 0.55rem + 1vw, 1rem)
}
}
@media (min-width: 45em){
html {
font-size: clamp(1rem, 0.36rem + 1vw, 1.625rem);
}
}
コードの詳細を説明すると、まず、小さい画面幅では文字を小さくしたいという要望がありました。そのため、以下の設計で文字が小さく変化するようにしています。
max-width: 44.9375em
: 719px。Turtleの画面幅でsmの最大値に当たり、比較的小さい画面幅の最大幅となる1rem / 1.125
: 1つ下のGlobal Tokenの大きさを下限値としている0.55rem + 1vw
: 719pxの時点で、ちょうど1remになるようにスケールする((16*0.55)+(719*0.01)
)1rem
: 上限値。小さい画面幅では文字を大きくしたいという要望はない
対して、大きい画面幅では文字を大きくしたいという要望があります。そのため、以下の設計で文字が大きく変化するようにしています。
min-width: 45em
: 720px。Turtleの画面幅でmdの最小値1rem
: 下限値。大きい画面幅では文字を小さくしたいという要望はない0.36rem + 1vw
: lgの画面幅1024px以上でスケールし始める。mdでスケールさせるニーズはないため((16*0.36) + (1024*0.01)
)1.625rem
: この上限値は勘です。px換算すると26pxになり、デザインシステムにおけるドキュメントの説明でキリの良い数字だと利用者がイメージしやすいことから26px以上大きくならないと説明するために設定された数値です。
上記のように、DMMにおけるスケールのニーズが画面幅によって異なるため、メディアクエリを分けています。
レスポンシブタイポグラフィーを導入することで、デザインと実装コストを下げつつ、ユーザーにとって最適な見え方を実現できます。
Typography を適切に使ってもらうために
FEGは実際にサービスを持っているわけではありません。あくまでデザインシステムを設計、運用、保守、導入サポート、導入先のコードレビューからデザインレビューを実施しています。
さまざまなサービスにデザインシステムに設計されたコンポーネントやTokenが共通して使えることに重きを置いています。そのため、私たちが設計したデザインシステムを同じ組織内の別のチームが利用することになります。
このようにして、デザインシステムを提供するだけに留まらず、サポートしていくことによって、実際に利用された知見を元にデザインシステムを育てています。
まとめ
今回は、プラットフォーム事業本部のフロントエンドグループで設計しているデザインシステムの試行錯誤を紹介させていただきました。
おそらく本記事を読んでいただいているほとんどの人が、今回の内容に限らず、課題に取り組んでいると思われます。私たちもまだまだデザインシステムを育てている途中なので、一緒に育ててくれる仲間も募集しています