SCSSをトークン化してみた. 3

2025.12.30 10:00
2025.12.30 21:39
SCSSをトークン化してみた. 3

前回はトークンの説明でした。
今回は実際に作ったトークンの中からプリミティブトークンを紹介してみます。

全体構成

まずはfoundationのディレクトリ構成です。
プリミティブトークンとマップトークン、そして全体の仕組みの土台になるcoreがあります。

foundation/
├─ _index.scss
├─ core/
│  ├─ _base.scss
│  ├─ _functions.scss
│  ├─ _mq.scss
│  └─ _reset.scss
├─ maps/
│  ├─ _color-map.scss
│  ├─ _elevation-map.scss
│  ├─ _font-size-role-map.scss
│  ├─ _font-size-scale-map.scss
│  ├─ _font-weight-role-map.scss
│  ├─ _gradient-map.scss
│  ├─ _radius-map.scss
│  ├─ _shadow-map.scss
│  ├─ _space-map.scss
│  ├─ _transition-map.scss
│  └─ _z-map.scss
└─ primitives/
   ├─ _primitives-color.scss
   ├─ _primitives-font-weight.scss
   ├─ _primitives-shadow.scss
   ├─ _primitives-space.scss
   ├─ _primitives-transition.scss
   └─ _primitives-typography.scss

プリミティブトークン

まずは元の値となるプリミティブトークンです。
これらがサイト全体のテイストに影響します。

primitives-color(色の素材トークン)

サイトで使う色の実値(#xxxxxx)だけを定義するプリミティブ層です。gray-100neutral-900 のような色の“素材”をここに集約し、text.defaultbg.subtle などの意味付け(用途割り当て)は color-map 側で行います。これにより、色の直書きを防ぎつつ、配色変更もプリミティブ側の差し替えで一括反映できます。

// ==================================================
// Foundation: variables (Primitive Layer)
// 値そのもののみ定義。意味は color-map 側で付与。
// ==================================================

// ==================================================
// Base (non-scaled)
// ==================================================
$white:    #ffffff;
$off-white: #f8f6f2;
$black:    #13100e;

// ==================================================
// Grayscale
// ==================================================
$gray-50:   #fdfefe;
$gray-100:  #fcfdfe;
$gray-200:  #f9fafc;
$gray-300:  #e6eaee;
$gray-400:  #cfd5db;
$gray-500:  #b6bcc2;
$gray-600:  #9ca2a9;
$gray-700:  #7d838a;
$gray-800:  #5e656c;
$gray-900:  #3f464d;

// ==================================================
// Neutral Scale(ブラウン〜和色系)
// ==================================================
$neutral-50:   #f5f3ef;
$neutral-100:  #f4f1ed;
$neutral-200:  #efede9;
$neutral-300:  #eae5de;
$neutral-400:  #cdc4bc;
$neutral-500:  #a49a92;
$neutral-600:  #7a7169;
$neutral-700:  #655b54;
$neutral-800:  #4f453e;
$neutral-900:  #3a2f29;

// ==================================================
// Red Scale
// ==================================================
$red-50:   #f8eded;
$red-100:  #f2dede;
$red-200:  #e4bebe;
$red-300:  #c89a9a;
$red-400:  #aa2e26;
$red-500:  #8e2e2a;
$red-600:  #712e2e;
$red-700:  #692727;
$red-800:  #621f1f;
$red-900:  #5a1818;

// ==================================================
// Blue Scale
// ==================================================
$blue-50:   #ebf1f7;
$blue-100:  #d7e3ee;
$blue-200:  #b4c9dd;
$blue-300:  #7fa7c5;
$blue-400:  #2f5c84;
$blue-500:  #2a5275;
$blue-600:  #244766;
$blue-700:  #21405c;
$blue-800:  #1d3a53;
$blue-900:  #1a3349;

// ==================================================
// Gold Scale
// ==================================================
$gold-50:   #f7f3eb;
$gold-100:  #f2ece2;
$gold-200:  #cbbfa8;
$gold-300:  #8e837a;
$gold-400:  #6e655e;
$gold-500:  #5f574f;
$gold-600:  #504940;
$gold-700:  #484137;
$gold-800:  #40382f;
$gold-900:  #383026;

// ==================================================
// Green Scale
// ==================================================
$green-50:   #e9f4ec;
$green-100:  #d3e9db;
$green-200:  #abd4b7;
$green-300:  #7fbd93;
$green-400:  #43a047;
$green-500:  #398d3e;
$green-600:  #2f7a36;
$green-700:  #296b2f;
$green-800:  #245d29;
$green-900:  #1e4e22;

// ==================================================
// Yellow Scale
// ==================================================
$yellow-50:   #fff7e8;
$yellow-100:  #ffefcf;
$yellow-200:  #ffe1a3;
$yellow-300:  #ffd36f;
$yellow-400:  #f9a825;
$yellow-500:  #e29a12;
$yellow-600:  #cc8c00;
$yellow-700:  #b67c00;
$yellow-800:  #a06d00;
$yellow-900:  #8a5d00;

primitives-font-weight(太さの素材トークン)

フォントの太さを数値(400/600/700など)で一元管理するプリミティブ層です。ここでは regular / semibold / bold のような素材トークンと実値の対応だけを持ち、headingbody など用途ごとの割り当ては font-weight-role-map 側で行います。太さの直書きを防ぎ、サイト全体の太さ運用を最小の段階で安定させます。

// ==================================================
// Foundation: variables (Primitive Layer)
// ==================================================

// ==================================================
// Font
// ==================================================
$font-family-ja: 'Noto Sans JP', sans-serif;
$font-family-en: 'Lato', sans-serif;
$font-size-base: 16px;

primitives-shadow(影色の素材トークン)

box-shadow に使う影色の基準色($shadow-base)と、よく使う不透明度バリエーション($shadow-05〜$shadow-60)を素材としてまとめたプリミティブ層です。影の「用途(card/modalなど)」や「サイズ(sm/md/lg)」はここでは扱わず、shadow-mapelevation-map 側でこの素材を参照して影を組み立てます。

// ==================================================
// Foundation: primitives-font-weight (Primitives)
// 重さの唯一ソース(最小運用:3段)
// - regular: 本文
// - semibold: 強調 / UI
// - bold: 見出し
// ==================================================

$font-weight-map: (
  'regular': 400,
  'semibold': 600,
  'bold': 700,
);

primitives-space(余白スケールの素材トークン)

余白の共通スケール(none / xs〜7xl)を、ブレークポイント(xs/sm/md/lg/xl)ごとのレスポンシブ値として定義するプリミティブ層です。ここは「段階そのもの(スケール)」だけを持ち、container-inlinebutton-inline などの用途別キーは space-map 側で管理します。余白の基準を一箇所に集約することで、全体の“間”の調整がしやすくなります。

@use '../core/function' as *;

// ==================================================
// Foundation: primitives-space
// Token Type: Scale(段階) / Mixed: No
// Source: rem()(core/function)
// --------------------------------------------------
// Purpose: 余白の共通スケール(none / xs〜7xl)をレスポンシブ値で定義
// Keys: none, xs, sm, md, lg, xl, 2xl...7xl × (xs/sm/md/lg/xl)
// Notes: 用途別(container/button...)は maps 側で管理する
// ==================================================

$space-scale-map: (
  'none': (
    'xs': rem(0),
    'sm': rem(0),
    'md': rem(0),
    'lg': rem(0),
    'xl': rem(0),
  ),

  'xs': (
    'xs': rem(4),
    'sm': rem(4),
    'md': rem(8),
    'lg': rem(8),
    'xl': rem(8),
  ),

  'sm': (
    'xs': rem(8),
    'sm': rem(8),
    'md': rem(8),
    'lg': rem(16),
    'xl': rem(16),
  ),

  'md': (
    'xs': rem(8),
    'sm': rem(16),
    'md': rem(16),
    'lg': rem(24),
    'xl': rem(32),
  ),

  'lg': (
    'xs': rem(16),
    'sm': rem(24),
    'md': rem(32),
    'lg': rem(32),
    'xl': rem(40),
  ),

  'xl': (
    'xs': rem(24),
    'sm': rem(32),
    'md': rem(40),
    'lg': rem(48),
    'xl': rem(56),
  ),

  '2xl': (
    'xs': rem(32),
    'sm': rem(40),
    'md': rem(48),
    'lg': rem(64),
    'xl': rem(72),
  ),

  '3xl': (
    'xs': rem(40),
    'sm': rem(48),
    'md': rem(64),
    'lg': rem(72),
    'xl': rem(88),
  ),

  '4xl': (
    'xs': rem(64),
    'sm': rem(64),
    'md': rem(80),
    'lg': rem(96),
    'xl': rem(112),
  ),

  '5xl': (
    'xs': rem(80),
    'sm': rem(80),
    'md': rem(96),
    'lg': rem(120),
    'xl': rem(144),
  ),

  '6xl': (
    'xs': rem(96),
    'sm': rem(96),
    'md': rem(120),
    'lg': rem(144),
    'xl': rem(168),
  ),

  '7xl': (
    'xs': rem(120),
    'sm': rem(120),
    'md': rem(160),
    'lg': rem(192),
    'xl': rem(216),
  ),
);

primitives-shadow(影色の素材トークン)

box-shadow に使う影色の基準色($shadow-base)と、よく使う不透明度バリエーション($shadow-05〜$shadow-60)を素材としてまとめたプリミティブ層です。影の「用途(card/modalなど)」や「サイズ(sm/md/lg)」はここでは扱わず、shadow-mapelevation-map 側でこの素材を参照して影を組み立てます。

@use '../primitives/primitives-color' as *;

// ==================================================
// Foundation: primitives-shadow
// Token Type: Primitives / Mixed: No
// Source: primitives-color(実値の唯一ソース)
// --------------------------------------------------
// Purpose: 影色(ベース)と不透明度バリエーション(素材)を提供する
// Keys: $shadow-base, $shadow-05..$shadow-60
// Notes: semantic(用途)や scale(sm/md/lg)は扱わない
// ==================================================

// Figma: ds/primitives/black (inverse) に対応(影の基準色)
$shadow-base: $black;

// 透明度付きシャドウカラー(プリミティブ)
$shadow-05: rgba($shadow-base, 0.05);
$shadow-07: rgba($shadow-base, 0.07);
$shadow-09: rgba($shadow-base, 0.09);
$shadow-10: rgba($shadow-base, 0.10);
$shadow-12: rgba($shadow-base, 0.12);
$shadow-13: rgba($shadow-base, 0.13);
$shadow-16: rgba($shadow-base, 0.16);
$shadow-18: rgba($shadow-base, 0.18);
$shadow-22: rgba($shadow-base, 0.22);
$shadow-60: rgba($shadow-base, 0.60);

primitives-transition(動きの素材トークン)

transition の基本パラメータである duration(速さ)easing(曲線) を、実値の唯一ソースとして定義するプリミティブ層です。ここでは fast/normal/slowout/in-out/linear の“素材”だけを持ち、ボタン・カードなど用途別の動きプリセット(hover/active で何をどう変えるか)は transition-map 側で組み立てます。これにより、サイト全体の“動きの気配”を一貫させつつ、調整も一箇所で済みます。

// ==================================================
// Foundation: primitives-transition
// Token Type: Scale(段階) / Mixed: No
// Source: none(実値の唯一ソース)
// --------------------------------------------------
// Purpose: transition の基本パラメータ(duration / easing)を提供する
// Keys: $transition-duration-map / $transition-easing-map
// Notes: preset(用途)は扱わない
// ==================================================

$transition-duration-map: (
  'fast': 0.24s,
  'normal': 0.5s,
  'slow': 1s,
);

$transition-easing-map: (
  'out': cubic-bezier(0.16, 1, 0.3, 1),
  'in-out': cubic-bezier(0.65, 0, 0.35, 1),
  'linear': linear,
);

プリミティブトークンは以上です!
次回はマップトークンの紹介です。

今回は以上です!