基础篇四 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完整系列,持续更新中。。,欢迎来逛逛


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

相关推荐
Highcharts.js8 小时前
线形比赛积分增长或竞赛图|Highcharts企业图表代码示列
开发语言·前端·javascript·折线图·highcharts·竞赛图
hpysirius8 小时前
在企业搭建一套完整的AI Agent系统
前端
追逐梦想永不停8 小时前
记录一个好用的excel判断数字格式的公式
前端·chrome·excel
hpysirius8 小时前
从零构建 Web 端视频剪辑器:技术实践与思考
前端
让学习成为一种生活方式8 小时前
大肠杆菌合成扑热息痛--对乙酰氨基酚--文献精读227
开发语言·前端·javascript
李白的天不白8 小时前
请求不到百度网址的原因
前端
Gary Studio8 小时前
Selinux编写
linux·服务器·前端
网络点点滴9 小时前
NPM的包版本管理
前端·npm·node.js
光影少年9 小时前
react性能优化比较好的办法有哪些?
前端·react.js·性能优化
fix一个write十个9 小时前
从零搭建音视频通话太痛苦?这个 Vue3 CallKit 让你 5 分钟搞定 1v1 + 群聊通话
前端·vue.js·github