2021/10/25追記
おまたせしました。この記事の後編も公開しておりますので、合わせてお読みください。 inside.pixiv.blog
こんにちは。プロダクトデザイナーの yksk とフロントエンドエンジニアの f_subal です。
ピクシブにはデザインシステムを開発するチームがあります。ピクシブが運営する数多くのプロダクトが共通のガイドライン、コードを使ってUIを設計できる体制への移行を目的としており、そのための仕組みづくりに取り組んでいます。
今回は、先日行われた pixiv DEV MEETUP 2021 のセッション「PIXIV Design System 2021」で発表した、技術的な取り組みについて前後編に分けて発表します。
前編にあたるこの記事では f_subal パートの内容をおさらいをしていきます。
PIXIV Design System 2021
昨年のpixiv DEV MEETUPでデザインシステムの発表をしてから1年が経ちました。 当時はデザインガイドラインが定義されたものの、他のサービスへの横展開はまだ行われてない状況でした。
デザインシステムには大きく2つの側面があります。デザインガイドライン と UI ライブラリ です。「デザインガイドライン」とは UI デザインのルールを定めたもので、主に用語集・ドキュメント・Figma 上のファイルとして表現されます。
一方 UI ライブラリ(狭義のデザインシステム) はそれを実装に落とし込んだもので、特にWeb の文脈では JavaScript や CSS でガイドラインに従った UI を書けるようにする仕組みを指します。あれから1年が経過し、社内にはデザインシステムの npm パッケージができ、いくつかのプロダクトで利用されるようになりました。
デザインシステムを導入する動機として、サービス間の体験の統一があります。ピクシブには多数のサービスがありますが、使っているサービスが変わっても「これは pixiv のサービスの一部だ」と感じられるようにしたいというモチベーションです。
ただし、ピクシブには 15〜20 程度の Web アプリケーションがある(しかもその大半が 5 年以上の歴史を持っている)ので、この状態を本当に実現しようと思うとまだまだ先は長いです。デザインシステムチームの使命とは、この状況でも少しずつ浸透させていけるような(既存のコードをすべて投げ捨てるような大改修を要求しない)UI ライブラリを実装し、導入を支援していくことです。以下、その最初の一歩となるライブラリをどうやって作っていったかをお話します。
多数のプロダクトで同じデザインシステムを使うとはどういうことか?
すでに述べたとおり、ピクシブには 15〜20 個のプロダクトが存在します。
しかもその大半は5年10年の歴史を持つコードベースです。最近できたプロダクトは最初から SPA として作ることが多いですが、昔からのプロダクトはそうではなく、後から SPA 化を進行するケースが大半です。
技術の選択は各チームの裁量に任されています。React を使っているプロダクトは多いですが、全社で技術統一とかはしていません。デザインシステムを浸透させていくためには、フロントエンドの技術スタックが React でも Vue.js でも、はたまたサーバーサイドのテンプレートエンジンであってもそれなりに通用する実装であることが求められてきます。
コンポーネント集だけではダメだった話
いまの形のデザインシステムが実装される前(2019年頃)、我々がやろうとしていたのはコンポーネント集でした。このときは pixiv.net の SPA 化の過程で生まれた React コンポーネント(及びテーマのための色変数)を、他のプロダクトでも使えるよう社内 npm に置くことだけが差し当たって目指されました。
結論この方針はダメでした。コンポーネント集や定数集はあればうれしいものですが、その恩恵を得られるのは React のプロジェクトだけでした。
問題はこれだけではありませんでした。当然のことですが、コンポーネント集はあらゆるユースケースの UI をカバーできるわけはありません。実際には各プロダクト特有の UI を書きたい場面があるはずです。このとき、コンポーネントそのものはプロダクト特有だけど、色やスペーシングはガイドラインに従いたい時にどういうコードを書くべきでしょう?単なる定数集にはその統制を取る力がないのは明白でした。
JavaScript で定数集を配り CSS in JS で使うことはできるものの、すべてのコンポーネントが必ずそれを使って書くような規約を、15以上のプロダクトで徹底することができるでしょうか?そんなことは到底できない、というのが我々の結論でした(同じ理由で SCSS などの変数も我々のデザインシステムの基盤としては弱すぎると考えました)。コンポーネント集+定数集というアプローチは、はじめから破綻が見えていたのです。
「CSS フレームワーク」を作りたくなかった話
とはいえ、React 以外のフレームワークで使えるデザインシステムの実装として良いアプローチがあるでしょうか?当時の我々は、Twitter の Bootstrap に相当するものを自前で作らないといけないのかと思っていました。しかし一方、この方針は避けたいとも思っていました。
多くのフロントエンドエンジニアに共感してもらえると思いますが、Bootstrap を導入したところで別に規律ができた試しはありません。たいていの場合、フレームワークのクラスは上書きされるものです。
また Boostrap のクラス名はコンポーネントと同じ粒度です( .btn
.navbar
)。これらは見た目しか提供しないという点で、React のコンポーネント集より退化しています。また、出来合いのコンポーネントでない独自 UI を書くときにあまり助けにならないという問題は残ります。
ユーティリティファースト CSS との出会い
そんな中で出会ったのが Tailwind.css でした。
Tailwind.css は「ユーティリティファースト」を謳った CSS フレームワークで、2020年初頭から日本でも本格的に流行りはじめました。こんな風に、.w-32
というクラスで width: 32px
にしたり、.bg-blue-500
をつけることで背景を青くすることが出来るのが特徴です。
<figure class="md:flex bg-gray-100 rounded-xl p-8 md:p-0"> <img class="w-32 h-32 md:w-48 md:h-auto md:rounded-none rounded-full mx-auto" src="/sarah-dayan.jpg" alt="" width="384" height="512"> <div class="pt-6 md:p-8 text-center md:text-left space-y-4"> <blockquote> <p class="text-lg font-semibold"> “Tailwind CSS is the only framework that I've seen scale on large teams. It’s easy to customize, adapts to any design, and the build size is tiny.” </p> </blockquote> </div> </figure>
最初に Tailwind を知ったとき、たしかに面白いアプローチだと思ったものの、これが我々のデザインシステムに役立つとは思っていませんでした。しかし実は Tailwind に設定ファイル( tailwind.config.js
)が存在し、この w-〇〇
や bg-〇〇
自分たちのテーマに沿ってカスタマイズできるというのを知った時、「これだ!」と思いました。
Tailwind.css はただの CSS フレームワークではありませんでした。フレームワークを作るための「メタ CSS フレームワーク」だったのです。
最初のコンポーネント集はお蔵入りしましたが、その後も定数集の npm パッケージは作っていました。これを元に tailwind.config.js を試しに書いてみて、手応えを感じました。
デザインシステムの定数集から Tailwind のクラスを生成し、基本的なマークアップは Tailwind のクラスのみを使う規約を作ります。すると「Tailwind に存在しないクラスはガイドラインの範囲外なので書けない」という状況が生まれます(正確には、書けはしますが html を見ただけでガイドラインから外れたことをやっているとわかるようになります)。
しかも Tailwind のクラスはコンポーネントよりも細かい粒度で提供されるので、プロダクト特有の UI を作る際にも組み合わせて使えます。これが我々にとっての答えでした。
デザインシステムの三層構造
問題を改めて振り返りましょう。出来合いのコンポーネントを配るだけのアプローチでは、プロダクト固有の UX に適応できる柔軟性がありません。また色やスペーシングの定数を配るだけでは、それを使ってコードを書かせる強制力が足りません。
ユーティリティファーストはこの2つの間を埋めるアプローチです。ここに載っている色やスペーシングの定義(この場合 CSS のクラス)以外を基本使わないと決めることで、先の2つの問題をどちらも解決することが出来ます。このようにして我々は、「定数(Constants)」「ユーティリティ」「コンポーネント」の三層構造でデザインシステムを構築するというアイデアに辿り着きました。
デザインシステムを利用するチームは、まずユーティリティだけを取り入れることが出来ます。
その上で <Button>
や <Pager>
など、挙動まで担保したいケースが生じた際に必要なコンポーネントだけを使う選択ができます。コンポーネント集は現状 React 限定になりがちですが、一方ユーティリティだけならどんな技術スタックでも導入ができます。技術スタックが多様な組織では、ユーティリティファーストが最もデザインシステムを始めやすいアプローチと考えられます。
まとめ
技術スタックが多様な組織で「コンポーネント集」一本でやっていくのは難しいことです。我々は「定数」と「コンポーネント」の間に「ユーティリティ」の三層目を作るのが良いことを学びました。我々の UI ライブラリは、Tailwind.css の思想にならって構築していくことにしました。
発表の後半パートでは、これらの思想に基づいてつくられたライブラリのより具体的な実装を紹介します。この記事で述べたユーティリティファーストな CSS を実際どうやって実装したのか、Tailwind.css を使ってない( styled-components などを使っている )プロジェクトはいったいどうしたら良いのか、どうやって社内に広げていったのかについてもう1人のエンジニア pnly に説明してもらいます。ご期待ください。
ピクシブ株式会社では、デザインシステムを強くし、広げてくれるフロントエンドエンジニアと、エンジニアと協力してデザインガイドラインの設計をしてくれるプロダクトデザイナーを募集しています!
https://hrmos.co/pages/pixiv/jobs/002hrmos.co