Figma Tokensの導入 デザイナーと協力して一貫性のあるUI実装を実現する

この記事は [Goodpatch Advent Calendar 2021](https://qiita.com/advent-calendar/2021/goodpatch) の12日目です。

今回はFigmaのPluginであるFigma Tokensを使ってみて実感した恩恵や、実際にどのように利用したかを書いていきます。

# はじめに
フロントエンジニアの責務の一つとしてUI実装（UIの実現）があります。
UI実装はFigmaなどのデザインファイルを設計書として実装していきます。しかしながら、デザイナーも人間なのでデザインファイルにミスがあることもあります。また、デザイナーとエンジニアが並走してプロジェクトを進めていく場合はデザインファイルの変更がたびたび起こることもあり、都度デザイナーとコミュニケーションをとりながらコードを修正しなければなりません。

このような状況を考えると、UI実現の責務をフロントエンドエンジニアだけが受け持つのは荷が重く、クオリティ低下につながる危険性があるのではないでしょうか。
今回はFigma Tokensを使ってみたのですが、このようなツールを利用することでデザイナーとエンジニアの両者がUI実現に対して責任をもつ環境を実現し、一貫性のあるUIを実現する上で大きな助力になってくれると感じました。

# UI実装の理想と現実
### 理想
UIを実現する上でエンジニアを必要としない、つまりデザイナーが作ったデザインがそのまま実装されている状態が理想だと思っています。つい先日、Figma上で作ったコンポーネントをReactコンポーネントとして生成することができるAmplify StudioがAWSから発表されましたが、まさにこのような状態になることが最高だと思っています。
まだ実際に触っていないのでAmplify Studioがどんなものかはわかりませんが、とりあえずありがとうAmazon。
[AWS、ローコードのアプリ開発ツール「Amplify Studio」を発表](https://jp.techcrunch.com/2021/12/04/2021-12-02-aws-launches-amplify-studio-a-new-low-code-app-development-tool/)
<img src="https://jp.techcrunch.com/wp-content/uploads/2021/12/ezgif-3-b98b50e3f6a6.gif?w=600">

### 現実
デザイナー→デザインファイル→エンジニアという流れで、エンジニアはデザインファイルを元にUIを作成します。
エンジニア側の見落としやデザイナー側のデザインファイルミスがどうしても発生してしまうだけでなく、特にデザイナーとエンジニアが並行して動くパターンでは両者が多大な管理コスト、コミュニケーションコストを払わざるを得ないケースがあります。


# Design Tokens (デザイントークン) とは
デザイントークンとは何かを説明をするだけで一つの記事になってしまい、本題に入れそうにありません。
僕が中途半端なことを書いて混乱を招くのも良くないので、Adobe先輩のBlogにあった最高の記事を置いておきます:pray: 
[デザイナーと開発者の連携を効率化するデザイントークンとは何か？ | アドビUX道場 #UXDojo](https://blog.adobe.com/jp/publish/2021/03/29/cc-web-what-are-design-tokens#gs.j66xof)


# Figma Tokens - 実装とデザインファイルを密に連携する
Figma TokensはFigmaのpluginで、前述したデザイントークンを管理するツールです。
実際に使ってみて思ったこと、どのように利用したかを書いていきます。

## Figma Tokensについて
<img width="720" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896711/e8b4a210-df55-b874-43ea-df203ac258f6.png">
**Docs** :point_right:  [Fimga Tokens Plugin Docs](https://docs.tokens.studio/)

```結局何ができるのかいまいちわからない公式の説明文.
デザイントークンを使用できるようになりました。
このトークンは、ボーダーの半径やスペーサーユニットから、他のトークンを参照できるセマンティックカラーやタイポグラフィスタイルまで、さまざまなデザインオプションに使用できます。
トークンを変更すると、その変更がドキュメント全体、スタイル、または選択範囲に適用されるのを確認することができます。

Gives you the ability to use Design Tokens that can be used for a whole range of design options,
from border radii or spacer units to semantic color and typography styles that are able to reference other tokens.
It allows you to change tokens and see these changes applied to the whole document, its styles or just a selection.
```


###  Figma Tokensでできること
全てを理解しているわけではありませんが、考えられるメリットを書いてみます。
特に僕自身はFigma Tokensを利用してデザインを作る経験はしていないので、UIデザイナーにとってのメリットはふわっとしか分かっていません。（今回はエンジニアとしてデザイナーと連携するために利用したためエンジニア観点が強い）


####  1. デザインリソースを一元管理できる
サービス内で利用しているcolorやfont、shadowなど様々な情報（デザイントークン）を一覧で確認、編集、反映できます。
後続のデザイナーやエンジニアがサービス内のデザインルールを把握するのにすごく助かります。
実際に作った例↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896711/9cf3a110-cebe-0d53-cd1f-4860d17574b4.png)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896711/6fe000bf-5e73-f1ce-b43a-0e4ca7de78fe.png)

<br>

#### 2. 利用するデザイントークンセットの切り替えができる
動画を見た方が早いので下に置いておきます。
僕は利用したことがないのでこういうことができるんだなぁぐらいの理解です。使いこなせばすごい便利そうですが、クライアントワークで利用するケースはあまりイメージついていないのが正直なところです。
明日までにあと３パターン見たいと言われたときに便利そう （地獄） 

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Figma should&#39;ve shipped with PunkBuster, this feels like cheating. <a href="https://t.co/XPGvek4HNQ">pic.twitter.com/XPGvek4HNQ</a></p>&mdash; Jan Six (@six7) <a href="https://twitter.com/six7/status/1367790843143282691?ref_src=twsrc%5Etfw">March 5, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


<br>

#### 3. Figma TokensからGithubのPull Requestにプッシュできる
GitHubと連携ができプルリクエストにプッシュできるので、デザイナーがデザイントークンの変更PRを作れるようになります。デザイナーだけで完結できるのが本当に楽。マージのときに変更内容を把握すればエンジニア側も把握できるので便利です。
Ref: [Figma Tokens - GitHub Sync](https://docs.tokens.studio/sync/github)

話はちょっと変わりますが、GoodpatchではコミットメッセージにEmoji prefixをつけて管理することがあります。デザイントークンの変更があった際の接頭辞は`:bear:`:bear: をつけるようにしていました。
ふぃ熊ってことです :bear: 

```example.commit_template
🐛 :bug: バグ修正
👍 :+1: 機能改善
✨ :sparkles: 部分的な機能追加（🎉レベルの機能を構成するひとつひとつの部品）
🎨 :art: スタイリングの修正
```

詳しくはこちら :point_right:  [Goodpatch Blog - Emojiで楽しく綺麗なコミットを手に入れる](https://goodpatch.com/blog/beautiful-commits-with-emojis)






<br>

## デザイントークンを実装に反映する
<img width="800" alt="figma-tokens-flow.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896711/bd487e1f-7b5b-3c19-12b8-9011c7d5cf8f.png">

デザイントークンが記述されているjsonファイルを実装側で利用できる形にするために[Style Dictionary](https://github.com/amzn/style-dictionary)を使います。

```Style-Dictionary.
Style Dictionaryは、デザイン・トークンを使ってスタイルを定義し、そのスタイルをあらゆるプラットフォームや言語で使用することができます。
スタイルを作成・編集するための単一の場所を提供し、これらのトークンを、
iOS、Android、CSS、JS、HTML、スケッチファイル、スタイルドキュメントなど、必要なすべての場所にエクスポートします。
npmを通じてCLIとして提供されていますが、機能を拡張したい場合は、通常のノードモジュールと同様に使用することもできます。
```

### Figma Tokens の jsonファイルを Style Dictionaryで変換する
Figma Tokensから書き出されたjsonファイルは、エイリアスなどが含まれているためそのままではStyle Dictionaryで利用できないみたいです。
そのため[Token Transformer](https://www.npmjs.com/package/token-transformer) というパッケージを使って変換する必要があります。
変換後のjsonをStyle Dictionaryに渡すことでようやくお目当てのスタイルファイルが手に入ります。
ここら辺はGitHub Actionsなどで全部自動化すると良さそうです。

ref: [How to use tokens stored in GitHub in development?](https://docs.tokens.studio/sync/github#7-how-to-use-tokens-stored-in-github-in-development) 

<br>

### デザイントークンを別個のSCSS変数ではなくmapで使いたい
Style Dictionaryで出力されたscssファイルは、初期設定では以下のように１トークンに１変数が定義されています。

```tokens-from-style-dictionary.scss
$display-text-high-font-family: Noto Sans JP !default;
$display-text-high-font-weight: 700 !default;
$display-text-high-line-height: 150% !default;
$display-text-high-font-size: 48px !default;
$display-text-high-letter-spacing: 2% !default;
```

セマンティクスカラーなどは確かにこれでもいいのですが、フォントスタイルなどは `@each` を使ってまとめて呼び出したいといったケースがあると思います（mapになってると嬉しいよねっていう話）。

Style Dictionaryはちゃんと対応してくれていました。ありがとうAmazon。
configファイルにてformatに`scss/map-flat`や`scss/map-deep`を与えてあげると出力してくれます。
他にも複数のフォーマットがあるのでリンク貼っておきます。

Ref: [Style Dictionary - Pre-defined Formats](https://amzn.github.io/style-dictionary/#/formats?id=pre-defined-formats)

```style-dictionary.config.json
{
  "source": ["figma-tokens.json"], //figma tokensで出力されたjson
  "platforms": {
    "scss": {
      "buildPath": "src/assets/variables/", //出力先
      "transformGroup": "scss",
      "files": [{
          "destination": "_tokens.scss", //出力ファイル名
          "format": "scss/map-deep", ←これ
          "mapName":"hoge-tokens",  //map変数名
          "options": {
            "outputReferences": true
          }
      }]
    }
  }
}

```

```map-deep-tokens-from-style-dictionary.scss
$display-text-high-font-family: Noto Sans JP !default;
$display-text-high-font-weight: 700 !default;
$display-text-high-line-height: 150% !default;
$display-text-high-font-size: 48px !default;
$display-text-high-letter-spacing: 2% !default;

$hoge-tokens: {
  'Display': (
    'Text': (
      'High': (
        'fontFamily': $display-text-high-font-family,
        'fontWeight': $display-text-high-font-weight
        'lineHeight': $display-text-high-line-height,
        'fontSize': $display-text-high-font-size,
        'letterSpacing': $display-text-high-letter-spacing
     )
  )
)
```

<br>

### デザインファイルとスタイル実装の同期 ~エンジニアの介入無しにデザイン変更作業を完了させたい~
UI実装をする上で、color, typography, shadowなどのスタイルをフロントエンジニアはどれだけ認識するべきでしょうか。
プリミティブな要素を扱うweb実装において、ここら辺のスタイルはデザイナーが決めたものがそのまま勝手に反映されていると最高だなと個人的には思っています。
とはいえ実装はしないといけないので、**Figma上の定義されているスタイル名（下画像の枠線）をコピペするだけでスタイルが適用されつつ、デザインの変更があった際にエンジニアが何もしなくてもスタイルが更新されるような状態**を目指しました。

<img width="228" alt="figma-inspect.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896711/57715b0c-31c7-29fe-3177-3db54fdaf82a.png" />



#### どのように対応したか

Style Dictionrayにて `deep-map` で出力した際、mapのkey名がFigma上のスタイル名と同じになります。また、Figmaはコンポーネント名を `/` で区切ることで状態を階層管理できるようになりますが、`deep-map` で出力するとmapの階層構造がFigmaと全く同じになります。

例えば、Figma上で`Display/Text/High`となっている場合は以下のようになります。タイポグラフィーだけでなく他のトークンも同様です。

```map-deep-tokens-from-style-dictionary.scss
$hoge-tokens: {
  'Display': (
    'Text': (
      'High': (
         ~~~~~~~~~~~
     )
  )
)
```

上記を利用して、引数にFigma上のスタイル名を渡すとスタイルを適用してくれるmixin、functionを作成しました（コード下記参照）
例えば、`Display/Text/High`というタイポグラフィースタイルがFigma上で当たっている場合は、以下のように記入するだけで適切なスタイルが全て当たるようにしました。

```how-to-typography.scss
@use 'typography' as typo;

h1 {
  @include typo.set-typography('Display/Text/High');
}
```

また、上記のmixinはデザイントークンを利用しているため、**スタイル修正があったとしてもトークンの値を更新すれば勝手にスタイルも更新されます**。
例えば `Display/Text/High` のスタイルに変更が起きた場合は

1. デザイナーがFigma Tokens上で`Display/Text/High`のスタイル（font-sizeなど）を修正（トークンの更新）
1. デザイナーが修正PRを作成
1. PRを取り込む（トークンの更新の適用）
1. mixinで`Display/Text/High`を渡しているところのスタイルが勝手に更新される

といった具合で、エンジニアが手を動かさなくてもスタイル修正を完了できます。
デザイントークンを利用している恩恵ですね。



```typography.scss
@use "sass:map";
@use "sass:math";
@use "tokens" as tokens; ///Style Dcitionaryで出力したデザイントークン

/*
 * NOTE: set-typography
 *
 * $typography-name-as-defined-in-figma: Figma上で定義されているタイポグラフィー名 (ex."Display/Text/High")
 */
@mixin set-typography($typography-name-as-defined-in-figma) {
  $typography-name-list: str-split($typography-name-as-defined-in-figma, '/'); //map変数のkey配列
  $typography-set: tokens.$tokens; //Style Dcitionaryで出力したデザイントークンのmap変数

  @each $name in $typography-name-list {
    $typography-set: map-get($typography-set, $name);
  }

  $font-size: map-get($typography-set, 'fontSize');
  $font-weight: map-get($typography-set, 'fontWeight');
  $font-family: map-get($typography-set, 'fontFamily');
  $line-height: map-get($typography-set, 'lineHeight');
  $letter-spacing: map-get($typography-set, 'letterSpacing');
  $text-decoration: map-get($typography-set, 'textDecoration');

  font: $font-weight $font-size $font-family;
  line-height: math.div($line-height, 100%);
  letter-spacing: math.div($letter-spacing, 100%) * 1em;
  text-decoration: $text-decoration;
}

/*
 * NOTE: str-split
 * 区切り文字で文字列を分割し配列を返す
 *
 * $string: 文字列
 * $separator: 区切り文字
 */
@function str-split($string, $separator) {
  $split-array: ();
  $index : str-index($string, $separator);
  @while $index != null {
      $item: str-slice($string, 1, $index - 1);
      $split-array: append($split-array, $item);
      $string: str-slice($string, $index + 1);
      $index : str-index($string, $separator);
  }
  $split-array: append($split-array, $string);
  @return $split-array;
}
```

# 使ってみて実際どうだったか
デザイナーとエンジニアが並走しながら仕様、デザインを決めていくフェーズにおいて、デザインの修正対応がデザイナーだけで完結できるのはかなり楽です。並走しないパターンだとしても、エンジニアが参加する前にFigma Tokensで準備をしておいてもらえると、エンジニアが気持ちよく走り出せるのではないでしょうか。

デザイナーがスタイリング実装の一部を擬似的に担う状況によって、冒頭で述べた「デザイナーとエンジニアの両者がUI実現に対して責任をもつ」という状態を作り出せるだけでなく、
本来発生していたであろうコミュニケーションを省けるのはデザイナー、エンジニアの両者にとっても大きなメリットだと思います。

# 最後に
今回はFigma Tokensを利用しましたが、デザイントークンを管理するツールは他にもたくさんあります。Figma Pluginだけでも`Design Tokens`と検索するだけで40個近く出てきます。

より良いUIを作ることは目的ではなく、あくまでより良いユーザー体験を届けるための手段の一つだと思うので、Figma Tokensのようなツールを駆使してチームの時間をうまく活用していきたい気持ちです:raising_hand:

明日は[Strap](https://product.strap.app/)に関する楽しい記事が公開されるそうです！お楽しみに〜〜〜