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 langzh 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 ModulesCSS 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);}编译后的类名自动转换buttonclassButton_button__abc123点击我/button2.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 CSSnpminstall-Dtailwindcss 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 */tailwindbase;tailwindcomponents;tailwindutilities;3.2 基本用法export default function Card({ title, content }) { return ( div classNamemax-w-md mx-auto bg-white rounded-lg shadow-md p-6 h2 classNametext-2xl font-bold text-gray-800 mb-4{title}/h2 p classNametext-gray-600 leading-relaxed{content}/p button classNamemt-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)} classNamepx-4 py-2 bg-gray-200 dark:bg-gray-800 dark:text-white rounded {darkMode ? ☀️ 亮色 : 暗色} /button /div ); }// tailwind.config.jsmodule.exports{darkMode:class,// 使用 class 策略// ...};3.5 自定义配置// tailwind.config.jsmodule.exports{theme:{extend:{colors:{primary:{50:#eff6ff,100:#dbeafe,500:#3b82f6,600:#2563eb,},},spacing:{128:32rem,},fontFamily:{sans:[Inter,sans-serif],},},},};// 使用自定义配置 div classNamebg-primary-500 p-128 font-sans 自定义配置 /div4. CSS-in-JSNext.js 支持多种 CSS-in-JS 库但需要注意与服务端渲染的兼容性。4.1 styled-jsx内置Next.js 内置支持无需额外安装。export default function Card({ title }) { return ( div classNamecard 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-componentsnpminstallstyled-componentsuse 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 langzh body{children}/body /html ); }4.3 Emotionnpminstallemotion/react emotion/styleduse 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 / SCSSNext.js 原生支持 Sass无需额外配置。npminstall-Dsass// 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 langzh 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 langzh 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 langzh 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 altLogo width{200} height{100} / {/* 远程图片需配置域名 */} Image srchttps://example.com/image.jpg alt远程图片 width{800} height{600} priority // 首屏图片优先加载 / {/* 响应式图片 */} Image src/hero.jpg altHero fill sizes(max-width: 768px) 100vw, 50vw style{{ objectFit: cover }} / {/* 懒加载默认 */} Image src/lazy.jpg alt懒加载图片 width{400} height{300} loadinglazy / /div ); }配置外部图片域名// next.config.jsmodule.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 classNamep-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 classNamebg-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 6pxrgba(0,0,0,0.1);transition:transform 0.2s,box-shadow 0.2s;}.card:hover{transform:translateY(-4px);box-shadow:0 8px 12pxrgba(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-JSstyled-components / Emotion动态样式强字体优化next/font自动优化避免布局偏移图片优化Image组件自动懒加载、格式转换最佳实践优先 CSS Modules / Tailwind动态值用 CSS 变量一句话总结Next.js 样式方案的核心是模块化 性能优化——CSS Modules 避免冲突Tailwind 提升效率next/font和Image自动优化CSS 变量实现动态主题。