Figmaの「Styles」と「Variables」の境界線:大規模デザインシステムにおけるトークン駆動アーキテクチャの極意
デザインシステムの黎明期、私たちはFigmaの「Styles(Color Styles, Text Styles等)」というプリミティブな抽象化層に救われていた。しかし、数千のコンポーネント、マルチブランド、ダークモード、そしてエンジニアリング領域のデザイン・トークン(Design Tokens)との完全な同期が求められる昨今、Styles単体での運用は限界を迎えている。
Figmaに「Variables(変数)」が導入されたことにより、私たちは真の意味で「コードとデザインのデータモデルの統一」に到達した。だが、ここで多くのプロダクトチームが混乱に陥る。
「どこまでをStylesで維持し、どこからをVariablesに移行すべきなのか?」
本稿では、UI/UXエンジニアおよびデザインシステム・アーキテクトに向けて、両者の内部アーキテクチャ、メモリフットプリント、そしてAPI/CLIを用いた完全自動化パイプラインの構築に至るまで、骨の髄までしゃぶり尽くす極限の知見を共有する。
—
1. 内部アーキテクチャと機能的境界線の解剖学
まず、Figmaのエンジン内部でStylesとVariablesがどのように処理されているかを理解する必要がある。ここを誤ると、大規模プロジェクトにおいてレンダリングパフォーマンスの劣化やメモリリークを誘発する。
Styles(スタイル)の正体
Stylesは、特定のプロパティセット(塗り、境界線、効果、タイポグラフィ)への「ポインタ(参照)」である。
- 特性: 静的であり、コンテキスト(モードやテーマ)を持たない。
- メモリフットプリント: 比較的軽量だが、タイポグラフィースタイルなどはFont Family、Weight、Line Heightなどの複合データを持つため、ノードツリーが巨大化するとパースコストが微増する。
- 限界: 「Dark ModeだからこのColor Styleの参照先を自動で切り替える」といった動的なコンテキストスイッチングができない(レイヤー側でのオーバーライドやセクションごとのテーマ適用が必要)。
Variables(変数)の正体
Variablesは、プリミティブな値(Color, Number, String, Boolean)を抽象化した「トークン・ストア」であり、モード(Modes)という多次元のマトリクスを持つ。
- 特性: 動的であり、スコープ(用途制限)とコレクション、そしてモードによる値のスイッチングが可能。
- メモリフットプリント: コレクションとモードの組み合わせ(マトリクス)が爆発的に増加すると、Figmaのドキュメントロード時の初期化フェーズにおけるJSONパースおよびメモリ消費量に直結する。
- 真髄: エンジニアリング側のW3C Design Tokens Format(JSON)と1:1でマッピングできる唯一のデータ構造。
—
2. 境界線の設計基準:どちらをどこに割り振るべきか?
「すべてをVariablesに置き換えればいい」という短絡的な思考は、デザインシステムのパフォーマンスとメンテナンス性を破綻させる。以下のマトリクスに基づき、厳格な境界線を引け。
| プロパティ / ユースケース | 推奨仕様 | 判断理由とアーキテクチャ上の根拠 |
| :— | :— | :— |
| カラー(背景、表面、ボーダー) | Variables | モード(Light/Dark)による動的切り替えが必須なため。Alias(参照)構造を作りやすいため。 |
| タイポグラフィ(フォント、サイズ等) | Styles | 現状のFigmaにおいて、Variablesはフォントファミリーや複合的なプロパティ(Font Weight, Line Height等)を一つの変数として束ねる「Typography Token」をネイティブサポートしていないため。(※部分的なNumber変数での制御は破綻の元) |
| スペーシング・レイアウト(Padding等) | Variables | プレミティブな数値(`spacing/4` = `16px`など)として定義し、レスポンシブや密度(Compact/Comfortable)のモード切替に直結させるため。 |
| シャドウ・エフェクト(Drop Shadow等) | Styles / Variables(ハイブリッド) | エフェクトプロパティ自体はStylesで保持しつつ、その中の「Color」や「Blurの数値」の部分のみをVariablesで駆動させる。 |
黄金律:カラーと数値はVariables、複合プロパティはStyles
タイポグラフィのように複数のCSSプロパティ(`font-family`, `font-size`, `line-height`, `letter-spacing`)が絡み合うものは、現在のFigmaの仕様上、Text Styleとして定義し、その内部の色やサイズの一部にVariablesを紐付ける、あるいはスタイル自体をコード側のCSS/Tailwindトークンと命名規則で完全に同期させるアプローチを取るのが最も堅牢である。
—
3. 既存デザインファイルのエグゼキューション:移行戦略と自動化
手動で数千のレイヤーのColor StyleをVariablesに置き換える? それはエンジニアの仕事ではない。人間の手作業は必ずヒューマンエラーを生む。
Figma Plugin APIおよびREST API / CLIを駆使し、完全にプログラム制御された移行パイプラインを構築せよ。
以下は、既存のColor Styleをスキャンし、対応するVariables(Primitives → Semantic構造)へとマッピング・置換するためのTypeScriptによるFigmaプラグインのコアロジックである。
自動移行スクリプト(Figma Plugin API)
/
- Figma Plugin: Styles to Variables Migration Engine
- 既存のColor Styleを走査し、対応するSemantic Variablesへ安全にバインドし直す
/
interface ColorMapping {
styleName: string;
variableName: string;
}
// 事前に定義されたマッピングテーブル(実際はJSON等からロード)
const migrationMap: ColorMapping[] = [
{ styleName: “color/primary/main”, variableName: “semantic/primary/default” },
{ styleName: “color/surface/background”, variableName: “semantic/bg/canvas” },
];
async function migrateStylesToVariables() {
// 1. ローカルのColor Stylesを取得
const localStyles = figma.getLocalPaintStyles();
// 2. ローカルのVariables(コレクション)を取得
const variableCollections = await figma.variables.getLocalVariableCollectionsAsync();
const targetCollection = variableCollections.find(c => c.name === “Semantic Tokens”);
if (!targetCollection) {
figma.notify(“Error: ‘Semantic Tokens’ collection not found.”, { error: true });
return;
}
const localVariables = await figma.variables.getLocalVariablesAsync();
// 3. ドキュメント内の全ノードを走査し、StyleIdをVariableのバインドへ置換
const nodes = figma.currentPage.findAll(node => ‘fillStyleId’ in node || ‘strokeStyleId’ in node);
let migratedCount = 0;
for (const node of nodes) {
// Fillの移行処理
if (‘fillStyleId’ in node && typeof node.fillStyleId === ‘string’ && node.fillStyleId !== figma.mixed) {
const style = localStyles.find(s => s.id === node.fillStyleId);
if (style) {
const mapping = migrationMap.find(m => m.styleName === style.name);
if (mapping) {
const targetVar = localVariables.find(v => v.name === mapping.variableName && v.variableCollectionId === targetCollection.id);
if (targetVar) {
// 変数をペイントにバインド
const paint = figma.variables.setBoundVariableForPaint(
{ type: ‘SOLID’, color: { r: 0, g: 0, b: 0 } }, // ダミーカラー(変数で上書きされるため何でもよい)
‘color’,
targetVar
);
node.fills = [paint];
migratedCount++;
}
}
}
}
}
figma.notify(`Migration Complete: Successfully migrated ${migratedCount} nodes to Variables.`);
}
// 実行
migrateStylesToVariables();
—
4. CI/CDパイプライン統合:Design TokensからFigma Variablesへの逆流
真のDevOps環境では、Figmaが唯一の真実のソース(Single Source of Truth)であってはならない。GitHubのコードリポジトリ(JSON)こそが真のソースであり、それをFigmaへCI/CD経由で自動同期(Sync)させるべきである。
以下は、W3C形式のデザイントークンJSONをFigma REST API経由でVariablesにインジェストするためのNode.js CLIスクリプトの概念設計だ。
/
- CLI Script: Sync W3C Design Tokens JSON to Figma Variables
- GitHub Actions等のCIパイプラインから実行され、Figma上のVariablesを自動更新する
/
import axios from ‘axios’;
const FIGMA_API_TOKEN = process.env.FIGMA_API_TOKEN;
const FIGMA_FILE_KEY = process.env.FIGMA_FILE_KEY;
interface DesignTokenJSON {
[key: string]: {
value: string;
type: string;
};
}
async function syncTokensToFigma(tokens: DesignTokenJSON) {
const endpoint = `https://api.figma.com/v1/files/${FIGMA_FILE_KEY}/variables`;
// Figma Variables REST API Payloadの構築
// ※実際のAPI仕様(POST /v1/files/:key/variables)に基づいたペイロード構成
const payload = {
variableCollections: [
{
action: “CREATE”,
id: “PrimitiveCollection”,
name: “Primitives (Synced via CI)”
}
],
variables: Object.entries(tokens).map(([key, token], index) => ({
action: “CREATE”,
id: `var_${index}`,
name: key,
variableCollectionId: “PrimitiveCollection”,
resolvedType: token.type === ‘color’ ? ‘COLOR’ : ‘FLOAT’,
valuesByMode: {
“default”: token.value
}
}))
};
try {
const response = await axios.post(endpoint, payload, {
headers: {
‘X-Figma-Token’: FIGMA_API_TOKEN,
‘Content-Type’: ‘application/json’
}
});
console.log(“Successfully synced tokens to Figma:”, response.data);
} catch (error) {
console.error(“Failed to sync tokens:”, error.response?.data || error.message);
process.exit(1);
}
}
// 実行サンプル
const sampleTokens: DesignTokenJSON = {
“color/primitive/blue/500”: { value: “#0066FF”, type: “color” },
“spacing/primitive/md”: { value: “16”, type: “dimension” }
};
// syncTokensToFigma(sampleTokens);
—
5. アーキテクトが守るべき運用上の鉄則
1. 名前空間(Namespace)の厳格化:
`primary-color`のような曖昧な命名を禁止する。必ず `primitive/color/blue/500` -> `semantic/action/primary-default` のような階層構造(Slash syntax)を強制し、Figmaとコード(TailwindやCSS Variables)の命名規則を完全一致させよ。
2. スコープ(Scopes)の活用によるポルターガイスト現象の防止:
Variablesの「Scopes」設定を適切に行い、例えばCorner Radius用の変数をColorの塗りに適用できないように制限せよ。デザイナーのヒューマンエラーをUIの制限で物理的に封じ込めるのが、真に優れたデザインシステム設計である。
3. パフォーマンス監視:
Variablesのモード数が過剰に増えると、Figmaファイルのランタイムメモリが肥大化する。マルチブランド対応において、1つのファイルにすべてのブランドのモードを詰め込むのではなく、ブランドごとにファイルを分割し、Publishされたライブラリとして参照(Library swapping)するアーキテクチャを選択せよ。
Stylesの直感性と、Variablesのプログラマビリティ。この二者の境界線を正確に見極め、コードベースと完全に同期したデザイン・インフラストラクチャを構築できたチームだけが、プロダクトのスケールとスピードのジレンマから解放される。
手を動かせ。コードを書け。デザインシステムをエンジニアリングせよ。