科技前沿 科普Web 基础教程建站系列

样式系统实战:白物集如何用 daisyUI 搭 UI

📅 2026-07-12

项目做到一定规模,手写 CSS 就撑不住了。白物集建站初期面临的问题很具体:几十个页面和组件,每个都要重复写按钮、导航、卡片、徽章——同事在不同页面里写了两套风格接近但不完全一样的按钮,后来花了半天统一。

解决方案是 Tailwind CSS v4 + daisyUI v5。不是选最潮的框架,是选最快出活的组合。下面直接拆白物集项目里的真实代码。

为什么不是纯 Tailwind

Tailwind CSS 的原子类写法,写过的人都知道:一个按钮能写满一行 class。daisyUI 把常见 UI 模式封装成语义类,一个 btn 就解决按钮的 padding、font-size、border-radius、hover 状态。

白物集用了 daisyUI 的这几个核心组件:

组件 daisyUI 类 项目中用的地方
导航栏 navbar + navbar-start/center/end NavBar.astro
按钮 btnbtn-ghostbtn-sm 所有页面
菜单 menumenu-horizontal 导航项
页脚 footerfooter-center BaseLayout.astro
卡片 card ArticleCard、文章详情
链接 linklink-hover 页脚链接
面包屑 breadcrumbs 文章详情页

好处是组件迁移时,HTML 结构改了,但 daisyUI 的 class 不变——NavBar 从横向布局改成纵向,只需要在 <nav> 上换一个类。

项目里的 Tailwind + daisyUI 配置

白物集用 Tailwind v4 的 CSS-first 配置方式(不是传统的 tailwind.config.js),入口文件 global.css 只有三行:

@import "tailwindcss";
@plugin "daisyui";

两个 @ 指令就完成了整站 UI 框架加载。daisyUI v5 兼容 Tailwind v4,可以直接用 @plugin 语法引入,不需要手动 import daisyUI 的 CSS 文件。

Astro 的配置也很简洁——astro.config.mjs 里用 Vite 插件接入 Tailwind:

import { defineConfig } from 'astro/config';
import tailwindcss from '@tailwindcss/vite';

export default defineConfig({
  vite: {
    plugins: [tailwindcss()],
  },
});

package.jsondaisyui: "^5.6.2"tailwindcss: "^4.3.1" 是 devDependencies,构建时会被 tree-shaken,不会污染生产包。

导航栏——daisyUI 组件实战

白物集的顶部导航栏(NavBar.astro)是 daisyUI 组件用得最多的地方。代码总共 70 行,去掉 SVG logo 和数据逻辑,核心结构就这些:

<nav class="navbar bg-base-100/80 backdrop-blur-md border-b border-base-200 sticky top-0 z-50">
  <div class="navbar-start">
    <a href="/" class="btn btn-ghost text-sm gap-1 md:gap-2 px-2 md:px-3">
      <span class="font-semibold tracking-wide text-sm">白物集</span>
    </a>
  </div>
  <div class="navbar-center hidden sm:flex">
    <ul class="menu menu-horizontal px-1 gap-1 text-sm">
      {items.map((item) => (
        <li><a href={item.href} class="btn btn-ghost btn-sm">{item.label}</a></li>
      ))}
    </ul>
  </div>
  <div class="navbar-end gap-1">
    <button id="theme-toggle" class="btn btn-ghost btn-sm text-lg">🌙</button>
  </div>
</nav>

几个关键点:

  • navbar 类自动实现 Flexbox 三栏布局,navbar-start/center/end 分别控制左中右对齐——不需要自己写 justify-content: space-between
  • bg-base-100/80 + backdrop-blur-md 是毛玻璃导航栏效果,/80 是 Tailwind v4 的透明度后缀。
  • btn btn-ghost 组合实现透明底按钮,hover 时有背景色变化,比手写 cursor: pointer + transition 少 5 行 CSS。
  • menu menu-horizontal 是横向导航菜单,自动处理 li 间距和 a 标签的点击区域。

这是项目里最常踩的坑:直接用 HTML 原生 <ul><li> 写导航栏,间距、对齐、hover 效果全部手写,换一个页面又得重新调一遍。用 daisyUI 的 menu 类后,导航栏样式在所有页面保持一致。

卡片组件——设计系统一致性

文章卡片是白物集首页最频繁出现的 UI 模式。ArticleCard.astro 里的卡片用了 daisyUI 的 card 类:

<a href={`/articles/${id}`}
   class="card group no-underline block bg-base-100 border border-base-300 rounded-xl p-5
          transition-all duration-200 hover:-translate-y-0.5
          hover:border-[color-mix(in_srgb,{accentColor}_50%,transparent)]">
  <div class="tag text-xs font-semibold uppercase tracking-wider mb-2"
       style="background:color-mix(in srgb, {accentColor} 15%, transparent);color:{accentColor};">
    {category}
  </div>
  <h3 class="text-base font-semibold mt-0 mb-2 leading-snug text-base-content">{title}</h3>
  <p class="text-sm leading-relaxed mb-0 text-base-content/70">{abstract}</p>
  <div class="flex gap-3 mt-3 text-xs text-base-content/50">
    <span>📅 {date}</span>
  </div>
</a>

text-base-content 是 daisyUI 的语义色变量,对应当前主题的文字色。切换暗色模式时,bodydata-theme 属性变 "dark",daisyUI 自动重写所有 base-content 的颜色值——整个换肤过程不需要碰一行 CSS。

首页 index.astro 的卡片网格用了一个技巧:按文章频道分别赋予不同的标签色,通过 color-mix 动态生成透明背景:

const tagStyle = isBreakfast
  ? 'background:rgba(10,132,255,0.12);color:var(--accent-cyan);'
  : isApple
  ? 'background:rgba(255,159,10,0.12);color:var(--accent-amber);'
  : isAi
  ? 'background:rgba(204,102,0,0.12);color:var(--accent-orange);'
  : 'background:rgba(90,184,255,0.12);color:var(--brand-secondary);';

暗色主题切换——只用两行 daisyUI

白物集支持浅色/暗色双主题,切换逻辑在 NavBar.astro 的 <script> 里,只有 6 行有效代码:

const html = document.documentElement;
function setTheme(t) {
  html.setAttribute('data-theme', t);
  localStorage.setItem('theme', t);
}

daisyUI v5 自带两套内置主题(lightdark),只需在 <html> 上设置 data-theme="dark",所有 daisyUI 组件的背景色、文字色、边框色自动切换。BaseLayout.astro 里还加了一段首屏 inline script,从 localStorage 恢复用户选择:

(function(){
  var s = localStorage.getItem('theme');
  if (s) { document.documentElement.setAttribute('data-theme', s); return; }
  var p = window.matchMedia('(prefers-color-scheme: dark)').matches;
  document.documentElement.setAttribute('data-theme', p ? 'dark' : 'light');
})();

这段代码放在 <head> 里同步执行,避免暗色模式下的首屏白屏闪烁。

白物集的设计 Token 体系

daisyUI 的 base-100base-200base-content 是基于 CSS 变量的抽象层,白物集在此基础上扩展了自己的 Token:

:root {
  --brand-primary: #0A84FF;
  --bg-primary: #0a0a0c;
  --bg-card: #16161a;
  --border: #2a2a33;
  --text-primary: #e8e8ed;
  --accent-cyan: var(--brand-primary);
}

[data-theme="light"] {
  --bg-primary: #f5f5f7;
  --bg-card: #ffffff;
  --border: #d2d2d7;
  --text-primary: #1d1d1f;
}

不要把所有样式都写在 daisyUI 类里。白物集的经验是:daisyUI 管组件结构(navbar、menu、card、btn),自定义 Token 管品牌色和间距。两者各自负责,不混在一起。页面的主色调用 --brand-primary,组件的行为结构用 daisyUI 的语义类——换主题时改 CSS 变量,不动 HTML。

避坑:daisyUI v5 和 Tailwind v4 的兼容

daisyUI v5 正式支持 Tailwind v4,但有一个注意事项:daisyUI v4 不兼容 Tailwind v4。白物集之前升级 Tailwind 到 v4 后,daisyUI 组件样式全乱了(按钮边框消失、卡片间距错位),排查后发现是 daisyUI 版本没跟上。最终方案是同时升级:tailwindcss@^4.3.1 + daisyui@^5.6.2,配合 @tailwindcss/vite 插件。

另一个坑:daisyUI 的内置主题色(primarysecondary)和白物集的品牌色冲突。daisyUI 默认 primary 是蓝色,白物集的品牌色也是蓝色,但饱和度不同。解决方案是不用 daisyUI 的 btn-primary,而是自己定义 --brand-primary CSS 变量,配合 <style> 标签里的自定义类。品牌一致性比框架便利性优先。

总结

白物集的样式系统结构很简单:Tailwind v4 提供原子类 → daisyUI v5 封装组件 → CSS 变量承载品牌色。三层各司其职,没有一种框架包办一切。对于内容型网站,这是出活最快、维护成本最低的组合。

下一篇拆后端——Express 在白物集里是怎么搭的,19 个 API 路由如何分层管理

← daisyUI:Tailwind CSS 最强组件库 → Apple 频道 xh:比 curl 更友好的 HTTP 客户端 →
🍎 Apple 深度分析
本文基于 Apple 公开资料及行业分析撰写。观点仅供参考与学习交流。