基础篇四 Nuxt4 全局样式与 CSS 模块

文章目录

写 CSS 看起来简单,但项目大了问题就来了:类名冲突、样式覆盖、主题切换......Nuxt 提供了多种样式管理方案,今天我们来梳理一下最佳实践。

一、全局样式

全局样式放在 assetscss 目录,在 nuxt.config.ts 中引入:

ts 复制代码
export default defineNuxtConfig({
  css: [
    '~/assets/css/main.css',
    '~/assets/css/reset.css'
  ]
})

创建 assets/css/main.css

css 复制代码
/* 全局变量 */
:root {
  --primary-color: #00dc82;
  --text-color: #333;
  --bg-color: #fff;
  --border-radius: 4px;
}

/* 暗色主题 */
.dark {
  --primary-color: #00b36b;
  --text-color: #fff;
  --bg-color: #1a1a1a;
}

/* 全局基础样式 */
body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  color: var(--text-color);
  background-color: var(--bg-color);
  line-height: 1.6;
}

a {
  color: var(--primary-color);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

二、CSS 变量与主题切换

CSS 变量让主题切换变得简单:

vue 复制代码
<script setup lang="ts">
const isDark = ref(false)

const toggleTheme = () => {
  isDark.value = !isDark.value
  document.documentElement.classList.toggle('dark', isDark.value)
}

// 初始化时检查系统主题
onMounted(() => {
  isDark.value = window.matchMedia('(prefers-color-scheme: dark)').matches
  document.documentElement.classList.toggle('dark', isDark.value)
})
</script>

<template>
  <button @click="toggleTheme">
    {{ isDark ? '🌙' : '☀️' }}
  </button>
</template>

配合 @nuxtjs/color-mode 模块更方便:

bash 复制代码
pnpm add @nuxtjs/color-mode
ts 复制代码
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxtjs/color-mode']
})
vue 复制代码
<script setup lang="ts">
const colorMode = useColorMode()

const toggleTheme = () => {
  colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
}
</script>

<template>
  <button @click="toggleTheme">
    {{ colorMode.value === 'dark' ? '🌙' : '☀️' }}
  </button>
</template>

三、Scoped CSS

组件内的样式使用 scoped 避免污染:

vue 复制代码
<template>
  <div class="card">
    <h2 class="title">标题</h2>
    <p class="content">内容</p>
  </div>
</template>

<style scoped>
.card {
  border: 1px solid #eee;
  border-radius: var(--border-radius);
  padding: 1rem;
}

.title {
  color: var(--primary-color);
  margin-bottom: 0.5rem;
}

.content {
  color: var(--text-color);
}
</style>

scoped 会给样式加上唯一的属性选择器,不会影响其他组件。

四、CSS Modules

想要更严格的类名隔离,用 CSS Modules:

vue 复制代码
<script setup lang="ts">
import styles from './ArticleCard.module.css'
</script>

<template>
  <article :class="styles.card">
    <h2 :class="styles.title">文章标题</h2>
    <p :class="styles.content">文章内容</p>
  </article>
</template>

ArticleCard.module.css

css 复制代码
.card {
  border: 1px solid #eee;
  padding: 1rem;
}

.title {
  color: #333;
}

.content {
  color: #666;
}

编译后类名会变成 _card_abc123 这样的唯一值。

五、Tailwind CSS

Nuxt 对 Tailwind 支持很好:

bash 复制代码
pnpm add -D @nuxtjs/tailwindcss
ts 复制代码
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxtjs/tailwindcss'],
  tailwindcss: {
    cssPath: '~/assets/css/tailwind.css',
    configPath: 'tailwind.config.ts'
  }
})

创建 tailwind.config.ts

ts 复制代码
import type { Config } from 'tailwindcss'

export default {
  content: [
    './components/**/*.{js,vue,ts}',
    './layouts/**/*.vue',
    './pages/**/*.vue',
    './plugins/**/*.{js,ts}',
    './app.vue'
  ],
  theme: {
    extend: {
      colors: {
        primary: '#00dc82'
      }
    }
  }
} satisfies Config

现在可以直接用 Tailwind 类名:

vue 复制代码
<template>
  <div class="p-4 border rounded-lg">
    <h1 class="text-2xl font-bold text-primary">标题</h1>
    <p class="text-gray-600 mt-2">内容</p>
    <button class="mt-4 px-4 py-2 bg-primary text-white rounded hover:opacity-80">
      按钮
    </button>
  </div>
</template>

六、UnoCSS

UnoCSS 是原子化 CSS 引擎,比 Tailwind 更快:

bash 复制代码
pnpm add -D @unocss/nuxt
ts 复制代码
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@unocss/nuxt']
})

创建 uno.config.ts

ts 复制代码
import { defineConfig, presetUno, presetAttributify, presetIcons } from 'unocss'

export default defineConfig({
  presets: [
    presetUno(),
    presetAttributify(),
    presetIcons()
  ]
})

使用方式和 Tailwind 类似:

vue 复制代码
<template>
  <div p-4 border rounded-lg>
    <h1 text-2xl font-bold text-primary>标题</h1>
    <button mt-4 px-4 py-2 bg-primary text-white rounded hover:opacity-80>
      按钮
    </button>
  </div>
</template>

七、预处理器支持

Nuxt 支持 Sass、Less、Stylus 等预处理器:

bash 复制代码
pnpm add -D sass

使用:

vue 复制代码
<style scoped lang="scss">
$primary: #00dc82;

.card {
  border: 1px solid #eee;
  
  .title {
    color: $primary;
    
    &:hover {
      opacity: 0.8;
    }
  }
  
  .content {
    color: #666;
  }
}
</style>

全局 Sass 变量,创建 assets/css/variables.scss

scss 复制代码
$primary: #00dc82;
$text-color: #333;

nuxt.config.ts 配置:

ts 复制代码
export default defineNuxtConfig({
  vite: {
    css: {
      preprocessorOptions: {
        scss: {
          additionalData: '@use "~/assets/css/variables.scss" as *;'
        }
      }
    }
  }
})

现在所有组件都能直接用这些变量:

vue 复制代码
<style scoped lang="scss">
.title {
  color: $primary;  // 直接使用,无需 import
}
</style>

八、PostCSS 配置

Nuxt 内置了 PostCSS,可以添加插件:

ts 复制代码
// nuxt.config.ts
export default defineNuxtConfig({
  postcss: {
    plugins: {
      'postcss-nested': {},  // 支持嵌套
      'autoprefixer': {}     // 自动添加前缀(默认已开启)
    }
  }
})

九、动态样式

根据状态动态改变样式:

vue 复制代码
<script setup lang="ts">
const theme = ref({
  primary: '#00dc82',
  fontSize: '14px'
})

const styleVars = computed(() => ({
  '--primary': theme.value.primary,
  '--font-size': theme.value.fontSize
}))
</script>

<template>
  <div :style="styleVars" class="container">
    <p class="text">这段文字会根据主题变化</p>
    <button @click="theme.primary = '#ff0000'">换成红色</button>
  </div>
</template>

<style scoped>
.text {
  color: var(--primary);
  font-size: var(--font-size);
}
</style>

总结

样式管理方案对比:

方案 特点 适用场景
全局 CSS 简单直接 基础样式、变量
Scoped CSS Vue 原生支持 组件内部样式
CSS Modules 类名隔离严格 大型项目
Tailwind/UnoCSS 原子化、快速 快速开发
Sass/Less 变量、嵌套 复杂样式需求

推荐组合:全局 CSS 变量 + Scoped CSS + Tailwind(可选)

下一篇聊聊静态资源管理,让你的图片、字体管理更规范。

相关文章

入门篇三:Nuxt4组件自动导入:写代码少敲一半字

入门篇二:Nuxt 4路由自动生成:告别手动配置路由的日子

延伸阅读

nuxt4完整系列,持续更新中。。,欢迎来逛逛


内容有帮助?点赞、收藏、关注三连!评论区等你 💪

相关推荐
患得患失9492 小时前
【前端websocket】企业级功能清单
前端·websocket·网络协议
禅思院2 小时前
前端性能优化:从"术"到"道"的完整修炼指南
前端·架构·前端框架
架构师老Y3 小时前
003、Python Web框架深度对比:Django vs Flask vs FastAPI
前端·python·django
小陈工6 小时前
Python Web开发入门(十七):Vue.js与Python后端集成——让前后端真正“握手言和“
开发语言·前端·javascript·数据库·vue.js·人工智能·python
xiaotao13110 小时前
第九章:Vite API 参考手册
前端·vite·前端打包
午安~婉10 小时前
Electron桌面应用聊天(续)
前端·javascript·electron
彧翎Pro11 小时前
基于 RO1 noetic 配置 robosense Helios 32(速腾) & xsense mti 300
前端·jvm
小码哥_常11 小时前
解锁系统设置新姿势:Activity嵌入全解析
前端
之歆11 小时前
前端存储方案对比:Cookie-Session-LocalStorage-IndexedDB
前端