主题

了解如何使用 Tailwind CSS v4、CSS 变量和 Tailwind Variants API 自定义 Nuxt UI 组件,以实现强大且灵活的主题定制。

Tailwind CSS

Nuxt UI 使用 Tailwind CSS v4,您可以阅读官方升级指南了解所有重大变更。

@theme

Tailwind CSS v4 采用 CSS 优先的配置方法,您现在可以在@theme指令中通过 CSS 变量自定义主题,定义项目的自定义设计令牌,例如字体、颜色和断点。

app/assets/css/main.css
@import "tailwindcss";
@import "@nuxt/ui";

@theme static {
  --font-sans: 'Public Sans', sans-serif;

  --breakpoint-3xl: 1920px;

  --color-green-50: #EFFDF5;
  --color-green-100: #D9FBE8;
  --color-green-200: #B3F5D1;
  --color-green-300: #75EDAE;
  --color-green-400: #00DC82;
  --color-green-500: #00C16A;
  --color-green-600: #00A155;
  --color-green-700: #007F45;
  --color-green-800: #016538;
  --color-green-900: #0A5331;
  --color-green-950: #052E16;
}
app/assets/css/main.css
@import "tailwindcss";
@import "@nuxt/ui-pro";

@theme static {
  --font-sans: 'Public Sans', sans-serif;

  --breakpoint-3xl: 1920px;

  --color-green-50: #EFFDF5;
  --color-green-100: #D9FBE8;
  --color-green-200: #B3F5D1;
  --color-green-300: #75EDAE;
  --color-green-400: #00DC82;
  --color-green-500: #00C16A;
  --color-green-600: #00A155;
  --color-green-700: #007F45;
  --color-green-800: #016538;
  --color-green-900: #0A5331;
  --color-green-950: #052E16;
}

@theme 指令告诉 Tailwind 根据这些变量生成新的工具类和变体。它等同于 Tailwind CSS v3 tailwind.config.ts 文件中的 theme.extend 键。

在主题变量文档中了解更多关于自定义主题的信息。

@source

您可以使用@source 指令来明确指定 Tailwind 自动内容检测无法识别的源文件。

这在编写 Markdown 文件中的 Tailwind CSS 类时很有用,例如结合使用@nuxt/content

app/assets/css/main.css
@import "tailwindcss";
@import "@nuxt/ui";

@source "../../../content";
/* Use this if you're not using compatibilityVersion: 4: https://nuxtjs.org.cn/docs/getting-started/upgrade#opting-in-to-nuxt-4 */
@source "../../content";
app/assets/css/main.css
@import "tailwindcss";
@import "@nuxt/ui-pro";

@source "../../../content";
/* Use this if you're not using compatibilityVersion: 4: https://nuxtjs.org.cn/docs/getting-started/upgrade#opting-in-to-nuxt-4 */
@source "../../content";
在源文件类检测文档中了解更多关于自动内容检测的信息。

设计系统

Nuxt UI 扩展了 Tailwind CSS 的主题功能,提供了一个灵活的设计系统,其中包含基于Tailwind CSS 颜色的预配置颜色别名。这使得轻松自定义和快速调整 UI 以符合您的品牌美学成为可能。

颜色默认值描述
primarygreen主要品牌色,用作组件的默认颜色。
secondaryblue辅助颜色,用于补充主要颜色。
successgreen用于成功状态。
infoblue用于信息状态。
warningyellow用于警告状态。
errorred用于表单验证错误状态。
neutralslate中性色,用于背景、文本等。

这些颜色用于组件的样式设置,也用于生成 color props。

<template>
  <UButton color="primary">Button</UButton>
</template>
尝试使用顶部标题栏中的 主题选择器来改变 primaryneutral 颜色。

配置

您可以在运行时在您的app.config.ts文件中,通过 ui.colors 键配置这些颜色别名,无需重新构建应用程序即可实现动态主题自定义。

app.config.ts
export default defineAppConfig({
  ui: {
    colors: {
      primary: 'blue',
      neutral: 'zinc'
    }
  }
})

您可以在运行时在您的 vite.config.ts 文件中,通过 ui.colors 键配置这些颜色别名。

vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        colors: {
          primary: 'blue',
          neutral: 'zinc'
        }
      }
    })
  ]
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import uiPro from '@nuxt/ui-pro/vite'

export default defineConfig({
  plugins: [
    vue(),
    uiPro({
      ui: {
        colors: {
          primary: 'blue',
          neutral: 'zinc'
        }
      }
    })
  ]
})

扩展颜色

您可以在 app.config.ts 中添加自己的动态颜色别名,但必须确保同时在 ui.theme.colors 选项中定义它们在您的 nuxt.config.ts 文件。

app.config.ts
export default defineAppConfig({
  ui: {
    colors: {
      tertiary: 'indigo'
    }
  }
})
nuxt.config.ts
export default defineNuxtConfig({
  ui: {
    theme: {
      colors: [
        'primary',
        'secondary',
        'tertiary',
        'info',
        'success',
        'warning',
        'error'
      ]
    }
  }
})

您可以在 vite.config.ts 中添加自己的动态颜色别名,但必须确保同时在 theme.colors 选项中定义它们在 ui 插件。

vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        colors: {
          tertiary: 'indigo'
        }
      },
      theme: {
        colors: [
          'primary',
          'secondary',
          'tertiary',
          'info',
          'success',
          'warning',
          'error'
        ]
      }
    })
  ]
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import uiPro from '@nuxt/ui-pro/vite'

export default defineConfig({
  plugins: [
    vue(),
    uiPro({
      ui: {
        colors: {
          tertiary: 'indigo'
        }
      },
      theme: {
        colors: [
          'primary',
          'secondary',
          'tertiary',
          'info',
          'success',
          'warning',
          'error'
        ]
      }
    })
  ]
})

CSS 变量

Nuxt UI 利用一套强大的 CSS 变量作为设计令牌,以确保组件样式的一致性和灵活性。这些令牌构成了主题系统的基础,提供对亮模式和暗模式的良好支持。

颜色

Nuxt UI 为您定义的每个颜色别名提供了一个 CSS 变量,这些变量代表了在亮模式和暗模式下使用的默认色调。

:root {
  --ui-primary: var(--ui-color-primary-500);
  --ui-secondary: var(--ui-color-secondary-500);
  --ui-success: var(--ui-color-success-500);
  --ui-info: var(--ui-color-info-500);
  --ui-warning: var(--ui-color-warning-500);
  --ui-error: var(--ui-color-error-500);
}

这些 CSS 变量在 Tailwind CSS 的 @theme 中定义,因此您可以将它们用作类。

PrimarySecondarySuccessInfoWarningError

<template>
  <span class="text-primary">Primary</span>
  <span class="text-secondary">Secondary</span>
  <span class="text-success">Success</span>
  <span class="text-info">Info</span>
  <span class="text-warning">Warning</span>
  <span class="text-error">Error</span>
</template>
以下是 @theme 如何为每个颜色别名生成的。
@theme default {
  --color-primary: var(--ui-primary);
  --color-primary-50: var(--ui-color-primary-50);
  --color-primary-100: var(--ui-color-primary-100);
  --color-primary-200: var(--ui-color-primary-200);
  --color-primary-300: var(--ui-color-primary-300);
  --color-primary-400: var(--ui-color-primary-400);
  --color-primary-500: var(--ui-color-primary-500);
  --color-primary-600: var(--ui-color-primary-600);
  --color-primary-700: var(--ui-color-primary-700);
  --color-primary-800: var(--ui-color-primary-800);
  --color-primary-900: var(--ui-color-primary-900);
  --color-primary-950: var(--ui-color-primary-950);
  --color-secondary: var(--ui-secondary);
  --color-secondary-50: var(--ui-color-secondary-50);
  --color-secondary-100: var(--ui-color-secondary-100);
  --color-secondary-200: var(--ui-color-secondary-200);
  --color-secondary-300: var(--ui-color-secondary-300);
  --color-secondary-400: var(--ui-color-secondary-400);
  --color-secondary-500: var(--ui-color-secondary-500);
  --color-secondary-600: var(--ui-color-secondary-600);
  --color-secondary-700: var(--ui-color-secondary-700);
  --color-secondary-800: var(--ui-color-secondary-800);
  --color-secondary-900: var(--ui-color-secondary-900);
  --color-secondary-950: var(--ui-color-secondary-950);
  --color-success: var(--ui-success);
  --color-success-50: var(--ui-color-success-50);
  --color-success-100: var(--ui-color-success-100);
  --color-success-200: var(--ui-color-success-200);
  --color-success-300: var(--ui-color-success-300);
  --color-success-400: var(--ui-color-success-400);
  --color-success-500: var(--ui-color-success-500);
  --color-success-600: var(--ui-color-success-600);
  --color-success-700: var(--ui-color-success-700);
  --color-success-800: var(--ui-color-success-800);
  --color-success-900: var(--ui-color-success-900);
  --color-success-950: var(--ui-color-success-950);
  --color-info: var(--ui-info);
  --color-info-50: var(--ui-color-info-50);
  --color-info-100: var(--ui-color-info-100);
  --color-info-200: var(--ui-color-info-200);
  --color-info-300: var(--ui-color-info-300);
  --color-info-400: var(--ui-color-info-400);
  --color-info-500: var(--ui-color-info-500);
  --color-info-600: var(--ui-color-info-600);
  --color-info-700: var(--ui-color-info-700);
  --color-info-800: var(--ui-color-info-800);
  --color-info-900: var(--ui-color-info-900);
  --color-info-950: var(--ui-color-info-950);
  --color-warning: var(--ui-warning);
  --color-warning-50: var(--ui-color-warning-50);
  --color-warning-100: var(--ui-color-warning-100);
  --color-warning-200: var(--ui-color-warning-200);
  --color-warning-300: var(--ui-color-warning-300);
  --color-warning-400: var(--ui-color-warning-400);
  --color-warning-500: var(--ui-color-warning-500);
  --color-warning-600: var(--ui-color-warning-600);
  --color-warning-700: var(--ui-color-warning-700);
  --color-warning-800: var(--ui-color-warning-800);
  --color-warning-900: var(--ui-color-warning-900);
  --color-warning-950: var(--ui-color-warning-950);
  --color-error: var(--ui-error);
  --color-error-50: var(--ui-color-error-50);
  --color-error-100: var(--ui-color-error-100);
  --color-error-200: var(--ui-color-error-200);
  --color-error-300: var(--ui-color-error-300);
  --color-error-400: var(--ui-color-error-400);
  --color-error-500: var(--ui-color-error-500);
  --color-error-600: var(--ui-color-error-600);
  --color-error-700: var(--ui-color-error-700);
  --color-error-800: var(--ui-color-error-800);
  --color-error-900: var(--ui-color-error-900);
  --color-error-950: var(--ui-color-error-950);
  --color-neutral-50: var(--ui-color-neutral-50);
  --color-neutral-100: var(--ui-color-neutral-100);
  --color-neutral-200: var(--ui-color-neutral-200);
  --color-neutral-300: var(--ui-color-neutral-300);
  --color-neutral-400: var(--ui-color-neutral-400);
  --color-neutral-500: var(--ui-color-neutral-500);
  --color-neutral-600: var(--ui-color-neutral-600);
  --color-neutral-700: var(--ui-color-neutral-700);
  --color-neutral-800: var(--ui-color-neutral-800);
  --color-neutral-900: var(--ui-color-neutral-900);
  --color-neutral-950: var(--ui-color-neutral-950);
}

您可以在您的 main.css 文件中更改亮模式和暗模式下每种颜色使用的色调。

app/assets/css/main.css
@import "tailwindcss";
@import "@nuxt/ui";

:root {
  --ui-primary: var(--ui-color-primary-700);
}

.dark {
  --ui-primary: var(--ui-color-primary-200);
}
app/assets/css/main.css
@import "tailwindcss";
@import "@nuxt/ui-pro";

:root {
  --ui-primary: var(--ui-color-primary-700);
}

.dark {
  --ui-primary: var(--ui-color-primary-200);
}

您不能在您的app.config.ts中设置 primary: 'black',因为此颜色没有色调。相反,您可以在 main.css 文件中覆盖 primary 颜色以创建黑白主题。

您不能在您的vite.config.ts中设置 primary: 'black',因为此颜色没有色调。相反,您可以在 main.css 文件中覆盖 primary 颜色以创建黑白主题。

app/assets/css/main.css
@import "tailwindcss";
@import "@nuxt/ui";

:root {
  --ui-primary: black;
}

.dark {
  --ui-primary: white;
}
app/assets/css/main.css
@import "tailwindcss";
@import "@nuxt/ui-pro";

:root {
  --ui-primary: black;
}

.dark {
  --ui-primary: white;
}

中性色

Nuxt UI 为 neutral 颜色调色板提供了一整套设计令牌,确保在亮模式和暗模式下 UI 样式的一致性和可访问性。这些令牌提供了对文本、背景和边框颜色的精细控制。

:root {
  --ui-text-dimmed: var(--ui-color-neutral-400);
  --ui-text-muted: var(--ui-color-neutral-500);
  --ui-text-toned: var(--ui-color-neutral-600);
  --ui-text: var(--ui-color-neutral-700);
  --ui-text-highlighted: var(--ui-color-neutral-900);
  --ui-text-inverted: var(--color-white);

  --ui-bg: var(--color-white);
  --ui-bg-muted: var(--ui-color-neutral-50);
  --ui-bg-elevated: var(--ui-color-neutral-100);
  --ui-bg-accented: var(--ui-color-neutral-200);
  --ui-bg-inverted: var(--ui-color-neutral-900);

  --ui-border: var(--ui-color-neutral-200);
  --ui-border-muted: var(--ui-color-neutral-200);
  --ui-border-accented: var(--ui-color-neutral-300);
  --ui-border-inverted: var(--ui-color-neutral-900);
}

这些 CSS 变量在 Tailwind CSS 的 @theme 中定义,因此您可以将它们用作类。

DimmedMutedTonedTextHighlightedInverted

<template>
  <span class="text-dimmed">Dimmed</span>
  <span class="text-muted">Muted</span>
  <span class="text-toned">Toned</span>
  <span class="text-default">Text</span>
  <span class="text-highlighted">Highlighted</span>
  <span class="text-inverted bg-inverted">Inverted</span>
</template>

DefaultMutedElevatedAccentedInverted

<template>
  <div class="bg-default">Default</div>
  <div class="bg-muted">Muted</div>
  <div class="bg-elevated">Elevated</div>
  <div class="bg-accented">Accented</div>
  <div class="bg-inverted text-inverted">Inverted</div>
</template>

DefaultMutedAccentedInverted

<template>
  <div class="border border-default">Default</div>
  <div class="border border-muted">Muted</div>
  <div class="border border-accented">Accented</div>
  <div class="border border-inverted">Inverted</div>
</template>
以下是 @theme 如何为每个设计令牌生成的。
@theme default {
  --text-color-dimmed: var(--ui-text-dimmed);
  --text-color-muted: var(--ui-text-muted);
  --text-color-toned: var(--ui-text-toned);
  --text-color-default: var(--ui-text);
  --text-color-highlighted: var(--ui-text-highlighted);
  --text-color-inverted: var(--ui-text-inverted);
  --background-color-default: var(--ui-bg);
  --background-color-muted: var(--ui-bg-muted);
  --background-color-elevated: var(--ui-bg-elevated);
  --background-color-accented: var(--ui-bg-accented);
  --background-color-inverted: var(--ui-bg-inverted);
  --background-color-border: var(--ui-border);
  --border-color-default: var(--ui-border);
  --border-color-muted: var(--ui-border-muted);
  --border-color-accented: var(--ui-border-accented);
  --border-color-inverted: var(--ui-border-inverted);
  --ring-color-default: var(--ui-border);
  --ring-color-muted: var(--ui-border-muted);
  --ring-color-accented: var(--ui-border-accented);
  --ring-color-inverted: var(--ui-border-inverted);
  --ring-color-bg: var(--ui-bg);
  --divide-color-default: var(--ui-border);
  --divide-color-muted: var(--ui-border-muted);
  --divide-color-accented: var(--ui-border-accented);
  --divide-color-inverted: var(--ui-border-inverted);
  --outline-color-default: var(--ui-border);
  --outline-color-inverted: var(--ui-border-inverted);
  --stroke-color-default: var(--ui-border);
  --stroke-color-inverted: var(--ui-border-inverted);
  --fill-color-default: var(--ui-border);
  --fill-color-inverted: var(--ui-border-inverted);
}

您可以在您的 main.css 文件中自定义这些 CSS 变量,以调整应用程序的外观。

app/assets/css/main.css
@import "tailwindcss";
@import "@nuxt/ui";

:root {
  --ui-bg: var(--ui-color-neutral-50);
  --ui-text: var(--ui-color-neutral-900);
}

.dark {
  --ui-bg: var(--ui-color-neutral-950);
  --ui-border: var(--ui-color-neutral-900);
}
app/assets/css/main.css
@import "tailwindcss";
@import "@nuxt/ui-pro";

:root {
  --ui-bg: var(--ui-color-neutral-50);
  --ui-text: var(--ui-color-neutral-900);
}

.dark {
  --ui-bg: var(--ui-color-neutral-950);
  --ui-border: var(--ui-color-neutral-900);
}
Nuxt UI 在您应用程序的 <body> 元素上应用文本和背景颜色。
body {
  @apply antialiased text-default bg-default scheme-light dark:scheme-dark;
}

圆角

Nuxt UI 通过 --ui-radius CSS 变量提供了一个集中的边框圆角系统。

:root {
  --ui-radius: 0.25rem;
}

此 CSS 变量取代了 Tailwind CSS 默认的 rounded-* 工具类,因此您可以使用相同的类名。

xssmmdlgxl2xl3xl

<template>
  <div class="rounded-xs">xs</div>
  <div class="rounded-sm">sm</div>
  <div class="rounded-md">md</div>
  <div class="rounded-lg">lg</div>
  <div class="rounded-xl">xl</div>
  <div class="rounded-2xl">2xl</div>
  <div class="rounded-3xl">3xl</div>
</template>
以下是 @theme 如何为每个圆角值生成的。
@theme default {
  --radius-xs: calc(var(--ui-radius) * 0.5);    /* 0.125rem */
  --radius-sm: var(--ui-radius);                /* 0.25rem */
  --radius-md: calc(var(--ui-radius) * 1.5);    /* 0.375rem */
  --radius-lg: calc(var(--ui-radius) * 2);      /* 0.5rem */
  --radius-xl: calc(var(--ui-radius) * 3);      /* 0.75rem */
  --radius-2xl: calc(var(--ui-radius) * 4);     /* 1rem */
  --radius-3xl: calc(var(--ui-radius) * 6);     /* 1.5rem */
}

您可以在您的 main.css 文件中自定义基础圆角值。

app/assets/css/main.css
@import "tailwindcss";
@import "@nuxt/ui";

:root {
  --ui-radius: 0.5rem;
}
app/assets/css/main.css
@import "tailwindcss";
@import "@nuxt/ui-pro";

:root {
  --ui-radius: 0.5rem;
}
尝试使用顶部标题栏中的 主题选择器来改变基础圆角值。

Container

Nuxt UI 提供了一个 --ui-container CSS 变量,用于控制 Container 组件的最大宽度。

:root {
  --ui-container: var(--container-7xl);
}

您可以在您的 main.css 文件中自定义此值,以便在整个应用程序中一致地调整容器宽度。

app/assets/css/main.css
@import "tailwindcss";
@import "@nuxt/ui";

@theme {
  --container-8xl: 90rem;
}

:root {
  --ui-container: var(--container-8xl);
}
app/assets/css/main.css
@import "tailwindcss";
@import "@nuxt/ui-pro";

@theme {
  --container-8xl: 90rem;
}

:root {
  --ui-container: var(--container-8xl);
}

组件主题

Nuxt UI 组件使用Tailwind VariantsAPI 进行样式设置,该 API 提供了创建变体和管理组件样式的强大方法。让我们探讨一下此 API 的主要特性。

插槽

Nuxt UI 中的组件可以有多个 slots,每个代表组件内一个不同的 HTML 元素或部分。这些插槽允许灵活的内容插入和样式设置。以 Card 组件为例。

export default {
  slots: {
    root: 'bg-default ring ring-default divide-y divide-default rounded-lg',
    header: 'p-4 sm:px-6',
    body: 'p-4 sm:p-6',
    footer: 'p-4 sm:px-6'
  }
}

有些组件没有插槽,它们只由一个根元素组成。在这种情况下,主题只定义 base 插槽,例如 Container 组件。

export default {
  base: 'max-w-(--ui-container) mx-auto px-4 sm:px-6 lg:px-8'
}
没有插槽的组件没有ui prop,只有class prop可用来覆盖样式。

变体

Nuxt UI 组件使用 variants 根据 prop 改变 slots 的样式。以下是 Avatar 组件的示例。

src/theme/avatar.ts
export default {
  slots: {
    root: 'inline-flex items-center justify-center shrink-0 select-none overflow-hidden rounded-full align-middle bg-elevated',
    image: 'h-full w-full rounded-[inherit] object-cover'
  },
  variants: {
    size: {
      sm: {
        root: 'size-7 text-sm'
      },
      md: {
        root: 'size-8 text-base'
      },
      lg: {
        root: 'size-9 text-lg'
      }
    }
  },
  defaultVariants: {
    size: 'md'
  }
}

这样,size prop 将把相应的样式应用到 root 插槽。

<template>
  <UAvatar src="https://github.com/nuxt.png" size="lg" />
</template>

defaultVariants 属性指定了每个变体的默认值。它决定了组件在未提供 prop 时的外观和行为。

您可以在您的app.config.ts中自定义这些默认值,以调整应用程序中组件的标准外观。
您可以在您的vite.config.ts中自定义这些默认值,以调整应用程序中组件的标准外观。

自定义主题

您有多种方式自定义 Nuxt UI 组件的外观,可以一次性修改所有组件,也可以按组件进行修改。

Tailwind Variants 使用tailwind-merge在底层合并类,因此您无需担心类冲突。
您可以通过两种方式探索每个组件的主题:
  • 查看每个组件文档中的 Theme 部分。
  • 直接在 GitHub 仓库中浏览源代码:v3/src/theme.

配置

您可以在您的 app.config.ts 中使用与主题对象完全相同的结构,全局覆盖组件主题。

假设您想改变所有按钮的字体粗细,可以这样做:

app.config.ts
export default defineAppConfig({
  ui: {
    button: {
      slots: {
        base: 'font-bold'
      }
    }
  }
})

您可以在您的 vite.config.ts 中使用与主题对象完全相同的结构,全局覆盖组件主题。

假设您想改变所有按钮的字体粗细,可以这样做:

vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        button: {
          slots: {
            base: 'font-bold'
          }
        }
      }
    })
  ]
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import uiPro from '@nuxt/ui-pro/vite'

export default defineConfig({
  plugins: [
    vue(),
    uiPro({
      ui: {
        button: {
          slots: {
            base: 'font-bold'
          }
        }
      }
    })
  ]
})
在此示例中,font-bold 类将覆盖所有按钮默认的 font-medium 类。

Props

ui prop

您还可以使用 ui prop 覆盖组件的 插槽。这优先于全局配置和 variants 解析。

<template>
  <UButton
    trailing-icon="i-lucide-chevron-right"
    size="md"
    color="neutral"
    variant="outline"
    :ui="{
      trailingIcon: 'rotate-90 size-3'
    }"
  >
    Button
  </UButton>
</template>
在此示例中,即使 md 尺寸变体本应向 trailingIcon 插槽应用 size-5 类,它也被 size-3 覆盖。

class prop

class prop 允许您覆盖 rootbase 插槽的类。这优先于全局配置和 variants 解析。

<template>
  <UButton class="font-bold rounded-full">Button</UButton>
</template>
在此示例中,font-bold 类将覆盖此按钮默认的 font-medium 类。