Next.js CSS模块 #
一、CSS模块基础 #
1.1 什么是CSS模块 #
CSS模块是一种CSS文件,默认情况下所有类名和动画名称都在局部作用域内:
css
.button {
background-color: blue;
color: white;
}
1.2 基本用法 #
创建CSS模块
css
.container {
max-width: 1200px;
margin: 0 auto;
padding: 1rem;
}
.title {
font-size: 2rem;
font-weight: bold;
}
使用CSS模块
tsx
import styles from './page.module.css'
export default function Page() {
return (
<div className={styles.container}>
<h1 className={styles.title}>页面标题</h1>
</div>
)
}
1.3 文件命名 #
CSS模块文件必须以 .module.css 结尾:
text
components/
├── Button.tsx
└── Button.module.css
二、局部作用域 #
2.1 类名作用域 #
css
.button {
padding: 0.5rem 1rem;
border-radius: 0.25rem;
}
编译后:
css
.Button_button__hash123 {
padding: 0.5rem 1rem;
border-radius: 0.25rem;
}
2.2 避免命名冲突 #
tsx
import buttonStyles from './Button.module.css'
import cardStyles from './Card.module.css'
export default function Card() {
return (
<div className={cardStyles.container}>
<button className={buttonStyles.button}>
点击
</button>
</div>
)
}
三、类名组合 #
3.1 多个类名 #
tsx
import styles from './page.module.css'
export default function Page() {
return (
<div className={`${styles.container} ${styles.active}`}>
内容
</div>
)
}
3.2 条件类名 #
tsx
import styles from './Button.module.css'
import { cn } from '@/lib/utils'
interface ButtonProps {
variant?: 'primary' | 'secondary'
size?: 'sm' | 'md' | 'lg'
disabled?: boolean
}
export default function Button({
variant = 'primary',
size = 'md',
disabled = false,
}: ButtonProps) {
return (
<button
className={cn(
styles.button,
styles[variant],
styles[size],
disabled && styles.disabled
)}
>
按钮
</button>
)
}
css
.button {
border: none;
cursor: pointer;
}
.primary {
background-color: blue;
color: white;
}
.secondary {
background-color: gray;
color: white;
}
.sm {
padding: 0.25rem 0.5rem;
font-size: 0.875rem;
}
.md {
padding: 0.5rem 1rem;
font-size: 1rem;
}
.lg {
padding: 0.75rem 1.5rem;
font-size: 1.125rem;
}
.disabled {
opacity: 0.5;
cursor: not-allowed;
}
3.3 使用clsx #
bash
npm install clsx
tsx
import styles from './Button.module.css'
import clsx from 'clsx'
export default function Button({ variant, size, disabled }) {
return (
<button
className={clsx(
styles.button,
styles[variant],
styles[size],
{
[styles.disabled]: disabled,
}
)}
>
按钮
</button>
)
}
四、CSS变量 #
4.1 定义变量 #
css
:root {
--primary-color: #3b82f6;
--secondary-color: #64748b;
--text-color: #1f2937;
--background-color: #ffffff;
}
.container {
background-color: var(--background-color);
color: var(--text-color);
}
.button {
background-color: var(--primary-color);
}
4.2 组件级变量 #
css
.card {
--card-padding: 1rem;
--card-radius: 0.5rem;
padding: var(--card-padding);
border-radius: var(--card-radius);
}
.cardLarge {
--card-padding: 2rem;
--card-radius: 1rem;
}
4.3 动态变量 #
tsx
import styles from './Theme.module.css'
export default function ThemeCard({ color }: { color: string }) {
return (
<div
className={styles.card}
style={{ '--accent-color': color } as React.CSSProperties}
>
内容
</div>
)
}
css
.card {
border: 2px solid var(--accent-color, gray);
}
五、组合与继承 #
5.1 composes #
css
.baseButton {
padding: 0.5rem 1rem;
border-radius: 0.25rem;
cursor: pointer;
}
.primaryButton {
composes: baseButton;
background-color: blue;
color: white;
}
.secondaryButton {
composes: baseButton;
background-color: gray;
color: white;
}
5.2 从其他文件组合 #
css
.common {
padding: 1rem;
margin: 1rem;
}
css
.card {
composes: common from './common.module.css';
background-color: white;
border-radius: 0.5rem;
}
5.3 多重组合 #
css
.base {
padding: 1rem;
}
.rounded {
border-radius: 0.5rem;
}
.shadow {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.card {
composes: base;
composes: rounded;
composes: shadow;
background-color: white;
}
六、全局样式 #
6.1 :global选择器 #
css
:global(.external-class) {
color: red;
}
.container :global(.third-party-class) {
margin: 1rem;
}
6.2 全局样式文件 #
css
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: system-ui, -apple-system, sans-serif;
line-height: 1.6;
}
a {
color: inherit;
text-decoration: none;
}
6.3 在布局中导入 #
tsx
import './globals.css'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="zh-CN">
<body>{children}</body>
</html>
)
}
七、响应式设计 #
7.1 媒体查询 #
css
.container {
padding: 1rem;
}
@media (min-width: 640px) {
.container {
padding: 2rem;
}
}
@media (min-width: 1024px) {
.container {
padding: 3rem;
}
}
7.2 响应式组件 #
css
.grid {
display: grid;
gap: 1rem;
grid-template-columns: 1fr;
}
@media (min-width: 640px) {
.grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (min-width: 1024px) {
.grid {
grid-template-columns: repeat(3, 1fr);
}
}
7.3 响应式字体 #
css
.title {
font-size: 1.5rem;
}
@media (min-width: 640px) {
.title {
font-size: 2rem;
}
}
@media (min-width: 1024px) {
.title {
font-size: 2.5rem;
}
}
八、最佳实践 #
8.1 组织CSS模块 #
text
components/
├── Button/
│ ├── Button.tsx
│ ├── Button.module.css
│ └── index.ts
├── Card/
│ ├── Card.tsx
│ └── Card.module.css
└── Layout/
├── Header.module.css
└── Footer.module.css
8.2 命名约定 #
css
.container {}
.header {}
.content {}
.footer {}
.title {}
.subtitle {}
.description {}
.button {}
.buttonPrimary {}
.buttonSecondary {}
.input {}
.label {}
8.3 变量管理 #
css
:root {
--color-primary: #3b82f6;
--color-secondary: #64748b;
--color-success: #22c55e;
--color-error: #ef4444;
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 2rem;
--radius-sm: 0.25rem;
--radius-md: 0.5rem;
--radius-lg: 1rem;
}
九、总结 #
CSS模块要点:
| 要点 | 说明 |
|---|---|
| 局部作用域 | 类名自动添加哈希 |
| 文件命名 | *.module.css |
| 类名组合 | clsx/classnames |
| CSS变量 | :root定义 |
| composes | 样式组合 |
| 全局样式 | :global选择器 |
下一步,让我们学习Tailwind CSS!
最后更新:2026-03-28