样式方案

Nuxt 对样式方案几乎不设限:纯 CSS、预处理器、Tailwind / UnoCSS,或 CSS Modules —— 都是“一等公民”。

本地样式文件

把源文件放进 app/assets/,任何组件里都能引用:

<script>
import '~/assets/css/first.css'
</script>

<style>
@import url("~/assets/css/second.css");
</style>

要全局注入,直接在 nuxt.config.ts 中声明:

export default defineNuxtConfig({
  css: ['~/assets/css/main.css'],
})

全局 CSS 会被内联到 SSR HTML,首屏一上来就是带样式的。

外部样式表

从配置里挂 <link>

export default defineNuxtConfig({
  app: {
    head: {
      link: [
        { rel: 'stylesheet', href: 'https://cdn.example.com/reset.css' },
      ],
    },
  },
})

或通过 useHead 动态挂载:

<script setup lang="ts">
useHead({
  link: [{ rel: 'stylesheet', href: 'https://cdn.example.com/theme.css' }],
})
</script>

外部样式表会阻塞渲染,能本地化时尽量本地化。

预处理器(SCSS / Sass / Less / Stylus)

安装预处理器后 Vite 会自动识别:

pnpm add -D sass
<style lang="scss">
@use "~/assets/scss/main.scss";
</style>

或全局注册:

export default defineNuxtConfig({
  css: ['~/assets/scss/main.scss'],
})

想要每个文件都自动注入变量、设计 token?用 Vite 的 preprocessorOptions

export default defineNuxtConfig({
  vite: {
    css: {
      preprocessorOptions: {
        scss: { additionalData: '@use "~/assets/_colors.scss" as *;' },
      },
    },
  },
})

单文件组件样式

这正是 Vue 的强项:

<script setup lang="ts">
const isActive = ref(true)
const color = ref('crimson')
</script>

<template>
  <div :class="['box', { active: isActive }]">
    <p :style="{ color }">hello</p>
  </div>
</template>

<style scoped>
.box { padding: 1rem; }
.active { outline: 2px solid v-bind(color); }
</style>

几个关键特性:

  • scoped —— 样式只作用于本组件。
  • v-bind() —— 在 <style> 中使用响应式值。
  • module —— CSS Modules,通过 $style 访问:
<template>
  <p :class="$style.red">red</p>
</template>
<style module>
.red { color: red; }
</style>
  • lang="scss"(或 sasslessstylus)—— 每个 <style> 块独立选择预处理器。

PostCSS

Nuxt 已经预配置了 postcss-importpostcss-urlautoprefixercssnano。要添加其他插件:

export default defineNuxtConfig({
  postcss: {
    plugins: {
      'postcss-nested': {},
      'postcss-custom-media': {},
    },
  },
})

SFC 里用 <style lang="postcss"> 可以获得正确的语法高亮。

Tailwind CSS / UnoCSS

想用 utility-first 方案,官方模块是最快路径:

pnpm add -D @nuxtjs/tailwindcss
export default defineNuxtConfig({
  modules: ['@nuxtjs/tailwindcss'],
})

或 UnoCSS:

pnpm add -D @unocss/nuxt
export default defineNuxtConfig({
  modules: ['@unocss/nuxt'],
})

两者都会自动注入生成的 CSS,不需要手动 import 'uno.css'

用布局做风格分隔

当应用里不同区域风格差别很大(比如深色后台 vs 亮色营销页),把外壳拆到布局里最干净:

<!-- app/layouts/admin.vue -->
<template>
  <div class="admin-shell"><slot /></div>
</template>

<style>
.admin-shell { background: #0f172a; color: #e2e8f0; }
</style>

策略选择

需求 选什么
工具类 + 小团队 Tailwind / UnoCSS
组件级隔离 <style scoped>
彻底避免类名冲突 <style module>
设计系统 + 设计 token SCSS + additionalData
可定制主题 app.config + CSS 变量

没有所谓“标准答案”,Nuxt 允许你在同一个项目里混着用。

樣式方案

Nuxt 對樣式方案幾乎不設限:純 CSS、預處理器、Tailwind/UnoCSS,或 CSS Modules —— 皆為「一等公民」。

本地樣式檔

把原始檔放於 app/assets/,任一元件皆可引用:

<script>
import '~/assets/css/first.css'
</script>

<style>
@import url("~/assets/css/second.css");
</style>

若要全域注入,於 nuxt.config.ts 宣告:

export default defineNuxtConfig({
  css: ['~/assets/css/main.css'],
})

全域 CSS 會被內嵌到 SSR HTML,首屏即為已套用樣式的版本。

外部樣式表

自設定掛上 <link>

export default defineNuxtConfig({
  app: {
    head: {
      link: [
        { rel: 'stylesheet', href: 'https://cdn.example.com/reset.css' },
      ],
    },
  },
})

或透過 useHead 動態掛載:

<script setup lang="ts">
useHead({
  link: [{ rel: 'stylesheet', href: 'https://cdn.example.com/theme.css' }],
})
</script>

外部樣式表會阻塞渲染,可本地化者盡量本地化。

預處理器(SCSS / Sass / Less / Stylus)

安裝預處理器後 Vite 會自動識別:

pnpm add -D sass
<style lang="scss">
@use "~/assets/scss/main.scss";
</style>

或全域註冊:

export default defineNuxtConfig({
  css: ['~/assets/scss/main.scss'],
})

希望每個檔都自動注入變數、設計 token?使用 Vite 的 preprocessorOptions

export default defineNuxtConfig({
  vite: {
    css: {
      preprocessorOptions: {
        scss: { additionalData: '@use "~/assets/_colors.scss" as *;' },
      },
    },
  },
})

單檔元件樣式

這正是 Vue 的強項:

<script setup lang="ts">
const isActive = ref(true)
const color = ref('crimson')
</script>

<template>
  <div :class="['box', { active: isActive }]">
    <p :style="{ color }">hello</p>
  </div>
</template>

<style scoped>
.box { padding: 1rem; }
.active { outline: 2px solid v-bind(color); }
</style>

重點特性:

  • scoped —— 樣式僅作用於當前元件。
  • v-bind() —— 於 <style> 中使用響應式值。
  • module —— CSS Modules,透過 $style 存取:
<template>
  <p :class="$style.red">red</p>
</template>
<style module>
.red { color: red; }
</style>
  • lang="scss"(或 sasslessstylus)—— 每個 <style> 可單獨選擇預處理器。

PostCSS

Nuxt 已預先設定 postcss-importpostcss-urlautoprefixercssnano。欲追加其他外掛:

export default defineNuxtConfig({
  postcss: {
    plugins: {
      'postcss-nested': {},
      'postcss-custom-media': {},
    },
  },
})

SFC 內使用 <style lang="postcss"> 可獲得正確語法突顯。

Tailwind CSS / UnoCSS

採用 utility-first 方案時,官方模組是最快路徑:

pnpm add -D @nuxtjs/tailwindcss
export default defineNuxtConfig({
  modules: ['@nuxtjs/tailwindcss'],
})

或 UnoCSS:

pnpm add -D @unocss/nuxt
export default defineNuxtConfig({
  modules: ['@unocss/nuxt'],
})

兩者皆會自動注入所產生之 CSS,毋須手動 import 'uno.css'

以佈局區隔風格

當應用不同區域風格差異顯著(如深色後台 vs 淺色行銷頁),把外殼拆到佈局最乾淨:

<!-- app/layouts/admin.vue -->
<template>
  <div class="admin-shell"><slot /></div>
</template>

<style>
.admin-shell { background: #0f172a; color: #e2e8f0; }
</style>

策略選擇

需求 選擇
工具類 + 小團隊 Tailwind / UnoCSS
元件層級隔離 <style scoped>
徹底避免類名衝突 <style module>
設計系統 + 設計 token SCSS + additionalData
可自訂主題 app.config + CSS 變數

沒有所謂「標準答案」,Nuxt 允許你於同一專案混合使用。

Styling

Nuxt is not opinionated about CSS. Write plain CSS, pull in a preprocessor, go all-in on Tailwind or UnoCSS, or embrace CSS Modules — all paths are first-class.

Local stylesheets

Put your source files under app/assets/ and reference them from any component:

<script>
import '~/assets/css/first.css'
</script>

<style>
@import url("~/assets/css/second.css");
</style>

To apply a stylesheet globally, use the css key in nuxt.config.ts:

export default defineNuxtConfig({
  css: ['~/assets/css/main.css'],
})

Nuxt inlines global CSS into the server-rendered HTML, so the first paint is already styled.

External stylesheets

Ship a <link> from your config:

export default defineNuxtConfig({
  app: {
    head: {
      link: [
        { rel: 'stylesheet', href: 'https://cdn.example.com/reset.css' },
      ],
    },
  },
})

Or dynamically via useHead:

<script setup lang="ts">
useHead({
  link: [{ rel: 'stylesheet', href: 'https://cdn.example.com/theme.css' }],
})
</script>

External stylesheets are render-blocking — prefer bundling them when you can.

Preprocessors (SCSS / Sass / Less / Stylus)

Install the preprocessor and Vite picks it up automatically:

pnpm add -D sass
<style lang="scss">
@use "~/assets/scss/main.scss";
</style>

Or register it globally:

export default defineNuxtConfig({
  css: ['~/assets/scss/main.scss'],
})

Need partials injected into every file (design tokens, variables)? Use Vite's preprocessorOptions:

export default defineNuxtConfig({
  vite: {
    css: {
      preprocessorOptions: {
        scss: { additionalData: '@use "~/assets/_colors.scss" as *;' },
      },
    },
  },
})

Single-file component styling

This is where Vue shines. Inside any component:

<script setup lang="ts">
const isActive = ref(true)
const color = ref('crimson')
</script>

<template>
  <div :class="['box', { active: isActive }]">
    <p :style="{ color }">hello</p>
  </div>
</template>

<style scoped>
.box { padding: 1rem; }
.active { outline: 2px solid v-bind(color); }
</style>

Notable features:

  • scoped — styles apply only to this component.
  • v-bind() — reactive values inside <style>.
  • module — CSS Modules via $style:
<template>
  <p :class="$style.red">red</p>
</template>
<style module>
.red { color: red; }
</style>
  • lang="scss" (or sass, less, stylus) — preprocessor per block.

PostCSS

Nuxt ships PostCSS pre-configured with postcss-import, postcss-url, autoprefixer, and cssnano. Add more plugins from nuxt.config.ts:

export default defineNuxtConfig({
  postcss: {
    plugins: {
      'postcss-nested': {},
      'postcss-custom-media': {},
    },
  },
})

Use <style lang="postcss"> for proper highlighting in SFCs.

Tailwind CSS / UnoCSS

For utility-first CSS, both integrate via official modules:

pnpm add -D @nuxtjs/tailwindcss
export default defineNuxtConfig({
  modules: ['@nuxtjs/tailwindcss'],
})

or UnoCSS:

pnpm add -D @unocss/nuxt
export default defineNuxtConfig({
  modules: ['@unocss/nuxt'],
})

Both auto-inject the generated CSS — no manual import 'uno.css' needed.

Layouts as style boundaries

When sections of your app need fundamentally different styling (e.g. a dark admin vs light marketing), layouts are the cleanest split:

<!-- app/layouts/admin.vue -->
<template>
  <div class="admin-shell"><slot /></div>
</template>

<style>
.admin-shell { background: #0f172a; color: #e2e8f0; }
</style>

Choosing a strategy

If you want… Pick
Utility classes, small teams Tailwind / UnoCSS
Component-scoped styles <style scoped>
Class-name collisions impossible <style module>
A design system with tokens SCSS partials + additionalData
A themeable library app.config + CSS variables

There is no wrong answer — Nuxt lets you mix all of them in one app.