Chapter 7 of 11
Next.js supports several approaches to styling. The right choice depends on your project's complexity and your personal workflow. We'll cover the three most common: Global CSS, CSS Modules, and Tailwind CSS.
Global CSS works exactly like normal CSS — you write styles in a .css file and they apply to the whole app. Best for base resets, typography, and CSS variables.
/* These styles apply to every page */
body {
margin: 0;
background: #000;
color: white;
font-family: -apple-system, sans-serif;
}
h1 { font-size: 2rem; }
a { color: #0070f3; text-decoration: none; }
a:hover { text-decoration: underline; }import "./globals.css"; // Import in the root layout only — once is enough
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}ANALOGY
Real-world analogy: Uniform ID badges. Imagine two people are both wearing name badges that say 'Manager'. They're in different departments so there's no confusion. CSS Modules work the same way — you can name a class .button in two different component files without conflict. Next.js automatically makes them unique by adding a hash suffix.
.card {
background: #111;
border: 1px solid #222;
border-radius: 12px;
padding: 1.5rem;
}
.title {
font-size: 1.2rem;
font-weight: bold;
color: white;
}
/* These classes get auto-hashed at build time: .card_a8f9x → no collisions */import styles from "./Card.module.css";
export default function Card({ title, children }) {
return (
<div className={styles.card}>
<h2 className={styles.title}>{title}</h2>
{children}
</div>
);
}Tailwind is a utility-first CSS framework. Instead of writing separate CSS files, you apply small utility classes directly in your JSX. It sounds strange at first — but most developers who try it never go back.
export default function CourseCard({ title, level, description }) {
return (
<div className="bg-zinc-900 border border-zinc-800 rounded-xl p-6
hover:border-zinc-600 transition-colors">
<span className="text-xs text-zinc-500 uppercase tracking-wider">
{level}
</span>
<h3 className="text-xl font-bold text-white mt-2 mb-3">
{title}
</h3>
<p className="text-zinc-400 text-sm leading-relaxed">
{description}
</p>
<button className="mt-5 bg-blue-600 text-white text-sm font-semibold
px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors">
Start Learning →
</button>
</div>
);
}NOTE
Tailwind quick reference. Spacing: p-4 (padding), m-4 (margin), gap-4 (flex/grid gap). Typography: text-lg, font-bold, text-zinc-400. Layout: flex, grid, items-center, justify-between. Colors: bg-blue-600, text-white, border-zinc-800. Hover: hover:bg-blue-700. Responsive: md:flex (applies at medium screen width and above).
import Image from "next/image";
export default function CourseThumbnail() {
return (
<Image
src="/nextjs-thumbnail.jpg" // From the /public folder
alt="Next.js course thumbnail"
width={800}
height={400}
priority // Load this image eagerly (above the fold)
className="rounded-xl w-full"
/>
);
}
// Why use next/image over plain <img>?
// ✅ Automatic conversion to WebP (smaller file size)
// ✅ Lazy loads by default (won't load until the user scrolls to it)
// ✅ Prevents layout shift (reserves space before the image loads)
// ✅ Responsive sizes built in