SuperAPI AI 工具集

Fluent UI Griffel Styling

前端与建站

查看项目

更新于 10-21 23:47

技能介绍

用途

Griffel 是 Fluent UI React v9 的样式引擎,属于原子化 CSS-in-JS 方案,用于为 Fluent UI 组件及自定义组件编写样式。它由 Fluent 团队构建,目标是解决传统 CSS-in-JS 库(styled-components、Emotion)在微软 365 规模下的性能与确定性问题。

主要能力

  • 原子 CSS 输出:每个 CSS 属性/值对生成一个可复用的类名,例如 color: 'red' 在任何位置都产生同一个原子类,样式表随应用规模呈对数增长而非线性增长。
  • AOT 零运行时:配置预编译(webpack 或 Vite 插件)后,Griffel 在构建期提取全部样式,运行时不再注入样式、管理 <style> 标签或修改 CSSOM。
  • 确定性优先级:每条规则只包含单一属性,因此不存在优先级冲突;HTML class 属性中靠后的类生效,由 mergeClasses() 负责去重。
  • 自动 RTL 翻转:集成 rtl-css-js,paddingLeft 等逻辑属性在 RTL 文档方向下自动变为 paddingRight。
  • 完整 TypeScript 支持:样式对象完全类型化,开发期即可捕获非法 CSS 属性与值。

核心包

  • @griffel/react:主运行时,提供 makeStyles、makeResetStyles、mergeClasses、shorthands。
  • @griffel/webpack-extraction-plugin:webpack 的 AOT 提取插件。
  • @griffel/vite-plugin:Vite 的 AOT 提取插件。
  • @griffel/babel-preset:AOT 用的 Babel 预设(被 webpack/Vite 插件内部使用)。
  • @griffel/core:与框架无关的核心(供非 React 场景使用)。
  • @griffel/devtools:用于检查原子类的浏览器扩展。

核心 API

makeStyles

主要样式 API,接收一个对象,每个键是命名样式槽,每个值是 CSS-in-JS 样式对象,返回一个生成类名字符串的 React hook。内部机制:调用时(或 AOT 构建时)将每个属性/值对转换为基于哈希的确定性类名;hook 返回对象,每个键映射到以空格分隔的原子类名字符串。支持的属性涵盖布局、Flexbox、Grid、盒模型、排版、视觉、边框、间距、阴影、变换、动画、溢出等标准 CSS 属性(camelCase 形式)。

makeResetStyles

创建单个非原子类,将一组样式一起应用,适用于基础/重置样式。与 makeStyles 的关键区别:makeResetStyles 输出包含全部属性的单个类,优先级低于原子化的 makeStyles 类;当 mergeClasses(baseClass, atomicStyles.variant) 合并时,原子类会覆盖重置类中的冲突属性,这是设计使然,也是推荐的组合模式。makeResetStyles 接受 CSS 简写,而 makeStyles 不接受。

shorthands

CSS 简写(如 padding: '8px 16px')无法拆分为原子类,Griffel 提供 shorthands.* 函数将其展开为长写属性。完整列表包括:border、borderLeft、borderRight、borderTop、borderBottom、borderColor、borderStyle、borderWidth、borderRadius、padding、margin、gap、overflow、flex、gridArea、inset、outline、textDecoration、transition。参数遵循 CSS 简写约定:1 个参数应用于所有边,2 个为垂直/水平,3 个为上/水平/下,4 个为上/右/下/左。

mergeClasses

用于去重与组合原子类名,是合并 Griffel 类名的唯一正确方式。它接收任意数量参数(字符串、undefined、false、null 等假值会被跳过),跟踪每个原子类对应的 CSS 属性,当两个类针对同一属性时后者胜出,返回去重后的空格分隔类名字符串。关键规则:不要用字符串拼接,始终使用 mergeClasses;每个元素只调用一次,不要嵌套;始终将外部 className prop 放在最后,以便父组件覆盖子组件样式。

九条关键规则

  1. 绝不拼接类名,始终使用 mergeClasses()。拼接会导致针对同一属性的两个原子类同时保留,最终生效者取决于样式表中的插入顺序,具有不确定性。
  2. 避免 !important。它会破坏原子 CSS 模型,无法被 mergeClasses 覆盖,阻碍组件组合与父组件定制。
  3. 使用设计令牌而非直接颜色值。硬编码颜色会破坏主题、深色模式与高对比度模式。
  4. 避免跨样式对象重复规则。同一属性/值对在多个槽中重复不会浪费 CSS 字节(是同一个原子类),但会降低代码可维护性,建议共享基础样式加变体覆盖。
  5. 每个元素只调用一次 mergeClasses。嵌套调用输出正确但浪费,应展平为单次调用。
  6. makeStyles 中不使用 CSS 简写,改用 shorthands.*。简写无法原子化,可能静默失败或产生错误输出;makeResetStyles 例外,因为它产生非原子单类。
  7. 标签选择器较慢,优先使用 className prop。避免用 > div、> span 等标签选择器,改为直接向子组件传递 className 或使用 slot 对象。

(资料在规则 7 之后截断,规则 8、9 及后续内容暂未提供。)

适用场景

  • 使用 Fluent UI React v9 构建应用,需要为组件编写样式。
  • 需要原子化 CSS 以控制样式表体积的大型应用。
  • 需要构建期提取样式、追求零运行时开销的场景。
  • 需要自动 RTL 支持、完整 TypeScript 类型检查的样式方案。
  • 同一引擎需在 SSR、SSG、CSR 下工作且不产生 hydration 不匹配的场景。

限制

  • makeStyles 中不能使用 CSS 简写,必须改用 shorthands.*。
  • 不应使用 !important,否则破坏原子模型与组合能力。
  • 不应拼接类名字符串,必须使用 mergeClasses。
  • 应避免标签选择器。
  • 资料未提供具体收费、价格、平台支持范围与性能基准数据。