关于 fluent2-design-system
fluent2-design-system 是面向 React 开发者的 Fluent 2 设计系统技能,涵盖 @fluentui/react-components v9 的组件、主题与样式规范。它强调使用设计令牌构建一致且可访问的界面。
主要功能
- 01Fluent 2 主题与自定义品牌
- 02基于 Griffel 的样式指南
- 03设计令牌分类与用法
- 04v9 组件模式与常用组件
- 05布局、排版与颜色规范
- 06键盘与高对比度无障碍指南
适用场景
- 01为 React 应用设置浅色、深色或品牌主题
- 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 设计系统
使用 Microsoft 的 Fluent 2 设计系统和 @fluentui/react-components(v9)构建可用于生产环境的界面。
快速开始
每个 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 - 自定义品牌:使用
createLightTheme(brandRamp)/createDarkTheme(brandRamp),并传入BrandVariants对象(键为10–160) - 嵌套:
FluentProvider可以嵌套,以便为子树应用不同主题 - 主题值会作为 CSS 自定义属性输出到 provider 元素上
使用 Griffel 进行样式设置
使用 makeStyles(来自 @fluentui/react-components)——需要支持 token 的样式设置时,切勿使用内联样式或外部 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.*——切勿硬编码十六进制或 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"
通过 className 配合 makeStyles/mergeClasses 覆盖组件样式。
设计 Token
Token 是设计意图与代码之间的桥梁。始终使用 tokens.*——切勿使用原始值。
完整的 Token 参考表(颜色、排版、间距、标高、描边、圆角)请参见 references/tokens.md。
Token 类别一览
| 类别 | 前缀 | 示例 |
|---|---|---|
| 中性色 | 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 |
双层 Token 系统
- 全局 Token — 与上下文无关的原始值(例如
colorBlue60、fontSize300) - 别名 Token — 应用于全局 Token 的语义含义(例如
colorBrandBackground→ 蓝色,colorNeutralForeground1→ 深灰色)
在代码中,通过 tokens 对象使用别名 Token。
布局
- 网格:使用 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 - 文本预设:使用带有预设变体的
<Text>组件 —Caption1、Body1、Body1Strong、Subtitle1、Subtitle2、Title1、Title2、Title3、LargeTitle、Display - 对齐方式:LTR 使用左对齐;Fluent 通过 Griffel 自动处理 RTL
颜色系统
三种调色板:
- 中性色 — 黑色、白色和灰色,用于表面、文本和布局
- 品牌色 — 强调色,用于强化品牌标识(Microsoft 的默认品牌色为蓝色)
- 共享色/状态色 — 跨产品使用的颜色:红色(危险)、绿色(成功)、黄色(警告)、蓝色(信息)
交互状态:常态 → 悬停(更深)→ 按下(最深)。焦点状态会增加描边粗细,而不是改变颜色。
无障碍访问
- 所有组件均包含 ARIA 角色、键盘导航(通过 Tabster)和焦点管理
- 高对比度:使用
teamsHighContrastTheme,或通过系统颜色(ButtonText、Highlight等)处理@media (forced-colors: active) - 默认情况下焦点指示器可见 — 切勿移除
- 通过语义化令牌配对确保符合 WCAG 对比度要求(例如,在
colorNeutralBackground1上使用colorNeutralForeground1)
组件清单
完整的分类组件列表及使用说明,请参阅 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属性 — 使用makeStyles和tokens - ❌ 在 v9 项目中从
@fluentui/react(v8)导入 — 使用@fluentui/react-components - ❌ 使用 v8
Stack— 使用 CSS Grid 或 Flexbox - ❌ 直接在 CSS 中覆盖颜色系统的 CSS 自定义属性 — 自适应颜色系统由 JS 驱动
- ❌ 移除焦点指示器 — 这是无障碍访问要求