样式

学习如何为您的 Nuxt 应用程序设置样式。

Nuxt 在样式方面高度灵活。你可以编写自己的样式,或引用本地和外部样式表。你可以使用 CSS 预处理器、CSS 框架、UI 库和 Nuxt 模块来为你的应用添加样式。

本地样式表

如果你要编写本地样式表,自然的放置位置是 app/assets/ 目录

在组件中导入

你可以在页面、布局和组件中直接导入样式表。可以使用 JavaScript 导入,或使用 CSS 的 @import 语句

app/pages/index.vue
<script>
// Use a static import for server-side compatibility
import '~/assets/css/first.css'

// Caution: Dynamic imports are not server-side compatible
import('~/assets/css/first.css')
</script>

<style>
@import url("~/assets/css/second.css");
</style>
这些样式表将被内联到 Nuxt 渲染的 HTML 中。

css 属性

你也可以在 Nuxt 配置中使用 css 属性。样式表的自然位置是 app/assets/ 目录。然后你可以引用其路径,Nuxt 会将其包含到应用的所有页面中。

nuxt.config.ts
export default defineNuxtConfig({
  css: ['~/assets/css/main.css'],
})
这些样式表将被内联到 Nuxt 渲染的 HTML 中,作为全局注入并出现在所有页面中。

字体处理

将本地字体文件放在你的 public/ 目录中,例如 public/fonts。然后可以在样式表中使用 url() 来引用它们。

assets/css/main.css
@font-face {
  font-family: 'FarAwayGalaxy';
  src: url('/fonts/FarAwayGalaxy.woff') format('woff');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

然后在样式表、页面或组件中按名称引用你的字体:

<style>
h1 {
  font-family: 'FarAwayGalaxy', sans-serif;
}
</style>

通过 NPM 分发的样式表

你也可以引用通过 npm 分发的样式表。我们以流行的 animate.css 库为例。

npm install animate.css

然后你可以在页面、布局和组件中直接引用它:

app/app.vue
<script>
import 'animate.css'
</script>

<style>
@import url("animate.css");
</style>

该包也可以作为字符串在你的 Nuxt 配置的 css 属性中引用。

nuxt.config.ts
export default defineNuxtConfig({
  css: ['animate.css'],
})

外部样式表

你可以通过在 nuxt.config 文件的 head 部分添加 link 元素来在应用中包含外部样式表。你可以通过不同的方法实现该结果。注意本地样式表也可以通过这种方式包含。

你可以使用 Nuxt 配置的 app.head 属性来操作 head:

nuxt.config.ts
export default defineNuxtConfig({
  app: {
    head: {
      link: [{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css' }],
    },
  },
})

动态添加样式表

你可以在代码中使用 useHead 组合式函数来动态设置 head 的值。

Read more in Docs > 4 X > API > Composables > Use Head.
useHead({
  link: [{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css' }],
})

Nuxt 在底层使用 unhead,你可以参考 它的完整文档

使用 Nitro 插件修改渲染的 head

如果你需要更高级的控制,可以使用钩子拦截渲染的 HTML 并以编程方式修改 head。

~/server/plugins/my-plugin.ts 中创建一个插件,如下所示:

server/plugins/my-plugin.ts
export default defineNitroPlugin((nitro) => {
  nitro.hooks.hook('render:html', (html) => {
    html.head.push('<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css">')
  })
})

外部样式表是阻塞渲染的资源:在浏览器渲染页面之前必须加载和处理它们。包含不必要的大量样式的网页渲染时间会更长。你可以在 web.dev 上阅读更多相关内容。

使用预处理器

要使用像 SCSS、Sass、Less 或 Stylus 这样的预处理器,先安装它们。

npm install -D sass

编写样式表的自然位置是 app/assets 目录。然后你可以在 app.vue(或布局文件)中使用预处理器语法导入源文件。

app/pages/app.vue
<style lang="scss">
@use "~/assets/scss/main.scss";
</style>

或者,你可以使用 Nuxt 配置的 css 属性。

nuxt.config.ts
export default defineNuxtConfig({
  css: ['~/assets/scss/main.scss'],
})
在这两种情况下,编译后的样式表都会被内联到 Nuxt 渲染的 HTML 中。

如果你需要向预处理文件注入代码,例如包含颜色变量的 Sass partial,可以使用 Vite 的 preprocessor options

在你的 app/assets 目录中创建一些 partials:

$primary: #49240F;
$secondary: #E4A79D;

然后在你的 nuxt.config 中:

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

Nuxt 默认使用 Vite。如果你希望改用 webpack,请参考各预处理器 loader 的文档

预处理器 Workers(实验性)

Vite 提供了一个实验性选项,可以加速预处理器的使用。

你可以在 nuxt.config 中启用它:

export default defineNuxtConfig({
  vite: {
    css: {
      preprocessorMaxWorkers: true, // number of CPUs minus 1
    },
  },
})
这是一个实验性选项,请参考 Vite 文档并提供反馈

单文件组件(SFC)样式

Vue 和 SFC 的优点之一是其在样式处理上的良好体验。你可以直接在组件文件的 style 块中编写 CSS 或预处理器代码,从而获得出色的开发体验,而无需使用诸如 CSS-in-JS 的方案。不过如果你希望使用 CSS-in-JS,也可以找到第三方库和模块来支持它,例如 pinceau

你可以参考 Vue 文档 获取有关在 SFC 中为组件添加样式的完整参考。

class 和 style 绑定

你可以利用 Vue SFC 的特性,通过 class 和 style 属性来为组件添加样式。

<script setup lang="ts">
const isActive = ref(true)
const hasError = ref(false)
const classObject = reactive({
  'active': true,
  'text-danger': false,
})
</script>

<template>
  <div
    class="static"
    :class="{ 'active': isActive, 'text-danger': hasError }"
  />
  <div :class="classObject" />
</template>

更多信息请参阅 Vue 文档

使用 v-bind 的动态样式

你可以在 style 块中使用 v-bind 函数引用 JavaScript 变量和表达式。绑定是动态的,意味着如果变量值发生变化,样式会被更新。

<script setup lang="ts">
const color = ref('red')
</script>

<template>
  <div class="text">
    hello
  </div>
</template>

<style>
.text {
  color: v-bind(color);
}
</style>

Scoped 样式

scoped 属性允许你将样式隔离到组件内部。使用此属性声明的样式只会应用于该组件。

<template>
  <div class="example">
    hi
  </div>
</template>

<style scoped>
.example {
  color: red;
}
</style>

CSS Modules

你可以使用带有 module 属性的 CSS Modules。通过注入的 $style 变量访问它。

<template>
  <p :class="$style.red">
    This should be red
  </p>
</template>

<style module>
.red {
  color: red;
}
</style>

预处理器支持

SFC 的 style 块支持预处理器语法。Vite 对 .scss、.sass、.less、.styl 和 .stylus 文件提供开箱即用的支持,无需配置。你只需先安装相应包,然后即可在 SFC 中通过 lang 属性直接使用。

<style lang="scss">
  /* Write scss here */
</style>

你可以参考 Vite CSS 文档@vitejs/plugin-vue 文档。 对于 webpack 用户,请参考 vue loader 文档

使用 PostCSS

Nuxt 内置了 postcss。你可以在 nuxt.config 文件中进行配置。

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

为了在 SFC 中获得正确的语法高亮,你可以使用 postcss 的 lang 属性。

<style lang="postcss">
  /* Write postcss here */
</style>

默认情况下,Nuxt 已经预配置了以下插件:

使用布局实现多套样式

如果你需要对应用的不同部分使用完全不同的样式,可以使用布局。为不同的布局使用不同的样式。

<template>
  <div class="default-layout">
    <h1>Default Layout</h1>
    <slot />
  </div>
</template>

<style>
.default-layout {
  color: red;
}
</style>
Read more in Docs > 4 X > Guide > Directory Structure > App > Layouts.

第三方库和模块

Nuxt 在样式方面不做强制性选择,并为你提供了多种可选方案。你可以使用任何你想要的样式工具,例如流行的库 UnoCSSTailwind CSS

社区和 Nuxt 团队已经开发了许多 Nuxt 模块以简化集成。你可以在网站的 modules 部分 发现它们。以下是一些帮助你入门的模块:

Nuxt 模块为你提供了开箱即用的良好开发体验,但请记住,如果你喜欢的工具没有模块,这并不意味着你不能在 Nuxt 中使用它!你可以为你的项目自行配置。根据不同工具,你可能需要使用 Nuxt 插件 和/或 自己创建模块。如果你这样做了,欢迎与 社区 分享!

轻松加载 Web 字体

你可以使用 Nuxt Google Fonts 模块 来加载 Google 字体。

如果你正在使用 UnoCSS,请注意它自带 web fonts 预设,可以方便地从常见提供者(包括 Google Fonts 等)加载字体。

高级

过渡

Nuxt 提供了与 Vue 相同的 <Transition> 元素,并支持实验性的 View Transitions API

Read more in Docs > 4 X > Getting Started > Transitions.

字体高级优化

我们建议使用 Fontaine 来减少你的 CLS。如果你需要更高级的功能,可以考虑创建一个 Nuxt 模块来扩展构建过程或 Nuxt 运行时。

请始终利用 Web 生态系统中各种可用的工具和技术,使为你的应用添加样式变得更简单、更高效。无论你使用原生 CSS、预处理器、postcss、UI 库还是模块,Nuxt 都能满足你的需求。祝你样式愉快!

LCP 高级优化

你可以通过以下方式加速全局 CSS 文件的下载:

  • 使用 CDN,使文件更靠近你的用户
  • 压缩你的资源,最好使用 Brotli
  • 使用 HTTP2/HTTP3 进行传输
  • 在同一域名下托管资源(不要使用不同的子域)

如果你使用像 Cloudflare、Netlify 或 Vercel 这样的现代平台,其中大多数优化会自动为你完成。 你可以在 web.dev 找到 LCP 优化指南。

如果你的所有 CSS 都被 Nuxt 内联,你可以(实验性地)完全阻止在渲染的 HTML 中引用外部 CSS 文件。 你可以通过一个钩子实现,该钩子可以放在模块中,或放在你的 Nuxt 配置文件中。

nuxt.config.ts
export default defineNuxtConfig({
  hooks: {
    'build:manifest': (manifest) => {
      // find the app entry, css list
      const css = Object.values(manifest).find(options => options.isEntry)?.css
      if (css) {
        // start from the end of the array and go to the beginning
        for (let i = css.length - 1; i >= 0; i--) {
          // if it starts with 'entry', remove it from the list
          if (css[i].startsWith('entry')) {
            css.splice(i, 1)
          }
        }
      }
    },
  },
})