首页
/ DaisyUI Swap 组件完全指南:用纯 CSS 实现开关切换、图标过渡与主题控制器

DaisyUI Swap 组件完全指南:用纯 CSS 实现开关切换、图标过渡与主题控制器

2026-09-08 10:17:00作者:宗隆裙

DaisyUI 的 Swap 组件是一个极简却强大的"双元素显隐切换器":它利用 HTML <label> 与隐藏的 <input type="checkbox">,在无任何 JavaScript 的情况下,即可在"开/关"两种状态间切换两个子元素(文本、图标、emoji 均可),并提供 swap-rotate(旋转)与 swap-flip(翻转)两种过渡动效。本文将以 Swap 官方文档/components/swap/+page.md) 为主线,结合 swap.css 源码 与配套 Skill 文档,带你从零掌握该组件的全部类名、交互原理与真实落地场景(含与 theme-controller 结合的暗色主题切换方案)。

适用前提:Swap 是 DaisyUI 开箱即用的组件,只需在 Tailwind 配置中引入 DaisyUI 插件,即可直接在任意 HTML 模板中使用;以下所有示例均默认可复制运行。

Swap 是什么

Swap 允许你通过一个 checkbox 或一个类名来切换两个元素的可见性。组件本体是一段语义化、轻量的结构:

<label class="swap">
  <input type="checkbox" autocomplete="off" />
  <div class="swap-on">ON</div>
  <div class="swap-off">OFF</div>
</label>

点击后会看到 swap-onswap-off 两个子元素在"显示/隐藏"之间互换。整个交互零 JavaScript——状态机完全由浏览器原生的 :checked 伪类驱动,这也是它与 Collapse、Dropdown 等组件一脉相承的设计理念。

完整类名速查表

Swap 的类名体系可以分为四类,对应文档 frontmatter 中定义的 classnames

分类 类名 作用
component swap Swap 容器,声明一个 swap 结构
part swap-on checkbox 被勾选 / swap 处于激活态时应显示的子元素
part swap-off checkbox 未被勾选 / swap 处于非激活态时应显示的子元素
part swap-indeterminate checkbox 处于 indeterminate(不确定)状态时应显示的子元素
modifier swap-active 直接激活 swap(无需 checkbox),配合 JS 增删该类名使用
style swap-rotate 为 swap 增加旋转过渡效果
style swap-flip 为 swap 增加翻转(3D 翻转)过渡效果

基本约束(见 skills/daisyui/components/swap.md):

  • 结构上,一个 modifier(swap-active)可选,一个 style(swap-rotate / swap-flip)可选;
  • 要么用一个隐藏 checkbox 控制状态,要么用 JS 增删 swap-active 类名控制状态;
  • 需要展示 checkbox indeterminate 状态的独立内容时,使用 swap-indeterminate

核心原理:为何不需要 JavaScript

打开 swap.css 源码,可以看到组件的关键实现全部是选择器层面的状态表达。容器本身使用 CSS Grid 将子元素重叠定位:

.swap {
  @layer daisyui.l1.l2 {
    @apply relative inline-grid cursor-pointer place-content-center align-middle select-none;

    input {
      @apply appearance-none;
      border: none;
    }

    > * {
      @apply col-start-1 row-start-1;   /* 所有直接子元素堆叠在同一个网格单元 */
    }
  }
}

而"谁显示、谁隐藏"由兄弟选择器决定:

  • 默认隐藏 swap-onswap-indeterminate.swap-on, .swap-indeterminate, input:indeterminate ~ .swap-on { opacity: 0 }
  • checkbox 勾选或处于 indeterminate 时隐藏 swap-offinput:is(:checked, :indeterminate) ~ .swap-off { opacity: 0 }
  • checkbox 勾选时显示 swap-oninput:checked ~ .swap-on { opacity: 100 }

由于两个子元素都处于同一网格单元(col-start-1 row-start-1),并通过 opacity 完成显隐(配合 pointer-events/过渡时间自然平滑切换),因此点击整块 label 的任意位置即可触发——label 与内部 checkbox 的隐式关联让整个容器都成了可点击区域。子元素自带 transition-property: transform, rotate, opacity; transition-duration: 0.2s(且仅在 prefers-reduced-motion: no-preference 时启用,尊重系统减弱动态效果设置)。

源码说明:该规则同时支持 :indeterminate 状态(需要少量 JS 设置 checkbox 的 .indeterminate = true),此时显示 swap-indeterminate 内容而不是 swap-off

在源码中的定位与结构

Swap 的样式定义位于组件目录 packages/daisyui/src/components/swap.css,其产物会进入 DaisyUI 的 daisyui.l1 / daisyui.l1.l2 级联层(.swap 本体落在 daisyui.l1.l2,修饰与动效类落在 daisyui.l1),确保与其他组件共存时优先级可控。需要为项目生成独立主题/产物时,它与其他组件一样遵循统一的打包流程(参见 packages/daisyui/package.jsonfunctions 目录 中的 CSS 编译工具链)。

六种实战用法逐一解析

下面按官方文档的顺序,覆盖 Swap 最常见的全部应用场景。示例源码位于 components/swap 文档页/components/swap/+page.md),可直接对照查看。

1. 文本切换(Swap text)

最基础的用法,两个子元素直接放文本:

<label class="swap">
  <input type="checkbox" autocomplete="off" />
  <div class="swap-on">ON</div>
  <div class="swap-off">OFF</div>
</label>

要点:swap-on 的文本在勾选后可见,swap-off 的文本在未勾选时可见。输入框不需要额外样式,因为 .swap input 已被 appearance-none + 无边框隐藏,但它必须保留在结构中作为状态载体

2. 音量图标切换(Swap volume icons)

在实际 UI 里,swap-on / swap-off 放 SVG 图标是最常见组合。示例使用两个内联 SVG(有声音量喇叭与静音喇叭),外层用 fill-current 让图标跟随文字颜色:

<label class="swap">
  <!-- this hidden checkbox controls the state -->
  <input type="checkbox" />

  <!-- volume on icon -->
  <svg
    class="swap-on fill-current"
    xmlns="http://www.w3.org/2000/svg"
    width="48"
    height="48"
    viewBox="0 0 24 24">
    <path d="M14,3.23V5.29C16.89,6.15 19,8.83 19,12C19,15.17 16.89,17.84 14,18.7V20.77C18,19.86 21,16.28 21,12C21,7.72 18,4.14 14,3.23M16.5,12C16.5,10.23 15.5,8.71 14,7.97V16C15.5,15.29 16.5,13.76 16.5,12M3,9V15H7L12,20V4L7,9H3Z" />
  </svg>

  <!-- volume off icon -->
  <svg
    class="swap-off fill-current"
    xmlns="http://www.w3.org/2000/svg"
    width="48"
    height="48"
    viewBox="0 0 24 24">
    <path d="M3,9H7L12,4V20L7,15H3V9M16.59,12L14,9.41L15.41,8L18,10.59L20.59,8L22,9.41L19.41,12L22,14.59L20.59,16L18,13.41L15.41,16L14,14.59L16.59,12Z" />
  </svg>
</label>

官方示例中为 .swap-on 加了 fill-current,这样切到不同主题(如 data-theme 变体)时图标颜色能自动适配前景色。

3. 旋转过渡:太阳/月亮主题开关(rotate effect)

给容器追加 swap-rotate,两个状态会以旋转方式过渡。太阳图标位于 swap-on,月亮图标位于 swap-off,这是官网暗色主题切换按钮的原型:

<label class="swap swap-rotate">
  <!-- this hidden checkbox controls the state -->
  <input type="checkbox" />

  <!-- sun icon -->
  <svg class="swap-on h-10 w-10 fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
    <path d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z" />
  </svg>

  <!-- moon icon -->
  <svg class="swap-off h-10 w-10 fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
    <path d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z" />
  </svg>
</label>

尺寸可通过 Tailwind 的 h-* / w-* 工具类(如 h-10 w-10)控制;若省略会默认使用文档示例中的固定 width/height 或随容器尺寸。

4. 汉堡按钮:菜单开关(Hamburger button)

Swap 常与 Button 组件叠加,做成"汉堡/关闭"二象按钮,非常适合移动端导航栏。容器同时叠加 btn btn-circle swap swap-rotate

<label class="btn btn-circle swap swap-rotate">
  <!-- this hidden checkbox controls the state -->
  <input type="checkbox" />

  <!-- hamburger icon(未勾选时显示) -->
  <svg class="swap-off fill-current" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 512 512">
    <path d="M64,384H448V341.33H64Zm0-106.67H448V234.67H64ZM64,128v42.67H448V128Z" />
  </svg>

  <!-- close icon(勾选后显示) -->
  <svg class="swap-on fill-current" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 512 512">
    <polygon points="400 145.49 366.51 112 256 222.51 145.49 112 112 145.49 222.51 256 112 366.51 145.49 400 256 289.49 366.51 400 400 366.51 289.49 256 400 145.49" />
  </svg>
</label>

btn btn-circle 提供圆形按钮的视觉与点击反馈,Swap 负责图标的旋转替换,两者职责分离、互不干扰。要注意子元素在 btn 中的布局:官方示例确保两个 SVG 处于堆叠网格单元,因此即便图标被旋转也始终居中于按钮。

5. 翻转过渡:表情切换(flip effect)

swap-flip 提供类似卡片翻面的 3D 过渡效果。配合任意内容(这里是大号 emoji),就能做一个趣味开关:

<label class="swap swap-flip text-9xl">
  <!-- this hidden checkbox controls the state -->
  <input type="checkbox" />

  <div class="swap-on">😈</div>
  <div class="swap-off">😇</div>
</label>

text-9xl 等字号工具类可任意放大文本/emoji 内容。

6. 不依赖点击:用类名激活(Activate using class name)

若你的触发逻辑并不来自 checkbox(比如由其他组件的状态、滚动监听或 JS 逻辑驱动),可以把容器换成 div,并交给 swap-active 类名控制——看到 swap-active 就显示 swap-on,没有就显示 swap-off

<!-- 默认状态:显示 swap-off(🥶) -->
<label class="swap text-6xl">
  <div class="swap-on">🥵</div>
  <div class="swap-off">🥶</div>
</label>

<!-- 激活状态:显示 swap-on(🥳),只要存在 swap-active 类即可 -->
<label class="swap swap-active text-6xl">
  <div class="swap-on">🥳</div>
  <div class="swap-off">😭</div>
</label>

这一模式的核心是"你可以在任意时刻用 JS 增删 swap-active 类名"来切换状态,适合那些把切换动作绑定到其他控件上的交互(例如点击一个外部按钮去控制某个 swap)。由于无需 checkbox,这里也可以使用 div 作为容器。

对应的 CSS 逻辑(见 swap.css)同样处理了与两个动效类的组合:

.swap-active {
  @layer daisyui.l1 {
    .swap-off { @apply opacity-0; }
    .swap-on  { @apply opacity-100; }

    &.swap-rotate .swap-on  { @apply rotate-0; }
    &.swap-rotate .swap-off { @apply -rotate-45; }

    &.swap-flip .swap-on  { transform: rotateY(0deg); }
    &.swap-flip .swap-off { transform: rotateY(-180deg); backface-visibility: hidden; @apply opacity-100; }
  }
}

因此无论走 checkbox 还是 swap-active,两种激活路径最终都收敛到同一套视觉结果。

旋转与翻转的底层差异

虽然 swap-rotateswap-flip 表面都是"切换时有动画",但源码实现截然不同,理解后能帮你正确选型:

  • swap-rotateswap.css):纯 2D 旋转。默认 swap-on 先处于 rotate-45,勾选/激活后旋转到 rotate-0 显示;swap-off 在激活后旋转到 -rotate-45 隐藏。实现基于 Tailwind 的 rotate 工具类 + 外层容器统一的 transition-property: transform, rotate, opacity
  • swap-flipswap.css):真正的 3D 翻面。容器开启 transform-style: preserve-3d; perspective: 20rem;默认 swap-on 位于 rotateY(180deg)(背对读者),勾选后转到 rotateY(0deg),而 swap-off 从 0 转到 -180deg,配合 backface-visibility: hidden 制造"卡片翻面"。

总结:追求 360° 旋转图标(太阳↔月亮)选 swap-rotate;追求"牌面翻转"(正反两面)选 swap-flip

实战联动:用 Swap 做一个暗色主题切换按钮

Swap 最常见的真实场景是作为 theme-controller 的载体。在 theme-controller 文档页/components/theme-controller/+page.md) 中可以看到完整用法——它本质上是一个使用 theme-controller 类名的 checkbox,配合 data-theme 值就能直接切换整个页面的主题:

<label class="swap swap-rotate">
  <!-- 同时充当主题控制器:勾选时切到 dark,取消时切回 light -->
  <input type="checkbox" class="theme-controller" value="dark" />
  <svg class="swap-on h-10 w-10 fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
    <!-- 月亮(dark 主题下的显示) -->
    <path d="M21.64,13a1,1,0,0,0-1.05-.14...Z" />
  </svg>
  <svg class="swap-off h-10 w-10 fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
    <!-- 太阳(light 主题下的显示) -->
    <path d="M5.64,17l-.71.71..." />
  </svg>
</label>

theme-controller 的具体行为与主题机制见 theme-controller 文档/components/theme-controller/+page.md) 与 Themes 文档/docs/themes/+page.md)。这种"一个 checkbox 同时控制显隐与主题"的组合,正是 Swap 零 JS 设计的最佳落地。

进阶使用与细节建议

  • 状态持久化需要少量 JS:Swap 本身不记忆状态。刷新页面后 checkbox 回到默认未勾选。若需持久化(如记住用户选择的主题),可在 change 事件里用 localStorage/Cookie 记录 checkbox.checked,页面加载时回填 checked 即可。
  • 不要放两个 checkbox:一个 swap 只能有一个控制状态的 checkbox,其余子元素都是纯展示内容。
  • 与动效类的顺序无关swap-rotateswap-flipswap-active 可以任意叠加(如 swap swap-active swap-flip),源码中的嵌套规则已分别处理 &.swap-rotate&.swap-flip 组合。
  • 配合尺寸工具类:容器和内容尺寸可完全由 Tailwind 工具类接管(w-10 h-10text-6xlbtn btn-circle 等),无需改动组件默认样式。
  • 使用自定义前缀时:如果配置了 DaisyUI 的 prefix 选项,所有类名(含 swapswap-on 等)都需要加前缀。官方文档示例中以 $$swap 占位符表示"前缀将在此替换",实际书写时替换为你配置的前缀或直接去掉。
  • 无障碍:官方示例在 checkbox 上加 autocomplete="off",避免浏览器误填充干扰状态;在真实表单/导航语境中建议补充适当的 aria-label(例如"切换菜单"),让辅助技术用户能理解这个 label 的语义。

小结

Swap 组件把"状态存储"交给浏览器原生的 checkbox、把"状态样式"交给 CSS 选择器,从而在无脚本的前提下覆盖了文本切换、图标切换、旋转/翻转动效、按钮化与主题切换等绝大多数开关型交互需求。掌握本文列出的三个 part 类名(swap-onswap-offswap-indeterminate)、一个 modifier(swap-active)和两个 style(swap-rotateswap-flip),再对照 swap.css 理解其兄弟选择器机制,你便可以在任何 DaisyUI 项目中高效地搭建"轻量无 JS"的状态切换 UI。

相关资源:

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

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391