目录

CSS-Class-Variance-Authority-CSS-类名管理工具库

【CSS 】Class Variance Authority CSS 类名管理工具库

1.背景、什么是 CVA?

  1. Class Variance Authority (CVA) 是一个用于管理 CSS 类名 的工具库,特别适合在 ReactVue 等前端框架中使用。
  2. 它可以帮助你更轻松地处理组件的 样式变体 (Variants),比如按钮的不同状态( primary、secondary、disabled 等)。
  3. 它非常契合像 Tailwind CSS 这类的原子化思想。

2. CVA 的主要功能和特点?

  1. 结构化样式管理 :CVA提供了一种结构化的方式来管理样式变体,减少了全局样式冲突的可能性。它允许开发者以声明的方式描述每个参数值的样式,从而自动找出正确的样式组合。
  2. 方便样式复用和扩展 :当需要添加新的样式变体时,CVA使得扩展变得更加方便和高效。开发者可以通过定义variants、compoundVariants和defaultVariants等参数,来轻松创建可复用的样式组合。
  3. 减少样式冲突 :由于CVA采用了结构化的样式管理方式,因此可以大大减少样式冲突的可能性。这使得在大型项目中维护样式变得更加容易。

3. CVA 的使用场景

  1. CVA 特别适用于使用 Tailwind CSS 等原子化 CSS 框架的项目。
  2. 在这些项目中,开发者通常需要根据组件的 props 值将 Tailwind 类组合在一起,以创建可重用的 UI 元素。
  3. 然而,随着组件样式的增加,这种组合方式可能会变得非常复杂。通过引入 CVA,开发者可以消除这种复杂性,并以声明的方式描述每个参数值的样式。

4.如何在项目中使用 CVA

4.1安装

你可以通过 npmpnpm 安装 CVA

npm install class-variance-authority

或者

pnpm add class-variance-authority

4.2 CVA 函数参数

  1. 基础类名(Base Classes)
    1. 参数形式 :通常是一个数组(也可以是一个用空格分割的字符串),包含一组基础的 CSS 类名。
      1. [‘pl-2’, ‘pt-1’]
      2. ‘pl-2 pt-1’
    2. 作用 :这些基础类名会被应用到所有生成的样式类名组合中,作为样式的基础部分。它们不是“默认值”意义上的参数,而是函数调用的必需部分。
  2. 变体定义( Variants Definitions
    1. 参数形式 :一个对象,其键是变体属性的名称,值通常是一个对象,该对象定义了不同属性值对应的CSS类名数组。
    2. 作用 :变体定义用于指定不同属性组合下的样式变化。这里的对象不是“第二个值”的固定形式,而是变体定义的一种常见结构。
  3. 其他可选参数
    1. 复合变体( Compound Variants :一个对象,定义了当多个变体属性同时满足特定条件时应用的额外CSS类名。
    2. 默认变体( Default Variants :一个数组或者是一个字符串,指定了当没有提供特定变体属性值时应使用的默认值。

4.3 定义 CVA 函数

4.3.1 基础使用

以下是一个简单的示例,展示如何使用 CVA 创建一个带有变体的按钮组件。

4.3.1.1 第一步

button.tsx

import React from "react";
import { cva } from "class-variance-authority";

export type ButtonProps = {
    intent: "primary" | "secondary" | "danger";
    size: "small" | "medium" | "large";
    children: React.ReactNode;
}

/** 
 * 定义样式变体 buttonVariants
 *  cva:核心函数,用于定义样式变体。
 *  variants:定义组件的变体(如 intent 和 size)。
 *  defaultVariants:设置默认的变体值。
*/
const buttonVariants = cva("button", {
    variants: {
        intent: {
            primary: "bg-blue-500 text-white",
            secondary: "bg-gray-500 text-white",
            danger: "bg-red-500 text-white",
        },
        size: {
            small: "text-sm py-1 px-2",
            medium: "text-base py-2 px-4",
            large: "text-lg py-3 px-6",
        },
    },
    defaultVariants: {
        intent: "primary",
        size: "medium",
    },
});

/** 
 * 按钮组件 
 *  buttonVariants({ intent, size }):根据传入的 intent 和 size 动态生成类名。
*/
const Button = ({ intent, size, children }: ButtonProps) => {
    return (
        <button className={buttonVariants({ intent, size })}>
            {children}
        </button>
    );
};

export default Button;

4.3.2.1.2 第二步 使用 botton 按钮

根据传入的 intent 和 size 动态生成类名。

import Button from './botton.tsx'

function App() {
  return (
    <div>
      {/* button bg-blue-500 text-white text-base py-2 px-4 */}
      <Button intent="primary" size="medium">Primary Button</Button>
      {/* button bg-gray-500 text-white text-sm py-1 px-2500 */}
      <Button intent="secondary" size="small">Secondary Button</Button>
      {/* 样式为: button bg-red-500 text-white text-lg py-3 px-6 */}
      <Button intent="danger" size="large">Danger Button</Button>
    </div>
  );
}

export default App;
4.3.1.2 高级用法
4.3.1.2.1 第一步: 复合变体, 你可以定义多个变体的组合!

button.tsx

import React from "react";
import { cva } from "class-variance-authority";

export type ButtonProps = {
    intent: "primary" | "secondary"
    disabled: boolean
    children: React.ReactNode
}

/** 
 * 定义样式变体 
 *  cva 第一个参数:"button" 是基础类名,用于定义组件的默认样式(如果有多个用空格分即可)。
 *  variants:定义组件的变体(如 intent 和 size)。
 *  defaultVariants:设置默认的变体值。
 *  compoundVariants:用于定义多个变体的组合样式。   
*/

const buttonVariants = cva("button", {
    variants: {
        intent: {
            primary: "bg-blue-500 text-white",
            secondary: "bg-gray-500 text-white",
        },
        outlined: {
            true: "border-2",
        },
    },
    compoundVariants: [
        {
            intent: "primary",
            outlined: false,
            class: "border-blue-500",
        },
        {
            intent: "secondary",
            outlined: false,
            class: "border-gray-500",
        },
    ],
});

/** 
 * 按钮组件 
 *  buttonVariants({ intent, disabled }):根据传入的 intent 和 size 动态生成类名。
 *  当 intent="secondary" 时,disabled=false 时, 它会添加 border-gray-500 类名到结果数组中; 
*/

const Button = ({ intent, disabled }: ButtonProps) => {
    return (
        <button
            className={buttonVariants({
                intent,
                outlined: disabled,
            })}
        >
            Click Me
        </button>
    );
};

export default Button;
4.3.1.2.2 第二步

根据传入的 intent 和 disabled动态生成类名。

import Button from './botton.tsx'

function App() {
  return (
    <div>
      {/* 
        当 intent="secondary" 时,disabled=true 时,样式为:
         button bg-blue-500 text-white border-2 
      */}
      <Button intent="primary" disabled>Primary Button</Button>
      {/* 
        当 intent="secondary" 时,disabled=false 时,样式为:
          button bg-gray-500 text-white border-gray-500 
      */}
      <Button intent="secondary"disabled={false}>Secondary Button</Button>
    </div>
  );
}

export default App;

5. 优点

  1. 声明式 API :通过 variantsdefaultVariants 定义样式,代码更清晰。
  2. 类型安全 :如果你使用 TypeScript,CVA 可以提供完整的类型推断。
  3. 灵活性 :支持复合变体和动态类名,适合复杂的 UI 组件。

6. 总结

  1. Class Variance Authority (CVA) 是一个强大的工具,特别适合管理组件的样式变体。
  2. 它可以帮助你减少重复代码,提高开发效率。
  3. 如果你正在构建一个需要多种样式变体的组件库,CVA 是一个非常好的选择!
  4. 如果你有更多问题,欢迎随时问我!😊