在 Vite 中配置 CSS 模块

你想了解在 Vite 中如何配置和使用 CSS 模块(CSS Modules),这是解决 React 项目中样式命名冲突的核心方案,Vite 对 CSS 模块提供了开箱即用的支持,同时也允许你自定义配置规则。

一、CSS 模块的基础使用(无需额外配置)

Vite 遵循 "约定大于配置" 的原则,只要将样式文件命名为 [name].module.css/[name].module.scss/[name].module.less 格式,就会自动启用 CSS 模块功能。

1. 基础使用示例(以 Scss 为例)

步骤 1:创建 CSS 模块文件(App.module.scss

scss

css 复制代码
// 定义样式类名(可以用驼峰/短横线命名)
.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
}

.title {
  color: #1890ff;
  font-size: 24px;
  font-weight: 600;
}

// 全局样式(:global 包裹,不会被模块化)
:global(.global-btn) {
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
}
步骤 2:在 React 组件中导入并使用

jsx

javascript 复制代码
import React from 'react';
// 导入 CSS 模块(默认导出一个对象,包含所有类名)
import styles from './App.module.scss';

function App() {
  return (
    <div className={styles.container}>
      {/* 使用模块化类名(自动转换为唯一名称) */}
      <h1 className={styles.title}>Vite + React CSS 模块</h1>
      {/* 使用全局样式(直接写类名) */}
      <button className="global-btn">全局按钮</button>
    </div>
  );
}

export default App;

2. 关键特性说明

  • 类名隔离 :Vite 会将 .container 编译为类似 App_container_12345 的唯一类名,避免不同组件样式冲突。
  • :global 关键字:包裹的类名不会被模块化,可用于全局样式。
  • 驼峰转换 :如果类名是 app-title,可以通过 styles.appTitle 访问(兼容短横线命名)。

二、自定义 CSS 模块配置

如果需要修改类名生成规则、指定生效范围等,可以在 vite.config.js 中配置 css.modules 选项,以下是完整的自定义配置示例:

javascript

运行

javascript 复制代码
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';

export default defineConfig({
  plugins: [react()],
  css: {
    // CSS 模块核心配置
    modules: {
      // 1. 自定义类名生成规则(常用)
      // 格式:[name](文件名)、[local](原类名)、[hash](哈希值)
      generateScopedName: '[name]__[local]___[hash:base64:5]',
      
      // 2. 指定哪些文件启用 CSS 模块(默认是 .module.*)
      // 比如让所有 .scss 文件都启用模块化(无需加 .module 后缀)
      // regexp: /.scss$/i,
      
      // 3. 关闭 CSS 模块的警告(比如未使用的类名警告)
      warnOnInvalidSymbols: false,
      
      // 4. 自定义 localsConvention(类名转换规则)
      localsConvention: 'camelCaseOnly', // 仅支持驼峰命名(如 appTitle)
      // 可选值:
      // - 'asIs':不转换(原类名)
      // - 'camelCase':兼容驼峰和短横线(app-title → appTitle)
      // - 'camelCaseOnly':仅驼峰
      // - 'dashes':短横线(默认)
      
      // 5. 生成 CSS 模块类型声明文件(TypeScript 项目推荐)
      generateDeclarations: true,
      
      // 6. 忽略某些文件的模块化(优先级高于 regexp)
      // ignore: /global.scss$/i // 全局样式文件不启用模块化
    },
    // 开发环境生成 SourceMap,方便调试样式
    devSourcemap: true
  },
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src')
    }
  }
});

三、TypeScript 项目适配

如果你的 React 项目使用 TypeScript,直接导入 .module.css/scss/less 文件可能会报 "找不到模块" 的错误,需要添加类型声明:

1. 创建类型声明文件(src/vite-env.d.ts

typescript

运行

typescript 复制代码
/// <reference types="vite/client" />

// 为 CSS 模块添加类型声明
declare module '*.module.css' {
  const classes: { readonly [key: string]: string };
  export default classes;
}

declare module '*.module.scss' {
  const classes: { readonly [key: string]: string };
  export default classes;
}

declare module '*.module.less' {
  const classes: { readonly [key: string]: string };
  export default classes;
}

2. 说明

  • 该文件会告诉 TypeScript 识别 .module.* 后缀的样式文件,并知道其导出的是一个键值对对象。
  • 如果启用了 css.modules.generateDeclarations,Vite 会自动生成 .d.ts 文件,无需手动声明。

四、常见问题解决

  1. 类名访问报错「属性不存在」

    • 检查类名拼写是否一致(比如样式文件中是 appTitle,组件中写了 apptitle)。
    • TypeScript 项目确保添加了上述类型声明文件,或重启 TypeScript 语言服务。
  2. 想让所有样式文件都启用模块化(无需 .module 后缀)

    • css.modules.regexp 中配置匹配规则,比如:

      javascript

      运行

      javascript 复制代码
      modules: {
        regexp: /.scss$/i, // 所有 .scss 文件都启用模块化
      }
  3. 全局样式被模块化

    • 方法 1:使用 :global() 包裹全局类名。
    • 方法 2:创建不含 .module 后缀的样式文件(如 global.scss),直接导入即可。

总结

  1. 基础使用 :样式文件命名为 [name].module.css/scss/less,导入后通过对象访问类名,自动实现样式隔离。
  2. 自定义配置 :通过 vite.config.jscss.modules 可修改类名生成规则、指定模块化文件范围、适配 TypeScript 等。
  3. 关键技巧generateScopedName 控制类名格式,:global 声明全局样式,TypeScript 需添加类型声明文件避免报错。
相关推荐
OpenTiny社区14 小时前
从零开发 AI 聊天页要两周?试试这款 Vue3 垂直对话组件库 TinyRobot,直接开箱即用
前端·vue.js·github
逛逛GitHub14 小时前
2 万多 Star!Google 开源了这个神级 GitHub 项目。
github
逛逛GitHub15 小时前
免费 Token 烧掉 5 万亿之后,他们出了个一站式创作平台。
github
用户8055336980316 小时前
RK-Forge外设系列开篇 - 把板子从「能启动」变成「能用」:Ethernet/SPI/MMC 三个纯接线外设
linux·github·嵌入式
inhere16 小时前
eget:不用等中央仓库,直接安装 GitHub 和任意下载站的工具
程序员·开源·github
YuePeng1 天前
写了五年注解的低代码框架,2.0 决定让你连注解都不用写了
github·产品
小白ai2 天前
从"能 ping 通吗"到"为什么上不了网"——我写了一个网络故障诊断引擎
github
徐小夕2 天前
jitword 协同文档3.2发布:打造浏览器中最强word编辑器
前端·架构·github
齐翊2 天前
分享一个在 Claude Code 里 [同时] 用多个 ApiKey 的方法
程序员·github·agent
A_Lonely_Cat2 天前
记一次 GitHub 幽灵协作者大清洗:强制重写 Git 历史与穿透 CDN 缓存实践
git·github