样式系统
配方(Recipes)
使用配方在 Chakra 中编写多变体样式。
概述
Chakra 提供了一种编写 CSS-in-JS 的方式,具备更佳的性能、开发者体验和可组合性。其关键 特性之一是通过类型安全的运行时 API 创建多变体样式。
一个配方包含以下属性:
className:附加到组件上的 classNamebase:组件的基础样式variants:组件的不同样式变体compoundVariants:多个变体的不同组合defaultVariants:组件的默认变体取值
定义配方
使用 defineRecipe 标识函数创建配方。
import { defineRecipe } from "@chakra-ui/react"
export const buttonRecipe = defineRecipe({
base: {
display: "flex",
},
variants: {
variant: {
solid: { bg: "red.200", color: "white" },
outline: { borderWidth: "1px", borderColor: "red.200" },
},
size: {
sm: { padding: "4", fontSize: "12px" },
lg: { padding: "8", fontSize: "24px" },
},
},
})使用配方
在组件中使用配方的两种方式:
- 直接在组件中使用
useRecipe - 使用
chakra工厂创建组件(推荐)
useContext 和 useInsertionEffect 等 React Hooks,需要添加 "use client" 指令。直接在组件中使用
使用 useRecipe Hook 获取组件的配方。然后,用它的变体属性调用该 配方即可得到样式。
"use client"
import { chakra, useRecipe } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"
export const Button = (props) => {
const { variant, size, ...restProps } = props
const recipe = useRecipe({ recipe: buttonRecipe })
const styles = recipe({ variant, size })
return <chakra.button css={styles} {...restProps} />
}splitVariantProps
注意你是如何将 variant 和 size 属性从 props 中解构出来并传入配方的。更聪明的做法是用 recipe.splitVariantProps 函数自动将配方属性从组件属性中拆分开。
"use client"
import { chakra, useRecipe } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"
export const Button = (props) => {
const recipe = useRecipe({ recipe: buttonRecipe })
const [recipeProps, restProps] = recipe.splitVariantProps(props)
const styles = recipe(recipeProps)
// ...
}TypeScript
使用 RecipeVariantProps 类型辅助函数来推断配方的变体属性类型。
import type { RecipeVariantProps } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"
type ButtonVariantProps = RecipeVariantProps<typeof buttonRecipe>
export interface ButtonProps extends React.PropsWithChildren<ButtonVariantProps> {}创建组件
使用 chakra 函数从配方创建组件。
chakra 函数中。"use client"
import { chakra } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"
export const Button = chakra("button", buttonRecipe)接下来,使用该组件并向其传递配方属性:
import { Button } from "./button"
const App = () => {
return (
<Button variant="solid" size="lg">
Click Me
</Button>
)
}默认变体
defaultVariants 属性用于设置配方的默认变体取值。当你希望默认 应用某个变体时,这会很有用。
"use client"
import { chakra } from "@chakra-ui/react"
const Button = chakra("button", {
base: {
display: "flex",
},
variants: {
variant: {
solid: { bg: "red.200", color: "white" },
outline: { borderWidth: "1px", borderColor: "red.200" },
},
size: {
sm: { padding: "4", fontSize: "12px" },
lg: { padding: "8", fontSize: "24px" },
},
},
defaultVariants: {
variant: "solid",
size: "lg",
},
})复合变体
使用 compoundVariants 属性定义一组变体,它们会根据其他变体的组合 而被应用。
"use client"
import { chakra } from "@chakra-ui/react"
const button = cva({
base: {
display: "flex",
},
variants: {
variant: {
solid: { bg: "red.200", color: "white" },
outline: { borderWidth: "1px", borderColor: "red.200" },
},
size: {
sm: { padding: "4", fontSize: "12px" },
lg: { padding: "8", fontSize: "24px" },
},
},
compoundVariants: [
{
size: "small",
variant: "outline",
css: {
borderWidth: "2px",
},
},
],
})当你同时使用 size="small" 和 variant="outline" 时,compoundVariants 会将 css 属性应用到组件上。
<Button size="small" variant="outline">
Click Me
</Button>注意事项
由于设计约束,compoundVariants 无法与响应式值配合使用。
这意味着如下代码不会生效:
<Button size={{ base: "sm", md: "lg" }} variant="outline">
Click Me
</Button>对于这种情况,我们建议渲染多个不同断点下的组件版本,再根据需求进行显示/隐藏。
使用语义化令牌
主题中的语义化令牌可以直接用于配方中,通过名称引用即可。
import { defineRecipe } from "@chakra-ui/react"
export const buttonRecipe = defineRecipe({
base: {
bg: "bg.muted", // 语义化令牌
color: "fg", // 语义化令牌
borderRadius: "l2", // 语义化圆角
},
variants: {
variant: {
primary: {
bg: "colorPalette.solid", // 虚拟颜色
color: "colorPalette.contrast",
},
},
},
})常用令牌:bg、fg、 border、colorPalette.*
在主题中使用
要以可复用的方式使用配方,请将它移入系统主题,并添加到 theme.recipes 属性中。
import { createSystem, defaultConfig, defineConfig } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"
const config = defineConfig({
theme: {
recipes: {
button: buttonRecipe,
},
},
})
export default createSystem(defaultConfig, config)TypeScript
使用 CLI 为配方生成类型,然后在组件中导入它们。关于如何在 postinstall、CI 和 monorepo 中运行 typegen,参见 CLI 文档。
npx @chakra-ui/cli typegen ./theme.ts然后,在组件中导入生成的类型:
import type { RecipeVariantProps } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"
type ButtonVariantProps = RecipeVariantProps<typeof buttonRecipe>
export interface ButtonProps extends React.PropsWithChildren<ButtonVariantProps> {}更新代码
如果你直接在组件中使用配方,请更新 useRecipe,改用 key 属性从主题中获取配方。
const Button = () => {
- const recipe = useRecipe({ recipe: buttonRecipe })
+ const recipe = useRecipe({ key: "button" })
// ...
}