Wantedly Engineering Handbook
  • Wantedly Engineering Handbook
  • まえがき
  • 第一部:開発チームへの案内
    • 技術とアーキテクチャ
    • プロダクト概要(未執筆)
    • 開発チームの構造
    • コミュニケーションの全体
    • ドキュメンテーション(未執筆)
    • カレンダー
    • 障害対応の心構え
    • 効率的な社内知識の調べ方
    • 外部発信(執筆中)
  • 第二部:技術領域への案内
    • Apps
      • アプリを提供するプラットフォーム
      • デザインシステム入門
      • Web アプリのアーキテクチャ
      • プロダクトデザイナーと上手に協働するための心得
      • Web アプリのデザインシステムライブラリ
      • Web アプリ共通ライブラリ "React Shared Component" の紹介
      • モバイルアプリのアーキテクチャ
      • モバイルアプリのデザインシステムライブラリ(未執筆)
    • The System
      • protobuf スキーマと gRPC 通信
      • 実践: gRPC in Ruby
      • 実践: gRPC in Go
      • GraphQL Gateway - アプリ向けに API を公開する
      • Wantedly Visit で BFF GraphQL サーバーを辞めた理由
      • 実践: GraphQL スキーマ設計(未執筆)
      • API での認可処理 (Authorization)
      • マイクロサービス共通ライブラリ "servicex" の紹介
      • 非同期メッセージング処理入門(未執筆)
      • バッチ処理入門(未執筆)
    • Infrastructure
      • Infrastructure Squad
      • プロダクト開発のための Kubernetes 入門
      • インフラ構成概要
      • リリース・デプロイ戦略を支える技術
      • SaaS を活用する:New Relic, Honeybadger, Datadog
    • Data
      • データ基盤入門
      • レコメンデーション
      • Looker 入門
      • 推薦システムの開発に使っているツール
    • 開発プロセス
      • Git の慣習
      • ポストモーテムの取り組み
      • 負債返済日の取り組み
      • プロダクトの課題発見及び解決
      • ソフトウェアデザインの基礎
      • コードレビュー
      • コーディング規約
      • リリース・デプロイ戦略
      • 上長承認が必要な作業
      • アーキテクチャディシジョンレコード(ADR)
      • 作業ログを残す意味
      • 多言語化対応(i18n)
      • メール開発
    • 開発ツール
      • 社内利用している開発ツールの最新状況
      • kube
      • Code Coverage
      • Kubefork
  • おわりに
    • ロードマップ(未執筆)
    • Handbook の書き方
    • コントリビューター
  • 付録
    • 社内用語集
    • 主要な GitHub レポジトリのリスト(未執筆)
    • 今後の挑戦・未解決イシュー(未執筆)
    • プロダクト開発組織のバリュー(未執筆)
    • 採用についての考え方(未執筆)
GitBook提供
このページ内
  • TL;DR
  • UI デザインシステムについて
  • Wantedly の UI デザインシステムとは何か・何でないか
  • なぜ UI デザインシステムを作るのか
  • React 実装の設計
  • UI デザインシステム構成要素について
  • Lv.0 Foundation
  • Lv.1 Basic components
  • その他 生産性向上のための工夫
  • まとめ & Future work

役に立ちましたか?

  1. 第二部:技術領域への案内
  2. Apps

Web アプリのデザインシステムライブラリ

前へプロダクトデザイナーと上手に協働するための心得次へWeb アプリ共通ライブラリ "React Shared Component" の紹介

最終更新 2 年前

役に立ちましたか?

TL;DR

  • Wantedly の UI デザインシステムは「WantedlyのUIをデザインする上での共通の考え方とツール&アセット」でありエンジニアとデザイナが効率よくコミュニケーションするための共通言語となる

  • デザインシステムを (Web) Frontend に持ち込む際は、単なるコンポーネントカタログではなく、システムが定義するものと同じレベルの抽象を持つライブラリ・フレームワークとして実装することで、より有効性を発揮する

UI デザインシステムについて

Wantedly におけるデザインシステムは、「プロダクト・デバイスをまたいでも・誰がデザインしても体験やブランドとしての一貫性を保つ」「デザインの生産性を向上させ、デザイナ - エンジニア 間コミュニケーションを改善することで、ユーザに価値を届ける速度を向上させる」といった目的のために作られたものです。

より詳しくは、を参照してください。

次の2つの画像にあるように、Wantedly のプロダクトなどをデザインするときに利用する色やフォントなどのスタイルと、ボタンやテキストフィールドなどの UI コンポーネントなどが定義されています。

Wantedly の UI デザインシステムとは何か・何でないか

Wantedly が作っている「UI デザインシステム」とは何か、内部のドキュメントでは次の一文で表現されています(強調は筆者による)。

WantedlyのUIをデザインする上での共通の考え方とツール&アセット

この「共通の考え方とツール&アセット」とは何か、いくつか具体例を見ていきます。

たとえば「Button」を表すコンポーネントですが、Sketch 上では以下のようなインタフェースとなっています。右のパネル中央付近に「Overrides」というセクションがあり、「TextStyle」「Shape」「State」「BackgroundColor」「Elevation」というパラメタが並んでおり、ここから見た目を変更できるようになっています。

上記5つのパラメタは Foundation としてデザインシステムに定義されており、殆どのオブジェクトはこれらのパラメタを変更することで見た目を決定するようになっています。

また、上記の画像では Button の見た目よりも少し外側に線が出ていますが、実際にその空白まで含んで Button であると定義されています。これは TouchArea と呼ばれ、そのコンポーネントが持つべき最低限の余白を表しています。これは Button や TextField などの Interactive なコンポーネントに適用されており、余白自身もコンポーネントの一部になります。

TouchArea によりコンポーネント間の余白がいい感じになるの図。この領域を含めて Apple や Google の Interface Guideline を満たすように設計されている。

ここまで例に上げたとおり、Wantedly の UI デザインシステムは「コンポーネントカタログ」ではなく、コンポーネントの構成要素・原則からなる「共通の考え方とツール&アセット」であるというのがなんとなくわかってもらえたでしょうか。

なぜ UI デザインシステムを作るのか

Wantedly では何のために UI デザインシステムというものを作っているのか、社内のドキュメントでは以下のような目的が挙げられています。

  • ブランド表現 - Wantedlyとしての見た目と振る舞い の一貫性を保つ

  • ベーシックなユーザビリティの担保

  • デザインアウトプットの効率化

    • 細かい造形で悩まず、プロダクトとして大切な体験にフォーカスできるように

    • 複数のプロダクトをまたいでも、共通の考え方で対応できるように

  • エンジニアとのフロントエンド開発、コミュニケーション、メンテナンスの効率化

ここでは「エンジニア」と明記されている「エンジニアとのフロントエンド開発、コミュニケーション、メンテナンスの効率化」について、なぜそうなるのかをもうちょっと掘り下げます。前節での「デザインをする上での共通の考え方とツール&アセット」というのを前提として考えると、以下のような理由があると考えています。

  • (UI)デザインシステムが、エンジニアとデザイナが効率よくコミュニケーションするための共通言語となる

  • UI デザインシステムにより、コンポーネントの作り方に一貫したルールが生まれる

    • このルールを知り、使いこなす(使いこなせるツールが存在する)ことで、誰でも「Wantedly らしい UI コンポーネント」が作れる

「デザイナがどういう言語を用いて、どのようなルールの上でデザインをしているか」をエンジニアが知ることで、コミュニケーションが円滑になり、背景・ロジックを知った上で実装ができるようになる。それにより「エンジニアとのフロントエンド開発、コミュニケーション、メンテナンスの効率化」が達成できるのではないでしょうか。

余談ですが「デザイナがどういう言語を用いて、どのようなルールの上でデザインをしているか」というのは、Web エンジニアが Ruby on Rails や Next.js といったフレームワークを利用するのと似たような構造に思えます。Wantedly のデザイナはデザインシステムというフレームワークに乗ることで、細かいことを気にせずプロダクトの価値を生み出すことに集中できると解釈するとわかりやすそうです。

React 実装の設計

前節で(UI)デザインシステムは「エンジニアとデザイナが効率よくコミュニケーションするための共通言語」であり「コンポーネントの作り方に一貫したルール」をもたらすものである、という解釈をしました。また、「UI デザインシステムというフレームワーク」とも表現しました。これを実現するために、エンジニア向けの実装はどのようにあるべきでしょうか。

「共通言語」であり「一貫したルール」であるために、エンジニアとデザイナはデザインシステムに関して同じレベルの抽象をもってコミュニケーションしていく必要があるはずです。ライブラリとして提供する実装に関しても、基本的にはデザイナが扱っている抽象・フレームワークとおなじレベルのものを提供していく必要があるでしょう。

「同じレベルの抽象」というとかなり抽象的な表現ですが、誤解を恐れずに言い換えると「デザイナと同じロジックでコンポーネントを作れること」ということでしょうか。わかりやすいところでいうと「デザイナがコンポーネントを作るときに指定するパラメタが、そのままコンポーネントの Props として表出している」などです。もっと深堀りすると「Button は〇〇と△△と…から構成されており、そのパラメタとして Elevation と ... がある」みたいなものが、正しく React コンポーネントの実装およびインタフェースとなっている必要があります。

type ButtonProps = {
  shape?: Shape;
  reaction?: Reaction;
  backgroundColor?: Color | Gradation;
  elevation?: Elevation;
  // ...
};

UI デザインシステム構成要素について

これは React 実装に限らない UI デザインシステムの定義上の話です。UI デザインシステムは次の3~段階の要素から構成されています。

  • Lv.0 Foundation

    • 一貫した Corporate Branding のためのシステム

    • UI に限らない Graphic Standards: 色, フォント, アイコン など

    • UI で守るべき基本原則: Layout unit, Shape, Elevation, Reaction, Typographic scale

  • Lv.1 Basic Components

    • (Designer|Developer) Productivity を向上させるためのシステム

    • ボタンやテキストフィールドなどの基礎コンポーネント群

  • Lv.2 ここまでの要素の組み合わせからなる UI コンポーネント群

  • Lv.3 プロダクトの UX を向上させるための機能コンポーネント群

  • ...

Lv.2 以降に関してはそこまでのコンポー ネントの組み合わせが主になります。よって、Lv.0 Foundation および Lv.1 Basic components を React の上でどう表現するかがポイントになってきます(Lv.2以降についてはまたの機会があれば紹介します)。

Lv.0 Foundation

//==== UI デザインシステムの実装
import { css } from "styled-components";

export type Elevation = 0 | 1 | 2 | 3 | 4 | 6 | 8 | 12 | 16 | 24;

export const elevationCss = css<{ elevation: Elevation }>`
  box-shadow: ${p => getElevationBoxShadow(p.elevation)};
`;

//==== 利用イメージ

// 上で定義した CSS を埋め込めば、elevation を props で指定できるコンポーネントになる
const Card = styled.div<{ elevation: Elevation }>`
  ${elevationCss}
`;

これで Wantedly の UI デザインシステムを表現できたでしょうか?実はまだ足りません。Foundation のパラメタを決定するタイミングでいくつかロジックが絡むことがあります。例えば次のようなものです。

  • Reaction は (対象物) × (アクションの種類) の組み合わせで変化するパラメタが異なる

    • ボタンは Elevation と背景色どちらも変化するが、テキストフィールドは背景色のみが変わるパターンが定義されている

    • Focus と Press では背景色の濃さなどが変わる

  • ユーザの閲覧環境や言語によって、同じテキストスタイルでも文字の大きさや行の高さが変化する場合がある

このようなロジックが絡むパラメタをうまく扱うために、styled-components の Interpolation だけでなく React のカスタム Hook も提供するようにしています。たとえば Reaction であれば useReaction というカスタムフックにリアクション推定のためのロジックを隠蔽しています。

//==== 利用イメージ

const Card: React.FC = ({ children }) => {
  // `useReaction` はライブラリで提供する
  // 返り値には onMouseEnter などのリアクションを取るためのイベントハンドラと、
  // CSS に渡すための props が含まれる(elevation や backgroundColor など)
  const reactionProps = useReaction()

  return (
    <CardContainer {...reactionProps}>
      {children}
    </CardContainer>
  )
};

const CardContainer = styled.div`
  /* reactionCss はライブラリで提供する */
  ${reactionCss};
`;

Lv.1 Basic components

Foundation の実装で、UI コンポーネントの原則を React component に適用するためのツールキットを作りました。これを利用して Button や TextField などの基礎コンポーネントに適用していきました。

export interface ButtonProps {
  elevation: Elevation;
  size: Size;
  shape: Shape;
  // ...
}

// NOTE: `forwardRefStyled` は styled-components のコンポーネントに対して
// Props 移譲と `forwardRef` をするためのユーティリティ
export const Button = forwardRefStyled<ButtonProps, "button">(function Button(
  props,
  ref
) {
  const { reactionProps } = useReaction()

  return (
    <StyledButton {...props} {..reactionProps}>
      {children}
    </StyledButton>
  )
});

const StyledButton = styled.button`
  /* 前節のreactionCssに加え、elevationやshapeまわりのスタイルを束ねた便利interpolation */
  ${foundationCss};
`

コンポーネントの実装に関しては基本的に Lv.0 で定義した interpolation を埋め込み、それに渡す property は custom hook から取得しています。styled-components をハードに使うので、とくに型周りに関していい感じになるようなユーティリティ関数を用意していたりしますが、そのあたりはこの記事では割愛します。

その他 生産性向上のための工夫

この記事中では具体的に紹介しませんでしたが、エンジニアがデザイナの思考をなぞりデザインシステムを使いこなすための、提供する実装にもいくつかの工夫をしています。

この Storybook は Pull Request を作るたびに URL が発行されるようになっており、レビューや動作確認時の助けにもなっています。

また、開発時にエディタ上から利用しやすくするために、「見やすい型」にするようにしていたりもします。

このあたりの細やかな工夫については未執筆です。

まとめ & Future work

ここまでで、「Wantedly における UI デザインシステムとはなにか」「デザインシステムの React 実装の設計」について紹介しました。この記事で紹介したデザインシステムの実装は、Wanteldy の最近のプロジェクトで活用されています。

一方で、デザインシステムについては、ここで紹介した React 実装以外にもやるべきこと・やると良さそうなことが無数に残っています。いくつか例を上げると下のようなものがあります。

  • Android および iOS 向けの実装

  • デザイナ - エンジニアのさらなるコミュニケーション改善のためのエンジニアリング

  • エンジニア実装(React, Android, iOS, ...)とデザイナ実装(Sketch or Figma)のインテグレーション

話を聞きに行きたい

  • GitHub: @wantedly/design-system-implementer

もっと知りたい

デザインシステムの Sketch 実装 -

ここまでで満たすべき要件を確認したので、設計に移っていきます。前提として、TypeScript + React でシステムを実装していきます。これは Wantedly における Web Frontend の主要な技術選択にあわせています。内部では を利用していますが、これは peerDependencies を除きインタフェースとして露出することは無いようにしています。

Lv.0 Foundation には前述したとおり、色・フォント・アイコン・Elevation などのデザインパラメタが定義されています。また、 や Reactionなど UI コンポーネントの振る舞いの原則も含まれます(Reaction: のような、Hover や Focus など、ユーザのアクションによってコンポーネントに起こる反応のパターン)。

さて、この Foundation を React + styled-components の世界に落とし込むとどうなるでしょうか?単なるデザインパラメタと捉えられれば、CSS プロパティの集合として表現することができそうです。styled-components には があるので、それを使います。

コードスニペット中にも書いていますが、提供する Hook の返り値には onMouseEnter などのイベントハンドラが仕込まれており、そのままコンポーネントに渡されることを想定しています。このあたりの API は などのライブラリを参考にしました。また、リアクションの推定などは の一部である というライブラリを内部的に利用しています(自分で実装するとアクセシビリティ観点などで考慮漏れするのが目に見えているため)。

単なる汎用スタイル定義集であれば Interpolation を提供するだけでも問題ないでしょう( などがそういうアプローチです)。ただ、Wantedly で作りたかったのは「Wantedly における UI コンポーネントの原則を適用するためのツールキット」であり、その "原則" にはロジックも含まれるため、カスタムフックを併用するような構成となりました。

わかりやすい例としては、 の提供があります。Props の定義・そこに記述したドキュメントが閲覧できるほか、 addon によって挙動の理解・確認の支援をしています。

Slack: ,

デザインシステムが加速させるプロダクト開発, p.41
styled-components
Elevation
Material Design における State
css という CSS interpolation を作るための API
downshift
React Spectrum
React Aria
styled-system
Storybook
knobs
#frontend_chapter
#design_system
React でデザインシステムを正しく実装する - コンポーネントカタログを超えて | Wantedly Engineer Blog
UIデザインに必要な『一貫性』へのアプローチ - 管理画面のアップデートに際して | Wantedly Design
ノンデザイナーズ・Wantedly デザインシステム完全理解ペーパー
デザインシステムが加速させるプロダクト開発 / Design System and Scalable Product Development