fluent2-design-system について
fluent2-design-system は、@fluentui/react-components v9 を使う React 開発者向けの Fluent 2 リファレンススキルです。テーマ、トークンベースのスタイル、コンポーネント、レイアウト、アクセシビリティを扱います。
主な機能
- 01Fluent 2 と独自ブランドのテーマ
- 02Griffel のスタイルガイド
- 03デザイントークンの分類と使い方
- 04v9 のコンポーネントパターンと一覧
- 05レイアウト、タイポグラフィ、色の指針
- 06キーボードとハイコントラスト対応
活用シーン
- 01React アプリにライト、ダーク、ブランドテーマを設定
- 02デザイントークンを使ったコンポーネントのスタイル設定
- 03入力、ナビゲーション、フィードバックを含む画面の構築
- 04キーボード操作とハイコントラスト対応の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ fefogarcia/ approved-skills --skill fluent2-design-systemインストール後、Claude Code で/fluent2-design-systemを入力して読み込まれたか確認します。
同梱ファイルreferences/components.mdreferences/tokens.md
詳細
Fluent 2 デザインシステム
@fluentui/react-components(v9)を使用して、Microsoft の Fluent 2 デザインシステムに基づく本番環境品質のインターフェイスを構築します。
クイックスタート
すべての Fluent 2 React アプリでは、テーマを指定してコンポーネントツリーを囲む FluentProvider が必要です。
import {
FluentProvider,
webLightTheme,
webDarkTheme,
Button,
tokens,
makeStyles,
mergeClasses,
} from "@fluentui/react-components";
export default function App() {
return (
<FluentProvider theme={webLightTheme}>
<Button appearance="primary">Hello Fluent 2</Button>
</FluentProvider>
);
}
インストール:npm install @fluentui/react-components
コアアーキテクチャ
テーマ設定
- 組み込みテーマ:
webLightTheme、webDarkTheme、teamsLightTheme、teamsDarkTheme、teamsHighContrastTheme - カスタムブランディング:
BrandVariantsオブジェクト(キーは10~160)を指定して、createLightTheme(brandRamp)/createDarkTheme(brandRamp)を使用します - ネスト:
FluentProviderをネストして、サブツリーに異なるテーマを適用できます - テーマの値は、プロバイダー要素の CSS カスタムプロパティとして出力されます
Griffel によるスタイリング
makeStyles(@fluentui/react-components からインポート)を使用してください。トークンを使用したスタイリングでは、インラインスタイルや外部 CSS は使用しないでください。
const useStyles = makeStyles({
root: {
backgroundColor: tokens.colorNeutralBackground1,
color: tokens.colorNeutralForeground1,
display: "flex",
gap: tokens.spacingHorizontalM,
padding: tokens.spacingVerticalM,
},
active: {
backgroundColor: tokens.colorBrandBackground,
color: tokens.colorNeutralForegroundOnBrand,
},
});
function MyComponent({ isActive }) {
const styles = useStyles();
return (
<div className={mergeClasses(styles.root, isActive && styles.active)}>
Content
</div>
);
}
重要なルール:
makeStylesはコンポーネントの外(モジュールスコープ)で定義します- クラスを組み合わせるには
mergeClasses()を使用します。文字列を連結しないでください - 色、間隔、タイポグラフィ、角丸、影にはすべて
tokens.*を使用します。16進数やpxの値を直接指定しないでください - CSS のショートハンド(
border、borderRadius、paddingなど)はサポートされていません。shorthands.*ヘルパーまたはロングハンドプロパティを使用してください - 疑似セレクターにはネストしたオブジェクトを使用します:
":hover": { color: tokens.colorBrandForeground1 } - メディアクエリーにはネストしたオブジェクトを使用します:
"@media (min-width: 768px)": { flexDirection: "row" }
コンポーネントモデル
すべての v9 コンポーネントは、一貫したパターンに従います。
- スロット:名前付きのサブパーツ(例:
root、icon、content)で、プロパティまたは JSX を受け取ります - 外観のバリエーション:
"primary"、"secondary"、"subtle"、"transparent"、"outline" - サイズのバリエーション:
"small"、"medium"、"large" - 形状のバリエーション:
"rounded"、"circular"、"square"
makeStyles/mergeClasses を使って作成した className で、コンポーネントのスタイルを上書きします。
デザイントークン
トークンは、デザインの意図とコードをつなぐものです。常に tokens.* を使用し、生の値を直接指定しないでください。
色、タイポグラフィ、間隔、エレベーション、線幅、角丸のトークン一覧については、 references/tokens.md を参照してください。
トークンカテゴリーの概要
| カテゴリー | プレフィックス | 例 |
|---|---|---|
| ニュートラルカラー | colorNeutral* | tokens.colorNeutralBackground1 |
| ブランドカラー | colorBrand* | tokens.colorBrandBackground |
| ステータスカラー | colorPalette{Color}* | tokens.colorPaletteRedForeground1 |
| タイポグラフィ | fontFamily*、fontSize*、fontWeight*、lineHeight* | tokens.fontSizeBase300 |
| 間隔 | spacingHorizontal*、spacingVertical* | tokens.spacingHorizontalM |
| 角丸 | borderRadius* | tokens.borderRadiusMedium |
| 線幅 | strokeWidth* | tokens.strokeWidthThin |
| 影 | shadow* | tokens.shadow4 |
| 継続時間 | duration* | tokens.durationNormal |
| イージング | curve* | tokens.curveEasyEase |
2層のトークンシステム
- グローバルトークン — コンテキストに依存しない生の値(例:
colorBlue60、fontSize300) - エイリアストークン — グローバルトークンに適用されるセマンティックな意味(例:
colorBrandBackground→ 青、colorNeutralForeground1→ 濃いグレー)
コードでは、tokens オブジェクトを介してエイリアストークンを使用します。
レイアウト
- グリッド:CSS Grid/Flexbox を使用します。Fluent 2 v9 には
Stackコンポーネントがありません - 間隔のスケール:基本単位は4pxです。値:
XXS(2)、XS(4)、S(8)、M(12)、L(16)、XL(20)、XXL(24)、XXXL(32) - カラムグリッド:Web では12カラムのフレームワークが推奨されます。CSS Grid を使用してください
- 配置:一貫した間隔を保つため、
tokens.spacingHorizontal*とtokens.spacingVertical*を使用します
タイポグラフィ
- プライマリ書体:Segoe UI(Web)、Segoe UI Variable(Windows)、SF Pro(macOS/iOS)、Roboto(Android)
- フォントスタック:
tokens.fontFamilyBase= Segoe UI → システムフォールバック → sans-serif - 等幅フォント:
tokens.fontFamilyMonospace - テキストプリセット:プリセットバリアント(
Caption1、Body1、Body1Strong、Subtitle1、Subtitle2、Title1、Title2、Title3、LargeTitle、Display)を指定して、<Text>コンポーネントを使用します - 配置:LTR では左揃えにします。Fluent は Griffel によって RTL を自動的に処理します
カラーシステム
3 つのパレットがあります。
- ニュートラル — サーフェス、テキスト、レイアウトに使用する黒、白、グレー
- ブランド — ブランドのアイデンティティを強調するアクセントカラー(Microsoft のデフォルトのブランドカラーは青)
- 共通/ステータス — 製品間で共通のカラー:赤(危険)、緑(成功)、黄(警告)、青(情報)
インタラクション状態:通常 → ホバー(より濃い色)→ 押下(最も濃い色)。フォーカス時は色を変えず、より太いストロークを追加します。
アクセシビリティ
- すべてのコンポーネントに、ARIA ロール、キーボードナビゲーション(Tabster 経由)、フォーカス管理が含まれます
- ハイコントラスト:
teamsHighContrastThemeを使用するか、システムカラー(ButtonText、Highlightなど)を使って@media (forced-colors: active)を処理します - フォーカスインジケーターはデフォルトで表示されます。削除しないでください
- セマンティックトークンの組み合わせ(例:
colorNeutralBackground1上のcolorNeutralForeground1)を使って、WCAG のコントラスト要件を満たしてください
コンポーネント一覧
使用上の注意を含む、カテゴリ別の全コンポーネント一覧については、 references/components.md を参照してください。
よく使われるコンポーネント
アクション:Button、CompoundButton、SplitButton、ToggleButton、MenuButton、Link 入力:Input、Textarea、Select、Combobox、Dropdown、Checkbox、RadioGroup、Switch、Slider、SpinButton、DatePicker、TimePicker レイアウト:Card、Divider、Drawer、Dialog、Popover、Tooltip データ表示:Table、DataGrid、Tree、Accordion、Badge、Avatar、AvatarGroup、Tag、Persona ナビゲーション:TabList、Breadcrumb、Nav(プレビュー) フィードバック:Toast、MessageBar、ProgressBar、Spinner、Skeleton サーフェス:Menu、Toolbar、Overflow
一般的なパターン
アプリシェルのレイアウト
const useStyles = makeStyles({
app: {
backgroundColor: tokens.colorNeutralBackground1,
display: "grid",
gridTemplateColumns: "1fr",
gridTemplateRows: "auto 1fr auto",
height: "100vh",
width: "100%",
},
header: {
borderBottom: `${tokens.strokeWidthThin} solid ${tokens.colorNeutralStroke1}`,
paddingTop: tokens.spacingVerticalS,
paddingBottom: tokens.spacingVerticalS,
paddingLeft: tokens.spacingHorizontalM,
paddingRight: tokens.spacingHorizontalM,
},
content: {
display: "grid",
gridTemplateColumns: "280px 1fr",
overflow: "hidden",
},
nav: {
borderRight: `${tokens.strokeWidthThin} solid ${tokens.colorNeutralStroke1}`,
overflowY: "auto",
},
main: {
overflowY: "auto",
paddingLeft: tokens.spacingHorizontalL,
paddingRight: tokens.spacingHorizontalL,
paddingTop: tokens.spacingVerticalL,
paddingBottom: tokens.spacingVerticalL,
},
});
カスタムブランドテーマ
import { createLightTheme, createDarkTheme } from "@fluentui/react-components";
const myBrand = {
10: "#020305", 20: "#111723", 30: "#16263D",
40: "#193253", 50: "#1B3F6A", 60: "#1B4C82",
70: "#18599B", 80: "#1267B4", 90: "#3174C2",
100: "#4F82C8", 110: "#6790CF", 120: "#7F9ED5",
130: "#96ADDC", 140: "#ADBCE3", 150: "#C4CBE9",
160: "#DBDBF0",
};
const lightTheme = createLightTheme(myBrand);
const darkTheme = createDarkTheme(myBrand);
ダークモードの切り替え
function App() {
const [isDark, setIsDark] = useState(false);
return (
<FluentProvider theme={isDark ? webDarkTheme : webLightTheme}>
<Switch
label="Dark mode"
checked={isDark}
onChange={(_, data) => setIsDark(data.checked)}
/>
</FluentProvider>
);
}
アンチパターン
- ❌ 色のハードコード(
color: "#333")—tokens.colorNeutralForeground1を使用してください - ❌
makeStylesでの CSS の短縮プロパティ(border: "1px solid red")— ロングハンドまたはshorthands.*を使用してください - ❌ classNames の文字列連結 —
mergeClasses()を使用してください - ❌ トークンベースの値にインラインの
styleプロパティを使用する —tokensを指定したmakeStylesを使用してください - ❌ v9 プロジェクトで
@fluentui/react(v8)からインポートする —@fluentui/react-componentsを使用してください - ❌ v8 の
Stackを使用する — CSS Grid または Flexbox を使用してください - ❌ CSS でカラーシステムの CSS カスタムプロパティを直接オーバーライドする — アダプティブカラーシステムは JS によって制御されます
- ❌ フォーカスインジケーターを削除する — アクセシビリティ要件です