Next.js CSS 样式
·
Next.js CSS 样式学习笔记
Next.js 支持多种 CSS 方案,从传统的 CSS Modules 到现代的 Tailwind CSS,再到 CSS-in-JS,开发者可以根据项目需求灵活选择。
1. 全局样式
1.1 基本用法
全局样式文件通常放在 app/globals.css,并在根布局中引入:
// app/layout.tsx
import './globals.css';
export default function RootLayout({ children }) {
return (
<html lang="zh">
<body>{children}</body>
</html>
);
}
/* app/globals.css */
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background-color: #f5f5f5;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
1.2 CSS 变量(推荐)
Next.js 推荐使用 CSS 变量定义主题:
/* app/globals.css */
:root {
--primary-color: #3b82f6;
--secondary-color: #10b981;
--text-color: #1f2937;
--bg-color: #ffffff;
--border-radius: 8px;
--spacing-unit: 4px;
}
.dark {
--primary-color: #60a5fa;
--text-color: #f3f4f6;
--bg-color: #111827;
}
body {
color: var(--text-color);
background-color: var(--bg-color);
}
.button {
background-color: var(--primary-color);
border-radius: var(--border-radius);
padding: calc(var(--spacing-unit) * 3);
}
2. CSS Modules
CSS Modules 是 Next.js 的默认方案,自动将类名转换为唯一标识,避免样式冲突。
2.1 基本用法
// app/components/Button.tsx
import styles from './Button.module.css';
export default function Button({ children }) {
return <button className={styles.button}>{children}</button>;
}
/* app/components/Button.module.css */
.button {
background-color: #3b82f6;
color: white;
padding: 12px 24px;
border-radius: 8px;
border: none;
cursor: pointer;
}
.button:hover {
background-color: #2563eb;
}
.button:active {
transform: scale(0.98);
}
编译后的类名(自动转换):
<button class="Button_button__abc123">点击我</button>
2.2 组合类名
import styles from './Card.module.css';
export default function Card({ title, content }) {
return (
<div className={`${styles.card} ${styles.shadow}`}>
<h2 className={styles.title}>{title}</h2>
<p className={styles.content}>{content}</p>
</div>
);
}
2.3 动态类名
import styles from './Alert.module.css';
export default function Alert({ type = 'info', children }) {
return (
<div className={`${styles.alert} ${styles[type]}`}>
{children}
</div>
);
}
/* Alert.module.css */
.alert {
padding: 12px;
border-radius: 8px;
}
.info {
background-color: #dbeafe;
color: #1e40af;
}
.warning {
background-color: #fef3c7;
color: #92400e;
}
.error {
background-color: #fee2e2;
color: #991b1b;
}
2.4 全局样式(CSS Modules 中)
/* Button.module.css */
.button {
padding: 12px;
}
/* :global() 中的类名不会被转换 */
:global(.container) {
max-width: 1200px;
margin: 0 auto;
}
3. Tailwind CSS(推荐)
Tailwind CSS 是 Next.js 官方推荐的实用优先 CSS 框架,开发效率极高。
3.1 安装与配置
# 安装 Tailwind CSS
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./src/pages/**/*.{js,ts,jsx,tsx,mdx}',
'./src/components/**/*.{js,ts,jsx,tsx,mdx}',
'./src/app/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {},
},
plugins: [],
};
/* app/globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
3.2 基本用法
export default function Card({ title, content }) {
return (
<div className="max-w-md mx-auto bg-white rounded-lg shadow-md p-6">
<h2 className="text-2xl font-bold text-gray-800 mb-4">{title}</h2>
<p className="text-gray-600 leading-relaxed">{content}</p>
<button className="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition">
了解更多
</button>
</div>
);
}
3.3 响应式设计
export default function ResponsiveCard() {
return (
<div className="
p-4
sm:p-6
md:p-8
lg:p-12
bg-white
rounded-lg
shadow-md
">
<h1 className="
text-xl
sm:text-2xl
md:text-3xl
lg:text-4xl
font-bold
">
响应式标题
</h1>
</div>
);
}
3.4 暗色模式
'use client';
import { useState } from 'react';
export default function DarkModeToggle() {
const [darkMode, setDarkMode] = useState(false);
return (
<div className={darkMode ? 'dark' : ''}>
<button
onClick={() => setDarkMode(!darkMode)}
className="px-4 py-2 bg-gray-200 dark:bg-gray-800 dark:text-white rounded"
>
{darkMode ? '☀️ 亮色' : '🌙 暗色'}
</button>
</div>
);
}
// tailwind.config.js
module.exports = {
darkMode: 'class', // 使用 class 策略
// ...
};
3.5 自定义配置
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
primary: {
50: '#eff6ff',
100: '#dbeafe',
500: '#3b82f6',
600: '#2563eb',
},
},
spacing: {
'128': '32rem',
},
fontFamily: {
sans: ['Inter', 'sans-serif'],
},
},
},
};
// 使用自定义配置
<div className="bg-primary-500 p-128 font-sans">
自定义配置
</div>
4. CSS-in-JS
Next.js 支持多种 CSS-in-JS 库,但需要注意与服务端渲染的兼容性。
4.1 styled-jsx(内置)
Next.js 内置支持,无需额外安装。
export default function Card({ title }) {
return (
<div className="card">
<h2>{title}</h2>
<style jsx>{`
.card {
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
h2 {
color: #1f2937;
font-size: 1.5rem;
margin-bottom: 0.5rem;
}
`}</style>
</div>
);
}
全局样式:
export default function Layout({ children }) {
return (
<div>
{children}
<style jsx global>{`
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
}
`}</style>
</div>
);
}
4.2 styled-components
npm install styled-components
'use client';
import styled from 'styled-components';
const Card = styled.div`
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
h2 {
color: #1f2937;
font-size: 1.5rem;
margin-bottom: 0.5rem;
}
`;
const Button = styled.button`
background-color: #3b82f6;
color: white;
padding: 12px 24px;
border-radius: 8px;
border: none;
cursor: pointer;
&:hover {
background-color: #2563eb;
}
`;
export default function StyledCard({ title }) {
return (
<Card>
<h2>{title}</h2>
<Button>点击我</Button>
</Card>
);
}
服务端渲染配置:
// app/layout.tsx
'use client';
import { ServerStyleSheet } from 'styled-components';
import { useServerInsertedHTML } from 'next/navigation';
export default function RootLayout({ children }) {
useServerInsertedHTML(() => {
const sheet = new ServerStyleSheet();
const styles = sheet.getStyleElement();
return <>{styles}</>;
});
return (
<html lang="zh">
<body>{children}</body>
</html>
);
}
4.3 Emotion
npm install @emotion/react @emotion/styled
'use client';
import styled from '@emotion/styled';
const Card = styled.div`
background-color: white;
padding: 20px;
border-radius: 8px;
`;
export default function EmotionCard({ title }) {
return <Card>{title}</Card>;
}
5. Sass / SCSS
Next.js 原生支持 Sass,无需额外配置。
npm install -D sass
// app/components/Button.module.scss
$primary-color: #3b82f6;
$hover-color: #2563eb;
.button {
background-color: $primary-color;
color: white;
padding: 12px 24px;
border-radius: 8px;
border: none;
cursor: pointer;
&:hover {
background-color: $hover-color;
}
&.large {
padding: 16px 32px;
font-size: 1.1rem;
}
}
import styles from './Button.module.scss';
export default function Button({ children, size = 'normal' }) {
return (
<button className={`${styles.button} ${styles[size]}`}>
{children}
</button>
);
}
6. next/font(字体优化)
Next.js 提供了 next/font 自动优化字体加载,避免布局偏移。
6.1 Google Fonts
// app/layout.tsx
import { Inter } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
variable: '--font-inter',
});
export default function RootLayout({ children }) {
return (
<html lang="zh" className={inter.variable}>
<body>{children}</body>
</html>
);
}
/* app/globals.css */
body {
font-family: var(--font-inter);
}
6.2 本地字体
// app/layout.tsx
import localFont from 'next/font/local';
const myFont = localFont({
src: './fonts/MyFont.woff2',
display: 'swap',
variable: '--font-my-font',
});
export default function RootLayout({ children }) {
return (
<html lang="zh" className={myFont.variable}>
<body>{children}</body>
</html>
);
}
6.3 多字体组合
import { Inter, Playfair_Display } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
variable: '--font-inter',
});
const playfair = Playfair_Display({
subsets: ['latin'],
variable: '--font-playfair',
});
export default function RootLayout({ children }) {
return (
<html lang="zh" className={`${inter.variable} ${playfair.variable}`}>
<body>{children}</body>
</html>
);
}
h1 {
font-family: var(--font-playfair);
}
p {
font-family: var(--font-inter);
}
7. next/image(图片优化)
Next.js 的 <Image> 组件自动优化图片,包括懒加载、格式转换、尺寸适配。
import Image from 'next/image';
export default function ImageExample() {
return (
<div>
{/* 本地图片 */}
<Image
src="/images/logo.png"
alt="Logo"
width={200}
height={100}
/>
{/* 远程图片(需配置域名) */}
<Image
src="https://example.com/image.jpg"
alt="远程图片"
width={800}
height={600}
priority // 首屏图片,优先加载
/>
{/* 响应式图片 */}
<Image
src="/hero.jpg"
alt="Hero"
fill
sizes="(max-width: 768px) 100vw, 50vw"
style={{ objectFit: 'cover' }}
/>
{/* 懒加载(默认) */}
<Image
src="/lazy.jpg"
alt="懒加载图片"
width={400}
height={300}
loading="lazy"
/>
</div>
);
}
配置外部图片域名:
// next.config.js
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
},
{
protocol: 'https',
hostname: '**.cdn.example.com',
},
],
},
};
8. 样式方案对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 全局 CSS | 简单直接 | 容易冲突 | 小型项目、快速原型 |
| CSS Modules | 避免冲突、原生支持 | 类名冗长 | 中型项目、组件库 |
| Tailwind CSS | 开发快、体积小、一致性好 | HTML 冗长、学习成本 | 大型项目、团队协作 |
| styled-jsx | 内置支持、作用域隔离 | 不如其他方案流行 | 简单组件 |
| styled-components | 动态样式强、生态好 | 包体积大、SSR 配置复杂 | 需要动态样式的项目 |
| Emotion | 轻量、性能好 | SSR 配置复杂 | 性能敏感项目 |
| Sass/SCSS | 变量、嵌套、混入 | 需要编译 | 传统项目迁移 |
9. 最佳实践
9.1 样式组织
src/
├── app/
│ └── globals.css # 全局样式、CSS 变量
├── components/
│ ├── Button/
│ │ ├── index.tsx
│ │ └── Button.module.css # 组件样式
│ └── Card/
│ ├── index.tsx
│ └── Card.module.css
└── styles/
├── variables.css # CSS 变量
├── mixins.css # Sass 混入
└── utilities.css # 工具类
9.2 性能优化
// ✅ 使用 CSS Modules 或 Tailwind,避免运行时样式计算
import styles from './Button.module.css';
// ❌ 避免内联样式(除非是动态值)
<button style={{ backgroundColor: color }}>点击</button>
// ✅ 动态值用 CSS 变量
<button style={{ '--color': color } as React.CSSProperties}>点击</button>
/* Button.module.css */
.button {
background-color: var(--color);
}
9.3 响应式设计
// ✅ 使用 Tailwind 的响应式前缀
<div className="p-4 sm:p-6 md:p-8 lg:p-12">
响应式内容
</div>
// ✅ 使用 CSS 媒体查询
/* Card.module.css */
.card {
padding: 16px;
}
@media (min-width: 768px) {
.card {
padding: 24px;
}
}
9.4 暗色模式
// ✅ 使用 CSS 变量 + Tailwind
<div className="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
暗色模式内容
</div>
// ✅ 使用 CSS 变量
:root {
--bg-color: white;
--text-color: black;
}
.dark {
--bg-color: black;
--text-color: white;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
}
10. 完整示例:响应式卡片组件
// app/components/Card.tsx
import Image from 'next/image';
import styles from './Card.module.css';
export default function Card({ title, description, image, tags }) {
return (
<article className={styles.card}>
<div className={styles.imageWrapper}>
<Image
src={image}
alt={title}
fill
sizes="(max-width: 768px) 100vw, 50vw"
className={styles.image}
/>
</div>
<div className={styles.content}>
<h2 className={styles.title}>{title}</h2>
<p className={styles.description}>{description}</p>
<div className={styles.tags}>
{tags.map((tag) => (
<span key={tag} className={styles.tag}>
{tag}
</span>
))}
</div>
</div>
</article>
);
}
/* Card.module.css */
.card {
background-color: white;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
transition: transform 0.2s, box-shadow 0.2s;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.15);
}
.imageWrapper {
position: relative;
aspect-ratio: 16 / 9;
overflow: hidden;
}
.image {
object-fit: cover;
}
.content {
padding: 20px;
}
.title {
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 0.5rem;
color: #1f2937;
}
.description {
color: #6b7280;
line-height: 1.6;
margin-bottom: 1rem;
}
.tags {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.tag {
background-color: #e5e7eb;
color: #374151;
padding: 4px 12px;
border-radius: 9999px;
font-size: 0.875rem;
}
@media (min-width: 768px) {
.content {
padding: 24px;
}
.title {
font-size: 1.75rem;
}
}
总结
| 核心概念 | 要点 |
|---|---|
| 全局样式 | app/globals.css + CSS 变量 |
| CSS Modules | 默认方案,自动类名转换,避免冲突 |
| Tailwind CSS | 官方推荐,实用优先,开发效率高 |
| CSS-in-JS | styled-components / Emotion,动态样式强 |
| 字体优化 | next/font 自动优化,避免布局偏移 |
| 图片优化 | <Image> 组件自动懒加载、格式转换 |
| 最佳实践 | 优先 CSS Modules / Tailwind,动态值用 CSS 变量 |
一句话总结:Next.js 样式方案的核心是模块化 + 性能优化——CSS Modules 避免冲突,Tailwind 提升效率,next/font 和 <Image> 自动优化,CSS 变量实现动态主题。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)