Next.js
CSS and Styling
Style NewsWave with CSS modules, global styles, Tailwind CSS, and Next.js optimization features to create a professional news website design.
The NewsWave team needs professional styling that looks modern and loads fast. Users judge news websites within seconds. Poor styling equals lost readers. Next.js provides multiple styling approaches that work differently from plain React. Unlike React where you import CSS files and hope for the best, Next.js handles CSS optimization automatically. It bundles styles, removes unused code, and loads only what each page needs. This keeps NewsWave fast even with complex designs. Think of Next.js styling like a smart closet organizer. It knows which clothes you need for each occasion and only packs what's necessary. No more bloated CSS files slowing down your site.Global Styles
Every website needs base styles that apply everywhere. Font families, body margins, heading colors. These global styles create consistency across all pages. Next.js handles global CSS differently from regular React apps. You must import global styles only in the root layout or_app.js file. This prevents duplicate imports and ensures styles load in the correct order. Other components cannot import global CSS files.
Global styles work like house rules. Everyone follows them, no exceptions. Set them once at the top level and every page inherits these base styles automatically.
/* styles/globals.css - Base styles for all NewsWave pages */
* {
margin: 0; /* Remove browser default margins */
padding: 0; /* Remove browser default padding */
box-sizing: border-box; /* Include padding in width calculations */
}
body {
font-family: -apple-system, sans-serif; /* System fonts for speed */
line-height: 1.6; /* Readable text spacing */
color: #334155; /* NewsWave brand color */
}// app/layout.js - Import global styles here only
import './globals.css' // Global styles imported at root level
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body> {/* Global styles apply to everything */}
</html>
)
}Next.js loaded your global CSS once and applied it everywhere. The reset styles removed browser inconsistencies, and the body font now appears on every NewsWave page. Try this: Add a background color to body and watch it appear across all routes.
CSS Modules
CSS Modules solve the biggest problem in web development: naming conflicts. Imagine two developers both creating.header classes. Which style wins? CSS Modules prevent this chaos by making class names locally scoped.
When you create a .module.css file, Next.js automatically generates unique class names. Your .title becomes something like .Header_title__3xKl9. Multiple components can have .title classes without conflicts.
Think of CSS Modules like apartment numbers. Building A has apartment 101, Building B has apartment 101. Same number, different addresses. No confusion because each building manages its own numbering system.
/* components/Header.module.css - Scoped to Header component */
.container {
background: #1e293b; /* Dark header background */
padding: 1rem 2rem; /* Comfortable spacing */
border-bottom: 1px solid #334155; /* Subtle border */
}
.logo {
color: #0ea5e9; /* NewsWave brand blue */
font-size: 1.5rem; /* Prominent size */
font-weight: bold; /* Strong presence */
}// components/Header.js - Using CSS modules
import styles from './Header.module.css' // Import as styles object
export default function Header() {
return (
<header className={styles.container}> {/* becomes unique class name */}
<h1 className={styles.logo}>NewsWave</h1> {/* scoped to this component */}
</header>
)
}Next.js transformed your CSS class names into unique identifiers. Multiple components can now use .container without conflicts. The styles object contains the generated class names. Try this: Create another component with the same class names and see how they remain separate.
Styled JSX
Styled JSX lets you write CSS directly inside React components. No external files, no imports. Just CSS that lives alongside your JSX code. Next.js includes styled-jsx by default, making it zero-config. This approach keeps styles close to the components that use them. When you delete a component, its styles disappear too. No more hunting through CSS files wondering which styles are still needed. Styled JSX works like inline styles but with full CSS power. Media queries, pseudo-selectors, animations. Everything works because it generates real CSS classes behind the scenes.// components/ArticleCard.js - CSS living inside the component
export default function ArticleCard({ title, excerpt }) {
return (
<div className="card">
<h3 className="title">{title}</h3> {/* Styled with CSS below */}
<p className="excerpt">{excerpt}</p>
<style jsx>{`
.card {
border: 1px solid #e2e8f0; /* Clean border */
border-radius: 8px; /* Rounded corners */
padding: 1.5rem; /* Generous padding */
}
`}</style>
</div>
)
}// Dynamic styles based on props
export default function NewsAlert({ type, message }) {
return (
<div className="alert">
{message}
<style jsx>{`
.alert {
padding: 1rem;
border-radius: 6px;
background: ${type === 'urgent' ? '#fef2f2' : '#f0f9ff'}; /* Dynamic color */
color: ${type === 'urgent' ? '#991b1b' : '#1e40af'}; /* Matching text */
}
`}</style>
</div>
)
}Styled JSX generated scoped CSS classes for each component. The dynamic alert changes color based on the type prop. Styles stay bundled with their components and disappear when components are deleted. Try this: Change the type prop values and watch the colors update.
Tailwind CSS Integration
Tailwind CSS provides utility classes that speed up development dramatically. Instead of writing custom CSS, you combine small utility classes to create designs. Next.js works perfectly with Tailwind through official integration. Professional news sites like TechCrunch use utility-first frameworks because they scale better. Design systems emerge naturally. Common patterns get reused. Development teams move faster without wrestling with CSS specificity. Tailwind feels backwards at first. You writebg-blue-500 text-white px-4 py-2 instead of creating a .button class. But this approach prevents the CSS bloat that kills website performance.
// tailwind.config.js - Configure Tailwind for NewsWave
module.exports = {
content: [
'./pages/**/*.{js,ts,jsx,tsx}', // Scan pages for classes
'./components/**/*.{js,ts,jsx,tsx}', // Scan components
'./app/**/*.{js,ts,jsx,tsx}', // Scan app directory
],
theme: {
extend: {
colors: {
newswave: '#0ea5e9', // Custom brand color
}
},
},
}/* styles/globals.css - Add Tailwind directives */
@tailwind base; /* Reset and base styles */
@tailwind components; /* Component layer for custom classes */
@tailwind utilities; /* Utility classes like bg-blue-500 */
/* Custom NewsWave components */
@layer components {
.btn-primary {
@apply bg-newswave text-white px-6 py-2 rounded-lg hover:bg-blue-600;
}
}// components/Hero.js - Using Tailwind classes
export default function Hero() {
return (
<section className="bg-gradient-to-r from-slate-900 to-slate-700 text-white py-16">
<div className="container mx-auto px-4 text-center"> {/* Responsive container */}
<h1 className="text-4xl md:text-6xl font-bold mb-4"> {/* Responsive text */}
Breaking News
</h1>
<p className="text-xl opacity-90 mb-8">Stay informed with NewsWave</p>
<button className="btn-primary">Read Latest</button> {/* Custom component */}
</div>
</section>
)
}Tailwind generated a minimal CSS file containing only the classes you used. The gradient background, responsive text sizing, and custom button component work together seamlessly. Tailwind removed all unused styles during build. Try this: Add new utility classes and see how quickly you can prototype designs.
CSS-in-JS Libraries
CSS-in-JS libraries like styled-components let you write CSS using JavaScript template literals. Styles become React components with props, logic, and full JavaScript power. Next.js supports most CSS-in-JS libraries with some configuration. This approach appeals to developers who prefer keeping everything in JavaScript. No context switching between CSS and JS files. No wondering which styles apply to which components. Everything lives together in component files. But CSS-in-JS has performance costs. Styles generate at runtime, adding JavaScript bundle size. Server-side rendering requires extra configuration. Consider these tradeoffs before choosing this approach for NewsWave.# Install styled-components for NewsWave
npm install styled-components
npm install -D babel-plugin-styled-components// .babelrc - Configure Babel for styled-components SSR
{
"presets": ["next/babel"], // Next.js preset
"plugins": [
["styled-components", {
"ssr": true, // Enable server-side rendering
"displayName": true // Better debugging names
}]
]
}// components/StyledButton.js - CSS-in-JS component
import styled from 'styled-components'
const Button = styled.button`
background: ${props => props.primary ? '#0ea5e9' : '#e2e8f0'}; /* Dynamic styling */
color: ${props => props.primary ? 'white' : '#334155'}; /* Conditional color */
padding: 0.75rem 1.5rem; /* Fixed spacing */
border: none; /* Clean look */
border-radius: 0.5rem; /* Rounded corners */
cursor: pointer; /* Interactive cursor */
&:hover {
opacity: 0.9; /* Hover effect */
}
`
export default function StyledButton({ children, primary }) {
return <Button primary={primary}>{children}</Button>
}The styled-component created a Button element with dynamic styling based on props. JavaScript template literals allowed conditional logic inside CSS. The Babel plugin ensured proper server-side rendering. Try this: Pass different prop values and watch the button styles change automatically.
CSS Optimization
Next.js optimizes CSS automatically to keep NewsWave loading fast. It splits CSS by pages, removes unused code, and minifies everything in production. These optimizations happen behind the scenes without any configuration. Critical CSS gets inlined directly into HTML pages. Users see styled content immediately instead of waiting for external CSS files. Non-critical styles load asynchronously to prevent blocking page rendering. Think of CSS optimization like packing for a trip. Next.js knows exactly which clothes (styles) you need for each destination (page) and packs only essentials in your carry-on (critical CSS). Everything else ships separately but arrives when needed. Modern news sites load thousands of styles across hundreds of pages. Without optimization, every page would download every style. Next.js prevents this waste by analyzing your code and delivering only what each page requires.Automatic Optimizations
CSS splitting by route, unused code removal, minification, and compression
Critical CSS Inlining
Above-the-fold styles embedded in HTML for instant rendering
Dynamic Imports
Component styles loaded only when components are used
Build-time Analysis
Dead code elimination and dependency tree shaking
// next.config.js - Additional CSS optimizations
module.exports = {
experimental: {
optimizeCss: true, // Enable CSS optimization
},
// CSS loader configuration
webpack: (config) => {
config.optimization.splitChunks.cacheGroups.styles = {
name: 'styles', // Bundle CSS together
test: /\.(css|scss|sass)$/, // Match style files
chunks: 'all', // Include all chunks
enforce: true, // Force this rule
}
return config
}
}Next.js analyzed your CSS dependencies and created optimized bundles for each page. Critical styles got inlined for faster rendering. Unused code disappeared from the final build. Production NewsWave now loads only essential styles on each route. Try this: Run the build command and examine the generated CSS files to see the optimizations.
Best Practices
Professional NewsWave styling requires following established patterns that scale across large teams. These practices prevent common pitfalls and ensure consistent performance as your news site grows. Start with global styles for typography and spacing. Use CSS Modules for component-specific styles. Reserve Tailwind for rapid prototyping and utility classes. This hybrid approach gives you flexibility while maintaining organization. Avoid mixing too many styling approaches in the same project. Pick a primary method and stick with it. Mixing CSS Modules, styled-components, and regular CSS creates confusion and increases bundle size unnecessarily.Avoid importing large CSS frameworks entirely. Import only the components or utilities you actually use. Unused CSS hurts performance even after minification because browsers still need to parse all the styles.
.article-header is better than .blue-box because content might change color later.
Organize stylesheets by component hierarchy. Keep related styles together. Delete styles when you delete components. Orphaned CSS accumulates over time and bloats your application unnecessarily.
/* styles/components.css - Organized component styles */
/* Header Components */
.site-header {
position: sticky; /* Stays visible while scrolling */
top: 0; /* Stick to top edge */
background: rgba(30, 41, 59, 0.95); /* Semi-transparent dark */
backdrop-filter: blur(10px); /* Modern glass effect */
}
.navigation-menu {
display: flex; /* Horizontal layout */
gap: 2rem; /* Consistent spacing */
align-items: center; /* Vertical alignment */
}
/* Article Components */
.article-grid {
display: grid; /* CSS Grid layout */
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); /* Responsive columns */
gap: 2rem; /* Space between articles */
}// components/Layout.js - Combining multiple styling approaches
import styles from './Layout.module.css' // Component-specific styles
import { useState } from 'react'
export default function Layout({ children }) {
const [darkMode, setDarkMode] = useState(false) // Theme state
return (
<div className={`${styles.container} ${darkMode ? 'dark' : 'light'}`}>
<header className="site-header"> {/* Global class from components.css */}
<nav className="navigation-menu flex items-center justify-between"> {/* Mix of global and Tailwind */}
<h1 className={styles.logo}>NewsWave</h1> {/* CSS Module class */}
<button
onClick={() => setDarkMode(!darkMode)}
className="bg-gray-200 hover:bg-gray-300 px-4 py-2 rounded" {/* Tailwind utilities */}
>
{darkMode ? '☀️' : '🌙'}
</button>
</nav>
</header>
<main className={styles.content}>{children}</main>
</div>
)
}The layout component combined global CSS classes, CSS Modules, and utility classes effectively. The dark mode toggle demonstrates state-driven styling. The sticky header and responsive grid showcase modern CSS techniques. Try this: Toggle between light and dark modes to see how different styling approaches work together.
Quiz
1. The NewsWave team has multiple developers creating components with similar class names like .header and .container. What Next.js feature prevents naming conflicts?
2. Where must global CSS files be imported in a Next.js application to work properly?
3. How does Next.js optimize CSS performance in production builds?
Up Next: Dynamic Routing
Create NewsWave article pages with URL parameters, nested routes, and programmatic navigation that adapts to any content structure.