首页
/ Ant Design Button 的 color 与 variant 属性:构建颜色 × 变体矩阵式按钮体系

Ant Design Button 的 color 与 variant 属性:构建颜色 × 变体矩阵式按钮体系

2026-09-06 16:08:25作者:宣聪麟

在 Ant Design 中,Button 组件从 5.21.0 开始引入了 colorvariant 两个正交属性,取代了过去单一的 type 属性。本文以官方案例 颜色与变体 为主体,讲解如何通过同时设置 colorvariant 衍生出完整的变体按钮矩阵,并结合 Button 组件源码样式生成逻辑 剖析这套体系背后的属性解析规则、CSS 变量机制与旧版 type 语法糖的兼容映射,帮助你在实际业务中灵活组合任意"颜色 + 变体"的按钮样式。

核心理念:同时设置 color 和 variant,衍生更多变体按钮

颜色与变体示例 的官方描述只有一句话,但信息量很大:

同时设置 colorvariant 属性,可以衍生出更多的变体按钮。

其含义是:color 决定按钮"用哪套颜色",variant 决定按钮"以什么形态呈现"(描边、填充、虚线、文本……)。两者相互正交,3 个基础色 + 13 个预设色6 种变体 自由组合,即可派生出 100 种以上按钮外观。

完整的演示代码

官方演示 color-variant.tsx 展示了 defaultprimarydangerpinkpurplecyan 六行颜色,每行遍历全部六种变体。核心代码结构如下(完整文件可直接参考 演示源码):

import React from 'react';
import { Button, ConfigProvider, Flex } from 'antd';
import { useResponsive } from 'antd-style';

const App: React.FC = () => {
  const { xxl } = useResponsive();

  return (
    // 大屏显示 medium 尺寸,小屏降级为 small,演示响应式尺寸
    <ConfigProvider componentSize={xxl ? 'medium' : 'small'}>
      <Flex vertical gap="small">
        <Flex gap="small" wrap>
          <Button color="default" variant="solid">Solid</Button>
          <Button color="default" variant="outlined">Outlined</Button>
          <Button color="default" variant="dashed">Dashed</Button>
          <Button color="default" variant="filled">Filled</Button>
          <Button color="default" variant="text">Text</Button>
          <Button color="default" variant="link">Link</Button>
        </Flex>
        <Flex gap="small" wrap>
          <Button color="primary" variant="solid">Solid</Button>
          <Button color="primary" variant="outlined">Outlined</Button>
          <Button color="primary" variant="dashed">Dashed</Button>
          <Button color="primary" variant="filled">Filled</Button>
          <Button color="primary" variant="text">Text</Button>
          <Button color="primary" variant="link">Link</Button>
        </Flex>
        <Flex gap="small" wrap>
          <Button color="danger" variant="solid">Solid</Button>
          {/* danger 的 outlined / dashed / filled / text / link 同理 */}
        </Flex>
        <Flex gap="small" wrap>
          <Button color="pink" variant="solid">Solid</Button>
          {/* pink 的其余变体同理 */}
        </Flex>
        <Flex gap="small" wrap>
          <Button color="purple" variant="solid">Solid</Button>
          {/* purple 的其余变体同理 */}
        </Flex>
        <Flex gap="small" wrap>
          <Button color="cyan" variant="solid">Solid</Button>
          {/* cyan 的其余变体同理 */}
        </Flex>
      </Flex>
    </ConfigProvider>
  );
};

export default App;

这个示例还顺带展示了一个实战技巧:通过 useResponsive 获取断点状态,配合 ConfigProvidercomponentSize 全局控制按钮尺寸,让同一套按钮矩阵在小屏设备自动缩小。

color 与 variant 的取值范围

根据 Button 组件文档 的 API 表与 类型定义

variant:六种变体

取值 视觉形态
outlined 描边按钮,透明背景 + 主色边框
dashed 虚线描边按钮
solid 实心按钮,主色背景填充
filled 浅色填充按钮(淡色背景 + 深色文字)
text 纯文本按钮,无边框无背景,hover 时出现浅色底
link 链接按钮,无下划线、无边框,类似超链接

类型声明为联合字面量:

// components/button/buttonHelpers.tsx
export const _ButtonVariantTypes = [
  'outlined', 'dashed', 'solid', 'filled', 'text', 'link',
] as const;
export type ButtonVariantType = (typeof _ButtonVariantTypes)[number];

color:基础色 + PresetColors

color 的取值为 default | primary | danger | PresetColors。其中 PresetColors 即 Ant Design 的 13 个预设色板:

type PresetColors =
  | 'blue' | 'purple' | 'cyan' | 'green' | 'magenta' | 'pink' | 'red'
  | 'orange' | 'yellow' | 'volcano' | 'geekblue' | 'lime' | 'gold';

各取值的版本支持情况(来自 文档 API 表):

  • defaultprimarydanger:5.21.0 起支持;
  • PresetColors(13 个预设色):5.23.0 起支持;
  • variant="solid" 时未指定 color 的默认色为 primary:6.4.0 起生效。

源码解析:color 与 variant 是如何被解析的

阅读 Button.tsxparsedColor / parsedVariant 的解析逻辑,可以确认以下优先级规则,这也是使用 color/variant 时必须理解的"决策树":

const [parsedColor, parsedVariant] = useMemo<ColorVariantPairType>(() => {
  // 1. 显式同时指定 color 与 variant,直接生效(最高优先级)
  if (color && variant) {
    return [color, variant];
  }

  // 2. 语法糖:type / danger 走映射表
  if (type || danger) {
    const colorVariantPair = ButtonTypeMap[mergedType] || [];
    if (danger) {
      return ['danger', colorVariantPair[1]];
    }
    return colorVariantPair;
  }

  // 3. variant="solid" 单独出现时,默认颜色为 primary
  if (variant === 'solid') {
    return ['primary', variant];
  }

  // 4. 回退到 ConfigProvider 的组件级配置
  if (contextColor && contextVariant) {
    return [contextColor, contextVariant];
  }
  if (contextVariant === 'solid') {
    return ['primary', contextVariant];
  }

  // 5. 最终兜底
  return ['default', 'outlined'];
}, [color, variant, type, danger, contextColor, contextVariant, mergedType]);

由此得到四条明确结论:

  1. colorvariant 同时设置时,二者直接组合生效——这正是本示例(颜色与变体)演示的核心能力;
  2. type 是语法糖:源码中的 ButtonTypeMapButton.tsx#L118-L125)给出了旧 API 到新体系的完整映射,type="primary" 等价于 color="primary" variant="solid"type="default" 等价于 color="default" variant="outlined"type="dashed" / type="text" / type="link" 分别映射到对应的变体;
  3. variant="solid" 缺省颜色为 primary:只写 <Button variant="solid" /> 会得到主色实心按钮,避免"实心 + 默认灰"这种反直觉外观;
  4. 支持全局配置ConfigProviderbutton 组件配置(5.25.0 起)可下发 colorvariant,组件级属性未指定时自动回退到上下文值,实现"一处配置、全局换肤"。

另外值得注意:danger 属性与 color 并存时"以 color 为准",源码中 isDanger 的判断依据是解析后的 mergedColor === 'danger'Button.tsx#L220-L221),因此 <Button color="pink" danger /> 最终呈现的是粉色而非危险红。

渲染产物:classNames 的组装

解析完成后,Button.tsx#L369-L397 将颜色与变体拼接到 DOM class 上:

const classes = clsx(
  prefixCls,
  // ...
  {
    // danger 会映射为 dangerous,保证与旧版 class 兼容
    [`${prefixCls}-color-${mergedColorText}`]: mergedColorText,
    [`${prefixCls}-variant-${mergedVariant}`]: mergedVariant,
    // 兼容 5.21.0 之前版本的 .ant-btn-primary 等类名
    [`${prefixCls}-${mergedType}`]: mergedType,
    // ...
  },
);

也就是说,<Button color="pink" variant="dashed" /> 最终会渲染出 ant-btn ant-btn-color-pink ant-btn-variant-dashed 这样的类名组合。这里还有一个细节:danger 颜色在 class 中实际写作 color-dangerousmergedColorText 做了 dangerdangerous 的转换),与 5.x 旧版的 .ant-btn-dangerous 命名保持一致。

样式层:一套 CSS 变量驱动全部 颜色 × 变体 组合

真正的视觉规则集中在 style/variant.ts。它的实现思路非常巧妙:不在每种"颜色 × 变体"组合上写死样式,而是为每个按钮先声明一组 CSS 变量(border-color、text-color、bg-color、shadow 等),再让六种变体覆写这些变量的取值,最后让 16 种颜色(default / primary / dangerous / 13 个 PresetColors)分别覆写基础色变量

各变体覆写的变量语义如下(摘自 variant.ts):

变体 关键覆写 效果
solid 边框透明、文字 colorTextLightSolid、背景取 solid-bg-color 实心底 + 白字,并附带主题投影
outlined / dashed 边框与文字取 color-base 系列,背景取容器底色 描边样式;dashed 额外把 border-style 改为 dashed
filled 边框透明、背景取 color-light 系列 淡色底 + 深色字
text / link 背景透明、无边框;text 的 hover 底为 color-light 无框文本按钮,hover 出现浅底

颜色侧的覆写示例:预设色由 PresetColors.map(...) 批量生成(variant.ts#L269-L291),每个预设色从主题 Token 中取 blue6blue1blueHoverblue2blue3blueActiveblueShadowColor 等色阶填充变量——这就是为什么 color="pink" 的六种变体在 hover / active 时都有连贯的深色过渡,而无需任何额外配置。

这种"变量 + 模板"的结构还带来两个实用能力:

  • 渐变按钮:演示 linear-gradient.tsx 正是利用这些 CSS 变量注入 background-image 实现的;
  • 自定义禁用背景:演示 custom-disabled-bg.tsx 通过覆写 bg-color-disabled 变量定制禁用态。

边界行为:ghost 与无框变体的交互

源码中有两处与 color/variant 组合相关的边界处理,使用时需要注意:

  1. ghost 会把 solid 降级为 outlinedButton.tsx#L213-L218 中,ghost 且解析出的变体为 solid 时,会自动改写为 outlined。因为实心按钮无法"背景透明",只有描边形态才适合做幽灵按钮;
  2. text / link 不能做 ghost:开发环境下若对 link/text 变体设置 ghost,源码的 warning 逻辑(Button.tsx#L320-L324)会提示 "link or text button can't be a ghost button.";同时这两类无边框变体(isUnBorderedButtonVariant)也不会附加点击波纹效果。

与旧版 type 的对照速查

旧写法(type 语法糖) 新写法(color + variant)
<Button type="default"> <Button color="default" variant="outlined">
<Button type="primary"> <Button color="primary" variant="solid">
<Button type="dashed"> <Button color="default" variant="dashed">
<Button type="text"> <Button color="default" variant="text">
<Button type="link"> <Button color="link" variant="link">
<Button danger> color="danger" + 保持原变体
<Button ghost type="primary"> <Button color="primary" variant="solid" ghost>(自动转为 outlined)

小结

Ant Design Button 的"颜色与变体"体系用两个正交属性替代了旧的单一 typecolor 取值 default / primary / danger 及 13 个 PresetColors,variant 取值 outlined / dashed / solid / filled / text / link。两者同时设置时自由组合生效;单独设置 variant="solid" 默认主色;typedanger 作为语法糖通过 ButtonTypeMap 向下兼容。样式层则通过"CSS 变量 + 变体覆写 + 颜色覆写"的三层结构,让 100 多种组合共享同一套 hover / active / disabled 状态逻辑,既保证了视觉一致性,也为你留出了通过覆写变量定制渐变、禁用背景的扩展空间。

登录后查看全文
热门项目推荐
相关项目推荐