entry-header-eye-catch.html
entry-title-container.html

entry-header-author-info.html
Article by

PIXIV Design System 2021 の発表をしました(後編) #pixivdevmeetup

こんにちは。フロントエンドエンジニアのpnlyです。

こちらの記事は前後編に分かれた記事となっておりますので、前編の記事「PIXIV Design System 2021 の発表をしました(前編)」もあわせてご覧いただけるとよりお楽しみいただけると思います。

前編では、デザインシステムを作ろうとして試行錯誤したエピソード、そして出来上がった設計思想についてお話しました。そしてこの後編では、その思想をどのようにして実現したのかについて具体的な実装をご紹介します。

デザインシステムの実装 "pixiv-elements"

前回の記事で出てきました"デザインシステムの三層構造"の実装は一つのモノリポジトリで管理されています。ガイドラインの根本となる定数以外にも、その定数をより利用しやすくするためのユーティリティや型定義、CIスクリプト、Storybookなどのドキュメントなど、デザインガイドラインを浸透させるための仕組みがすべて含まれています。

それでは一つずつパッケージを見ていきましょう。

今回は、"デザインシステム三層構造" にフォーカスを当てて、根本となる6つのパッケージを紹介します。

ガイドラインの基本となる定数

まずはじめに、デザインシステムの三層構造における最下層、"定数"の層から見ていきましょう。

Constantsには主要な2つのパッケージがあります。1つ目は @pixiv-elements/theme。こちらはテーマによって変化する色の値を指し示す"色の名前"を定める型定義です。この色の名前をつかってデザイナーとコミュニケーションを行います。figma上で指定された色名にしたがって色をあてることで、ダークテーマなどテーマによる違いを意識せずに実装することができます。

ポイントは、この色の命名です。たとえばmodalTitleやoverlayLabelなど、具体的すぎる名前にしていますとどんどん色名が増えていってしまい色の名前に対する意味合いが複雑になり破綻してしまうケースが多々ありました。できるだけ多くの人で利用するためには、できるだけ理解しやすく、シンプルに、セマンティクスは最低限にしています。

次に、@pixiv-elements/foundationです。

こちらはテーマに依存しない色以外の定数の置き場です。定数を一箇所で管理し、パッケージ化し、皆でこの一つの信頼できるソースを参照することで変更に対して柔軟な基盤が作られます。

デザインガイドラインはfigmaに定義されているだけでは形骸化を免れないでしょう。実装を含めたこの仕組みこそがデザインシステムたる礎になっています。

CSSを作り出すユーティリティ

デザインシステムの三層構造における中間の層であるユーティリティ層のパッケージを見ていきます。

ユーティリティとは、ガイドラインの各種定数を正しく使えるようにスタイリングを補助する役割を持っています。数値だけの定義ではその数値をどのように利用するかについての制約がありませんから、その値の使い方を提供するのがユーティリティの主な目的です。Webに例えると、CSSにおいての12px, #fffなどがいままで紹介した定数に対応し、font-size: 12px, background-color: #fffのようにプロパティまで含んだ定義がこのユーティリティの担う部分になります。

そして使いやすさというのも重要なファクターです。短い記述で便利にスタイリングできれば、より使ってもらえる。そして無意識にガイドラインの制約を満たしている状況を作り出せるのです。tailwindは漸進的な導入を促せる非常に適した解決策でした。

それでは具体的なパッケージを見ていきましょう。まずはじめに @pixiv-elements/tailwind-config です。その名の通り、CSSメタフレームワークで有名なtailwindのconfigファイルです。ガイドラインで定められている各種定数に沿って、configの定義を生成しています。存在しないクラスではスタイリングできないため、ガイドラインの制約が機能するという仕組みです。

tailwindに代わるstyled-components向けのユーティリティ

tailwindで書けばガイドラインの制約を満たしてかんたんにスタイリングできるようになりました。これでみんな幸せになったはず。

しかしながらtailwindで書かなければならない!というのは些か強引なところがありました。pixivにはたくさんのプロダクトがあり多種多様な技術で構成されています。皆がtailwindと相性が良いわけではありません。特に、すでにstyled-componentsでスタイリングをしているプロダクトではtailwindと混在する環境になってしまいます。それではtailwindのインラインの記法とstyledの記法とでスタイルの記述が分散してしまい見通しが良く無さそうです。

そこで我々はtailwindに代わるもう一つのパッケージ、@pixiv-elements/styled を作りました。pixivでは React + styled-components という構成がメジャーであるため、既存のstyled-componentsの記述と共存できる親和性の高い設計になっています。

基本的にはtailwindと同じことを実現するユーティリティになります。下の画像がそのコード例です。themeという見慣れない関数がありますが、この関数によってガイドラインに沿ったstyled-components用のスタイル(CSSObject)を生成しています。そして、メソッドチェーンの方式でスタイルを指定します。これらはすべて型安全にできているため、tailwindと同様にガイドラインの制約を担保できる仕組みになっています。

これは少し余談ですが、styled-componentsのcss propという機能を利用するとtailwindっぽくかけたりもします。

頻出するロジックをコンポーネントとして提供する

まずは導入コストの低いtailwindなどのユーティリティを利用するのがファーストステップでした。しかしながら基礎的なコンポーネントだと思っていたボタンなどについて深く考え始めると、意外と複雑なものだと気付かされるものです。それらを共通化して何も考えなくてもいい感じにしてほしい、その悩みに答えるのがコンポーネント層のパッケージ @pixiv-elements/react になります。

基本的なマークアップは先程のstyled, tailwindを使えばよいです。しかし、たとえばButtonやPagerなど頻出でかつ挙動が複雑であったりアクセシビリティを担保するために、Reactコンポーネントとして提供しています。

特徴としては、依存するコンポーネントの注入を行っている点です。いくらかのコンポーネントは、グローバルのコンテキストに依存するコンポーネントを内包せざるを得ないケースがあります。たとえばルーティング用のLinkがその代表例になります。そのようなコンポーネントの依存性を外部から注入する仕組みを用意することで、コンポーネント内部のリンクがreact-routerでもnext/linkでも、はたまたただの<a>タグでも動くようにできます。このような設計により技術選択の自由に幅をもたせることができました。

@pixiv-elements/icons、アイコン類もコンポーネントとして提供しているパッケージの一つになります。Web Components で構成されているため、導入コストが非常に低いです。

また、CIを用いてfigmaからSVGファイルのダウンロードする作業を自動化しています。定期的にfigmaを監視して、変更があったらGitlabに自動でMRが立つしくみです。これは別途記事になっておりますので、興味のある方は見てみてください。

今後

足りていないコンポーネントの充実化を進めていくというのが1つ目です。アクセシビリティが担保された最高品質のコンポーネントを整えていきます。もう一つは、利用プロダクトを広げていき、どのプロダクトからでもデザインシステムにコントリビューションできる環境を作っていくというのが一つ課題になっています。デザイナーやエンジニアなどいろんな人が横断的に編集できるドキュメントの管理方法など、まだいくつか試行錯誤が必要です。

そして、社内だけでなく、社外へ。

来年2022年、オープンソース化を目標に目指していきます!


再びデザイナーのykskです。いかがだったでしょうか。デザインシステムの設計に悩むみなさんの参考になれば幸いです。

ピクシブの各プロダクトはほぼ同じユーザー層を対象としているため、ユーザーはプロダクト間を跨いで利用することがあります。コードを共通化すれば各プロダクトで同じ挙動を提供でき、利用の手助けになると同時に、ピクシブのブランドにも寄与すると考えています。複数プロダクトの基盤になることから難易度の高い取り組みですが、他ではなかなかできない楽しい体験でもあると思います。

興味のある方は、下記で採用募集していますのでぜひご応募ください。お待ちしています。

icon
pnly
2019年新卒入社。pixiv.netのフロントエンドエンジニアをしています。TypeScriptと旅とジントニックが好き。