logoAnt Design

⌘ K
  • 设计
  • 研发
  • 组件
  • 博客
  • 资源
  • 国内镜像
5.25.4
  • v6 的一些 CSS 琐事
  • 👀 视觉回归测试
  • 为什么禁用日期这么难?
  • 封装 Form.Item 实现数组转对象
  • 行省略计算
  • 📢 v4 维护周期截止
  • antd 里常用的 TypeScript 工具方法
  • 一个构建的幽灵
  • 当 Ant Design 遇上 CSS 变量
  • API 的历史债务
  • 灵动的 Notification
  • 色彩模型与颜色选择器
  • 主题拓展
  • 虚拟表格来了!
  • 快乐工作主题(一)
  • 动态样式去哪儿了?
  • Suspense 引发的样式丢失问题
  • 打包体积优化
  • 你好,GitHub Actions
  • 所见即所得
  • 静态方法之痛
  • SSR 静态样式导出
  • 依赖排查
  • 贡献者开发维护指南
  • 转载-如何提交无法解答的问题
  • 新的 Tooltip 对齐方式
  • 非必要的渲染
  • 如何成长为 Collaborator
  • Modal hook 的有趣 BUG
  • antd 测试库迁移的那些事儿
  • Tree 的勾选传导
  • getContainer 的一些变化
  • 组件级别的 CSS-in-JS
变体
样式覆盖
条件兼容
条件样式
@scope
影响范围

v6 的一些 CSS 琐事

2025-05-23
@zombieJ
文档贡献者
  • 👀 视觉回归测试

    相关资源

    Ant Design X
    Ant Design Charts
    Ant Design Pro
    Pro Components
    Ant Design Mobile
    Ant Design Mini
    Ant Design Web3
    Ant Design Landing-首页模板集
    Scaffolds-脚手架市场
    Umi-React 应用开发框架
    dumi-组件/文档研发工具
    qiankun-微前端框架
    Ant Motion-设计动效
    国内镜像站点 🇨🇳

    社区

    Awesome Ant Design
    Medium
    Twitter
    yuque logoAnt Design 语雀专栏
    Ant Design 知乎专栏
    体验科技专栏
    seeconf logoSEE Conf-蚂蚁体验科技大会
    加入我们

    帮助

    GitHub
    更新日志
    常见问题
    报告 Bug
    议题
    讨论区
    StackOverflow
    SegmentFault

    Ant XTech logo更多产品

    yuque logo语雀-构建你的数字花园
    AntV logoAntV-数据可视化解决方案
    Egg logoEgg-企业级 Node.js 框架
    Kitchen logoKitchen-Sketch 工具集
    Galacean logoGalacean-互动图形解决方案
    xtech logo蚂蚁体验科技
    主题编辑器
    Made with ❤ by
    蚂蚁集团和 Ant Design 开源社区

    Ant Design v6 的开发过程中,由于不需要再考虑 IE 的兼容问题,我们对部分组件改造使用了 CSS 变量获得了更小的 CSS 体积以及更好的性能。今天我们来聊聊 CSS 变量的一些小事。

    变体

    在 v5 中一些组件支持 variant 属性来实现不同的样式,Button 组件就是一个典型例子:

    Variant Button

    (配合 color 实现了不同的按钮组合)

    在 v5 中,Button 的变体与颜色组合会创建一套重复的排列组合样式:

    css
    /* Sample code. Not used in real world. */
    .ant-btn-solid.ant-btn-red {
    color: #fff;
    background: red;
    }
    .ant-btn-solid.ant-btn-blue {
    color: #fff;
    background: blue;
    }
    .ant-btn-outlined.ant-btn-red {
    color: #fff;
    border: 1px solid red;
    }
    .ant-btn-outlined.ant-btn-blue {
    color: #fff;
    border: 1px solid blue;
    }
    /* ... */

    转换成 CSS 变量后,逻辑就会从样式转成对色板的控制。因而在定义完一套基础色板后,就可以通过变量简单的量产样式:

    css
    /* Sample code. Not used in real world. */
    /* Template Part */
    .ant-btn {
    color: var(--ant-btn-color);
    background: var(--ant-btn-background);
    border-color: var(--ant-btn-border-color);
    border-width: 1px;
    border-style: solid;
    }
    .ant-btn-solid {
    --ant-btn-color: #fff;
    --ant-btn-background: var(--ant-color-solid);
    }
    .ant-btn-outlined {
    --ant-btn-color: var(--ant-color-solid);
    --ant-btn-border-color: var(--ant-color-solid);
    }
    /* CSS Variables. The more color you have, the more size to save. */
    .ant-btn-red {
    --ant-color-solid: red;
    }
    .ant-btn-blue {
    --ant-color-solid: blue;
    }
    /* ... */

    样式覆盖

    在 CSS 变量下,用户侧的样式覆盖也变得更简单了。过去开发者覆盖一个样式需要对各个状态进行覆盖,同时还需要考虑优先级覆盖的情况:

    css
    .ant-btn-solid.my-btn:not(:disabled) {
    background: #f00;
    }
    .ant-btn-solid.my-btn:not(:disabled):hover {
    background: #e00;
    }
    .ant-btn-solid.my-btn:not(:disabled):active {
    background: #d00;
    }
    .ant-btn-outlined.my-btn:not(:disabled) {
    color: #f00;
    border-color: #f00;
    }
    .ant-btn-outlined.my-btn:not(:disabled):hover {
    color: #e00;
    border-color: #e00;
    }
    .ant-btn-outlined.my-btn:not(:disabled):active {
    color: #d00;
    border-color: #d00;
    }

    而覆盖 CSS 变量则简单很多:

    css
    .ant-btn-outlined.my-btn {
    --ant-color-solid: #f00;
    --ant-color-solid-hover: #e00;
    --ant-color-solid-active: #d00;
    }

    条件兼容

    v6 为了实现语义化结构,我们对大量组件的 DOM 结构进行了调整,同时也将 v4 至 v5 迁移时的 less 变量兼容提供的对应 Component Token 进行了清理(更多的数值通过计算生成而不是让开发者手工来配置)。但是为了避免对现有用户造成影响,我们是希望尽可能的兼容。

    其中一个例子就是某个 token 存在的时候,我们使用另一种样式:

    less
    .sample {
    color: blue;
    }
    /* How to if? */
    if (customVar exist) {
    .sample {
    color: red;
    }
    }

    一个想法是在组件中根据 token 的存在与否来添加一个额外的 className:

    jsx
    const Sample = () => {
    const { token } = useToken();
    // Sad. Component token is not exist in token.
    if (token.components.sample.customVar) {
    // ...
    }
    };

    但是遗憾的是,组件的 token 在 useToken 中并不存在。它只有在组件的渲染 effect 中才会异步生成从而避免无用的性能浪费。因而在 CSS 中条件判断会是个更好的选择,这里就不卖关子了,使用 @container 便可以实现条件判断:

    css
    /* Current container support css var `--custom-var` */
    @container style(--custom-var) {
    /* ... */
    }

    Without CSS Var

    With CSS Var

    条件样式
    CodeSandbox Icon
    codeblock
    codepen icon
    External Link Icon
    expand codeexpand code

    需要注意的是,@container 的 CSS 变量查询目前 Firefox 尚未支持。所以在 v6 中,我们并不会把主要的功能放在 @container 上,而是作为一个兼容兜底逻辑来使用。

    @scope

    如果说 CSS 中最诱人的属性是什么,那可能非 @scope 莫属了。v5 中,我们使用 :where 来实现 CSS 的命名空间,从而实现多个版本或者主题的 antd 组件的样式隔离:

    css
    /* Theme 1 */
    :where(.css-BamBoo) {
    .ant-btn {
    color: red;
    }
    }
    /* Theme 2 */
    :where(.css-LIghT) {
    .ant-btn {
    color: blue;
    }
    }

    但是这对于嵌套逻辑来说,偶尔会有一些问题。比如下面的例子中,Theme1 对 span 的样式会影响 Theme2:

    css
    /* Theme 1 */
    :where(.css-BamBoo).component-a span {
    color: red;
    }
    /* Theme 2 */
    :where(.css-LIghT).component-b {
    color: blue;
    }
    tsx
    <div className="component-a css-BamBoo">
    <div className="component-b css-LIghT">
    <span>Hello World</span>
    </div>
    </div>

    而 @scope 则可以完美的解决这个问题:

    css
    @scope (.component-a) to (span) {
    /* ... */
    }
    Should be red
    Should be blue
    影响范围
    CodeSandbox Icon
    codeblock
    codepen icon
    External Link Icon
    expand codeexpand code

    但是同样的,@scope 目前也并不被 Firefox 支持。而如果将其应用于 v6 版本,那就会导致 Firefox 用户无法使用 antd 组件。因而我们可能会在下一个大版本中才能见到它的身影。