指南

主题定制

定制 Liquid Glass 材质、明暗 token 与 Tailwind 别名。

核心组件包提供一个样式表,其中包含设计 token、共享玻璃材质与 Tailwind 源码扫描 配置。在全局 CSS 中导入一次,其余布局围绕它来组织。

@import "tailwindcss";
@import "@xingxingmofashu/ui";

明暗主题

Token 通过 .light / .dark 类或 data-theme="light" / data-theme="dark" 属性切换。即使没有主题选择器,默认也是浅色。

<html class="dark">
<html data-theme="dark">

两种机制可以互换。在深色文档中,嵌套的 .light 或 [data-theme="light"] 子树可以切回浅色 token,适合局部预览与独立面板。

<html class="dark">
  <body>
    <main class="dark">...</main>
    <aside data-theme="light">...</aside>
  </body>
</html>

尽量在首次绘制前设置主题。在渲染期间读取 localStorage 会导致 hydration 不匹配;应在内联脚本中设置类名,或使用 next-themes 之类的主题库,并在 <html> 上添加 suppressHydrationWarning。

玻璃预设

玻璃预设是可选的插件,不属于核心样式表。插件的样式表提供 thin、soft、 regular、thick 四组材质,React 入口负责 data-glass 状态与持久化。

配置方式、预设参数、受控状态、容器级覆盖与水合行为见 玻璃预设。

Token 分层

材质分为两层:

  • 运行时 token 随主题变化:--ui-ink、--ui-ink-active、--ui-surface、 --ui-glass-surface、--ui-glass-overlay-surface、--ui-glass-border、 --ui-glass-highlight、--ui-glass-rim、--ui-glass-focus、 --ui-glass-inner-border、--ui-glass-tone、--ui-glass-contrast、 --ui-shadow-glass 和 --ui-drop-shadow-label。
  • 共享几何与光学参数 在明暗主题中保持一致:--ui-glass-blur、 --ui-glass-saturate、--ui-glass-inner-inset、--ui-glass-rim-inset 等共享的 --ui-glass-* 参数。预设可以替换 blur 与 saturation。checkbox 的 rim、slider 的 lens 等组件专属数值保留在该组件的主题配置中。

组件包在 @layer theme 中定义这些值。因此应用里未分层的 :root 无需 !important 就能覆盖:

@import "tailwindcss";
@import "@xingxingmofashu/ui";

:root {
  --ui-glass-surface: rgb(255 255 255 / 0.5);
  --ui-glass-overlay-surface: rgb(255 255 255 / 0.8);
  --ui-glass-border: rgb(15 23 42 / 0.16);
  --ui-glass-blur: 20px;
  --ui-glass-saturate: 160%;
}

.dark,
[data-theme="dark"] {
  --ui-glass-surface: rgb(20 20 20 / 0.75);
  --ui-glass-overlay-surface: rgb(20 20 20 / 0.86);
  --ui-glass-border: rgb(255 255 255 / 0.24);
}

默认的 thin 材质使用 20% 浅色遮罩或 62% 深色遮罩,搭配 4px 模糊与 150% 饱和度。遮罩强度需要在通透感和文字对比度之间取舍,请按应用中的图片来 调整:在最复杂、最暗的背景上测试,而不只是纯色页面。

承载文字的浮层——Dialog、Alert Dialog、Drawer、Popover、Menu、Select、 Toast 与 Tooltip——使用 .ui-glass-overlay 与更强的 --ui-glass-overlay-surface 遮罩(默认浅色 64% / 深色 76%)。页面仍会透出, 但正文会获得更强的底板;由于底色仍随页面变化,请在最复杂的图片上验证次级 文字对比度。玻璃预设插件会同时调整这两档 surface token。

浮层不再使用 --ui-surface:如果之前通过覆盖它来调整浮层背景,请改用 --ui-glass-overlay-surface。如果希望不透明表面与浮层同步变化,请同时设置 两者。

Tailwind 别名

样式表为常用 token 提供了 Tailwind 颜色别名:

工具类Token
text-ui-ink、bg-ui-ink--ui-ink
bg-ui-glass-surface--ui-glass-surface
bg-ui-glass-overlay-surface--ui-glass-overlay-surface
border-ui-glass-border--ui-glass-border
outline-ui-glass-focus--ui-glass-focus
bg-ui-surface--ui-surface

为自己的布局使用这些别名,可以让自定义界面跟随组件主题。需要一次性数值时, 仍然可以使用任意值:

<div className="rounded-3xl border border-ui-glass-border bg-ui-glass-surface p-6 text-ui-ink">
  与组件材质保持一致。
</div>

自定义玻璃表面

共享材质也以 CSS 类导出。需要组件库未提供的玻璃面板时,可以组合这些类:

<div className="ui-glass ui-glass-inner ui-glass-highlight relative overflow-hidden rounded-3xl p-6">
  <span aria-hidden="true" className="ui-glass-rim" />
  <p className="relative z-10 text-sm text-ui-ink">自定义玻璃面板</p>
</div>
  • .ui-glass 绘制半透明填充、双层边框、镜面阴影与背景模糊。
  • .ui-glass-overlay 换用更强的浮层遮罩;用于悬浮在页面内容之上的文字面板。
  • .ui-glass-inner 通过 ::before 添加柔和内轮廓。
  • .ui-glass-highlight 通过 ::after 添加对角高光。
  • .ui-glass-rim 是装饰性子元素,请加上 aria-hidden="true"。
  • .ui-glass-chip 是用于小型读数等紧凑表面的样式。

大多数组件已经组合了这些类。只有组件库没有提供对应表面时,才需要直接使用它们。

组件级样式

每个组件都接受 className 与 style。它们会合并到组件的主要元素:大多数组件是 根元素,Dialog、Alert Dialog、Drawer、Popover、Menu、Tooltip 是弹窗,Input 是 外层根元素,Select 是字段根元素,Toast 则是每条通知。用它们处理布局,而不是 替换材质:

<Button className="w-full" style={{ maxWidth: 320 }} label="继续" />

每个组件还接受 ui,其键对应组件的 data-slot 名称。用它调整内部槽位的样式, 同时保持单结构 API:

<Card
  title="部署"
  description="生产环境"
  ui={{
    glass: "bg-white/40",
    header: "pb-0",
    title: "tracking-tight",
  }}
>
  <p className="text-sm text-ui-ink/70">Build 128 已上线。</p>
</Card>

值为 ClassValue,因此支持字符串、数组与类名映射。合并顺序是主题配方、ui、 className;对于 Accordion、Toggle Group 这类集合组件,先应用根 ui,再应用 每个 item 的 ui,最后是 item 的 className。可查看 DOM 的 data-slot 属性 或组件 API 表中的槽位列表。

需要在运行时计算的值(包括实例级 CSS 变量)可以用 style。内联样式会覆盖主题与 className 中的同名属性;颜色、模糊与阴影仍应通过共享 token 调整。

需要完全控制时,可以导入编译后的主题配方:

import buttonTheme from "@xingxingmofashu/ui/theme/button";

const styles = buttonTheme({ size: "lg" });

export function CustomButton() {
  return <button className={styles.root()}>自定义操作</button>;
}

配方返回各插槽的类名,自定义组件可以复用相同的几何与材质,而不必复制 Tailwind 类。

动效与浏览器支持

过渡与按压效果都包含 motion-reduce 变体。设置 prefers-reduced-motion: reduce 的用户仍会看到布局与状态变化,但装饰性动效会 被移除或缩短。

视觉材质依赖现代 CSS:backdrop-filter、color-mix、容器单位、独立的 translate / scale 属性,以及 :has。对于不支持 backdrop-filter 的 浏览器,请提供合理的背景回退,或将支持范围限制在现代常青浏览器。

检查清单

  • 只导入一次组件样式表,并放在自定义覆盖之前。
  • 在首次绘制前设置 .dark 或 data-theme="dark"。
  • 共享材质切换使用可选的玻璃预设插件 的 data-glass。
  • 自定义材质在未分层的 :root 与 .dark 块中覆盖 token。
  • 在应用中最复杂的背景上测试玻璃对比度。
  • 内部槽位优先用 ui,布局优先用 className 与 style,材质变化优先用 token。