Font Optimization and the Font Component in Next.js 16
Next.js course · Module 3: Styling and Visual Optimization
In Metropolis Quantum, city designers know that typography is a key element of the city's visual identity. Every sign, information display, and urban terminal interface uses carefully selected typefaces that are not only aesthetic but also optimized for rendering speed and readability on various devices. In the web world, fonts play a similar role - they are an important design element but can also significantly affect website performance.
Next.js 16 offers an optimized way of managing fonts through the next/font module, available since Next.js 13. In this chapter, we will explore this solution and best practices for font optimization in Next.js applications.
Why is Font Optimization Important?
Custom web fonts can significantly impact page performance:
- Slower page loading - web fonts are additional resources that must be downloaded
- Text flickering (FOUT - Flash of Unstyled Text) - when text initially displays with the default font and then changes to the custom one after it loads
- Invisible text (FOIT - Flash of Invisible Text) - when text is hidden until the font loads
- Impact on Core Web Vitals - especially on Largest Contentful Paint (LCP) and Cumulative Layout Shift (CLS)
The font system in Next.js 16 solves these problems by providing:
- Zero additional HTTP requests to external servers
- Automatic self-hosting of font files
- Automatic fallback system
- No layout shifts
- Built-in font swap hints for browsers
Komponent Font w Next.js 16
Next.js 16 provides the next/font module, which supports:
- Google Fonts (
next/font/google) - Lokalne pliki czcionek (
next/font/local)
Google Fonts
Here is how to use Google Fonts in Next.js 16:
1// app/fonts.ts
2import { Inter, Roboto_Mono } from 'next/font/google';
3
4// Export variables allow reuse of the same font instances
5export const inter = Inter({
6 subsets: ['latin'],
7 display: 'swap',
8});
9
10export const roboto_mono = Roboto_Mono({
11 subsets: ['latin'],
12 display: 'swap',
13 weight: ['400', '700'],
14});Then you can use these fonts in your layout:
1// app/layout.tsx
2import { inter } from './fonts';
3import './globals.css';
4import type { Metadata } from 'next';
5
6export const metadata: Metadata = {
7 title: 'Metropolis Quantum',
8 description: 'Official information portal of the city of the future',
9};
10
11export default function RootLayout({
12 children,
13}: {
14 children: React.ReactNode;
15}) {
16 return (
17 <html lang="pl" className={inter.className}>
18 <body>{children}</body>
19 </html>
20 );
21}Lokalne pliki czcionek
You can also use local font files, which is recommended for custom, non-standard typefaces:
1// app/fonts.ts
2import localFont from 'next/font/local';
3
4export const quantumSans = localFont({
5 src: [
6 {
7 path: '../public/fonts/QuantumSans-Regular.woff2',
8 weight: '400',
9 style: 'normal',
10 },
11 {
12 path: '../public/fonts/QuantumSans-Bold.woff2',
13 weight: '700',
14 style: 'normal',
15 },
16 {
17 path: '../public/fonts/QuantumSans-Italic.woff2',
18 weight: '400',
19 style: 'italic',
20 },
21 ],
22 display: 'swap',
23 variable: '--font-quantum-sans',
24});Font Configuration Options
Komponent Font w Next.js 16 oferuje szereg opcji konfiguracyjnych:
Dla Google Fonts:
1import { Roboto } from 'next/font/google';
2
3const roboto = Roboto({
4 weight: ['400', '700'], // Selecting specific font weights
5 style: ['normal', 'italic'], // Selecting font styles
6 subsets: ['latin'], // Selecting character subsets
7 display: 'swap', // Display strategy: 'auto', 'block', 'swap', 'fallback', 'optional'
8 preload: true, // Whether to preload the font
9 fallback: ['system-ui', 'Arial'], // Czcionki zapasowe
10 adjustFontFallback: true, // Automatyczne dostosowywanie czcionek zapasowych
11 variable: '--font-roboto', // CSS variable if using variable API
12});Dla lokalnych czcionek:
1import localFont from 'next/font/local';
2
3const quantumDisplay = localFont({
4 src: [
5 {
6 path: './fonts/QuantumDisplay-Regular.woff2',
7 weight: '400',
8 style: 'normal',
9 },
10 {
11 path: './fonts/QuantumDisplay-Bold.woff2',
12 weight: '700',
13 style: 'normal',
14 },
15 ],
16 display: 'swap',
17 preload: true,
18 variable: '--font-quantum-display',
19 fallback: ['system-ui', 'Arial'],
20 adjustFontFallback: true,
21});Using Fonts in the Application
1. Global Use for the Entire Application
1// app/layout.tsx
2import { quantumSans } from './fonts';
3import './globals.css';
4
5export default function RootLayout({
6 children,
7}: {
8 children: React.ReactNode;
9}) {
10 return (
11 <html lang="pl" className={quantumSans.className}>
12 <body>{children}</body>
13 </html>
14 );
15}2. Using CSS Variables for Greater Flexibility
1// app/fonts.ts
2import { Inter, Roboto_Mono } from 'next/font/google';
3
4export const inter = Inter({
5 subsets: ['latin'],
6 display: 'swap',
7 variable: '--font-inter',
8});
9
10export const roboto_mono = Roboto_Mono({
11 subsets: ['latin'],
12 display: 'swap',
13 weight: ['400', '700'],
14 variable: '--font-roboto-mono',
15});1// app/layout.tsx
2import { inter, roboto_mono } from './fonts';
3import './globals.css';
4
5export default function RootLayout({
6 children,
7}: {
8 children: React.ReactNode;
9}) {
10 return (
11 <html lang="pl" className={`${inter.variable} ${roboto_mono.variable}`}>
12 <body>{children}</body>
13 </html>
14 );
15}1/* app/globals.css */
2:root {
3 --font-inter: 'Inter', system-ui, sans-serif;
4 --font-roboto-mono: 'Roboto Mono', monospace;
5}
6
7body {
8 font-family: var(--font-inter);
9}
10
11code {
12 font-family: var(--font-roboto-mono);
13}3. Using for Specific Components
1// components/Heading.tsx
2import { quantumDisplay } from '@/app/fonts';
3
4export function Heading({ children }: { children: React.ReactNode }) {
5 return (
6 <h1 className={quantumDisplay.className}>
7 {children}
8 </h1>
9 );
10}Zaawansowane techniki optymalizacji czcionek
1. Optimizing Subsets for Different Languages
If your application supports multiple languages, you can optimize font files by loading only the needed character subsets:
1import { Roboto } from 'next/font/google';
2
3// Dla strony po polsku
4export const robotoPolish = Roboto({
5 subsets: ['latin', 'latin-ext'], // latin-ext contains characters used in Polish
6 weight: ['400', '700'],
7});
8
9// For a Japanese page
10export const robotoJapanese = Roboto({
11 subsets: ['latin', 'japanese'],
12 weight: ['400', '700'],
13});2. Using Variable Fonts
Variable fonts are a modern font format that allows storing multiple styles and weights in a single file, significantly reducing the amount of data to download:
1import { Roboto_Flex } from 'next/font/google';
2
3export const roboto = Roboto_Flex({
4 subsets: ['latin'],
5 display: 'swap',
6 // Variable fonts often offer a wider range of weights
7});3. Preload vs. Lazy loading
By default, Next.js preloads fonts, but you can disable this feature for fonts that are not used immediately:
1import { Roboto } from 'next/font/google';
2
3// Main font, preloaded
4export const robotoMain = Roboto({
5 subsets: ['latin'],
6 weight: ['400', '700'],
7 preload: true,
8});
9
10// Font used only in some components, without preloading
11export const robotoSpecial = Roboto({
12 subsets: ['latin'],
13 weight: ['900'],
14 preload: false,
15});4. Display Strategies (font-display)
The display property determines how the browser should handle the font loading phase:
swap(default): Immediately shows text using the fallback font, swaps it for the custom font when it loads.block: Briefly hides text, then shows it with the fallback font, swaps to the target after loading.fallback: Similar toswap, but with a short period of hidden text. If loading takes too long, the fallback font is used for the session.optional: Similar tofallback, but the browser may completely skip the custom font based on network conditions.
1import { Roboto } from 'next/font/google';
2
3// For main text, we use swap to ensure immediate readability
4export const robotoBody = Roboto({
5 subsets: ['latin'],
6 weight: ['400'],
7 display: 'swap',
8});
9
10// For decorative headings, we can use optional since they are not critical
11export const robotoHeading = Roboto({
12 subsets: ['latin'],
13 weight: ['900'],
14 display: 'optional',
15});Implementation in Different Layouts
1. Basic Layout with Two Fonts
1// app/fonts.ts
2import { Inter, Playfair_Display } from 'next/font/google';
3
4export const inter = Inter({
5 subsets: ['latin'],
6 display: 'swap',
7 variable: '--font-sans',
8});
9
10export const playfair = Playfair_Display({
11 subsets: ['latin'],
12 display: 'swap',
13 variable: '--font-serif',
14});1// app/layout.tsx
2import { inter, playfair } from './fonts';
3import './globals.css';
4
5export default function RootLayout({
6 children,
7}: {
8 children: React.ReactNode;
9}) {
10 return (
11 <html lang="pl" className={`${inter.variable} ${playfair.variable}`}>
12 <body>
13 <header className={playfair.className}>
14 <h1>Metropolis Quantum</h1>
15 </header>
16 <main className={inter.className}>
17 {children}
18 </main>
19 </body>
20 </html>
21 );
22}1/* app/globals.css */
2:root {
3 --font-sans: 'Inter', system-ui, sans-serif;
4 --font-serif: 'Playfair Display', Georgia, serif;
5}
6
7h1, h2, h3, h4, h5, h6 {
8 font-family: var(--font-serif);
9}
10
11body {
12 font-family: var(--font-sans);
13}2. Dashboard with Monospace Font for Data
1// app/dashboard/layout.tsx
2import { roboto_mono } from '../fonts';
3
4export default function DashboardLayout({
5 children,
6}: {
7 children: React.ReactNode;
8}) {
9 return (
10 <div className="dashboard-layout">
11 <div className="sidebar">
12 {/* Sidebar content */}
13 </div>
14 <div className={`content ${roboto_mono.className}`}>
15 {children}
16 </div>
17 </div>
18 );
19}3. Typography Component System
1// components/Typography.tsx
2import { ReactNode } from 'react';
3import { inter, playfair, roboto_mono } from '@/app/fonts';
4
5type FontVariant = 'sans' | 'serif' | 'mono';
6
7interface TypographyProps {
8 children: ReactNode;
9 variant?: FontVariant;
10 as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span' | 'div';
11 className?: string;
12}
13
14export function Typography({
15 children,
16 variant = 'sans',
17 as: Component = 'p',
18 className = '',
19}: TypographyProps) {
20 let fontClass = '';
21
22 switch (variant) {
23 case 'sans':
24 fontClass = inter.className;
25 break;
26 case 'serif':
27 fontClass = playfair.className;
28 break;
29 case 'mono':
30 fontClass = roboto_mono.className;
31 break;
32 }
33
34 return (
35 <Component className={`${fontClass} ${className}`}>
36 {children}
37 </Component>
38 );
39}Example usage:
1// app/page.tsx
2import { Typography } from '@/components/Typography';
3
4export default function HomePage() {
5 return (
6 <div>
7 <Typography as="h1" variant="serif" className="text-4xl mb-4">
8 Witaj w Metropolis Quantum
9 </Typography>
10
11 <Typography variant="sans" className="mb-6">
12 The city of the future where technology meets everyday life.
13 </Typography>
14
15 <div className="code-example">
16 <Typography variant="mono" className="text-sm">
17 console.log("Hello, Quantum World!");
18 </Typography>
19 </div>
20 </div>
21 );
22}Impact on Core Web Vitals
Proper font implementation has a direct impact on key performance metrics:
Largest Contentful Paint (LCP)
Custom fonts can delay the rendering of the largest content element. The Font component in Next.js 16 minimizes this problem by:
- Automatic self-hosting of fonts
- Preloading critical fonts
- Display strategies enabling immediate text rendering
Cumulative Layout Shift (CLS)
Automatic calculation of fallback font sizes minimizes layout shifts when the custom font is finally loaded.
First Input Delay (FID) i Interaction to Next Paint (INP)
Fonts do not have a direct impact on these metrics, but efficient font loading can reduce the load on the browser's main thread.
Analyzing Font Performance
1. Lighthouse
Use the Lighthouse tool to analyze font performance:
- Open Chrome Developer Tools (F12)
- Go to the "Lighthouse" tab
- Zaznacz "Performance" i uruchom test
- Check the "Opportunities" and "Diagnostics" sections for potential font issues
2. Network panel w DevTools
Analyze font loading in the Network tab:
- Filtruj po "Font" lub "Woff2"
- Check download time, file sizes, and loading priority
3. WebPageTest
The WebPageTest tool (webpagetest.org) offers detailed analysis of resource loading, including fonts, on different devices and internet connections.
Best Practices
- Use the Font component from Next.js 16 instead of importing fonts directly from Google Fonts or other external sources
- Limit the number of fonts used to 2-3 families (e.g., one for headings, one for text, possibly one monospace)
- Choose only the needed weights and styles - each additional weight means extra data to download
- Use subsets specific to your application's languages
- Consider variable fonts for families with many weights
- Choose the appropriate display strategy (
display) depending on the font's purpose - Use CSS variables for greater flexibility in styling
- Test performance on different devices and connections
Comprehensive Implementation Example
Below is an example of a comprehensive font system implementation in a Next.js 16 application:
1// app/fonts.ts
2import { Inter, Playfair_Display, Roboto_Mono } from 'next/font/google';
3import localFont from 'next/font/local';
4
5// Main font for text
6export const inter = Inter({
7 subsets: ['latin', 'latin-ext'],
8 display: 'swap',
9 variable: '--font-sans',
10 weight: ['400', '500', '700'],
11});
12
13// Font for headings
14export const playfair = Playfair_Display({
15 subsets: ['latin', 'latin-ext'],
16 display: 'optional',
17 variable: '--font-serif',
18 weight: ['700', '900'],
19});
20
21// Czcionka dla kodu
22export const roboto_mono = Roboto_Mono({
23 subsets: ['latin'],
24 display: 'swap',
25 variable: '--font-mono',
26 weight: ['400', '700'],
27});
28
29// Custom, non-standard font (logo and highlighted elements)
30export const quantumDisplay = localFont({
31 src: [
32 {
33 path: '../public/fonts/QuantumDisplay-Regular.woff2',
34 weight: '400',
35 style: 'normal',
36 },
37 {
38 path: '../public/fonts/QuantumDisplay-Bold.woff2',
39 weight: '700',
40 style: 'normal',
41 },
42 ],
43 display: 'swap',
44 variable: '--font-quantum',
45});1// app/layout.tsx
2import { inter, playfair, roboto_mono, quantumDisplay } from './fonts';
3import './globals.css';
4
5export default function RootLayout({
6 children,
7}: {
8 children: React.ReactNode;
9}) {
10 return (
11 <html lang="pl" className={`
12 ${inter.variable}
13 ${playfair.variable}
14 ${roboto_mono.variable}
15 ${quantumDisplay.variable}
16 `}>
17 <body className={inter.className}>{children}</body>
18 </html>
19 );
20}1/* app/globals.css */
2:root {
3 --font-sans: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
4 --font-serif: 'Playfair Display', Georgia, Cambria, 'Times New Roman', Times, serif;
5 --font-mono: 'Roboto Mono', SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
6 --font-quantum: 'Quantum Display', var(--font-sans);
7
8 /* Font sizes */
9 --fs-xs: 0.75rem;
10 --fs-sm: 0.875rem;
11 --fs-base: 1rem;
12 --fs-lg: 1.125rem;
13 --fs-xl: 1.25rem;
14 --fs-2xl: 1.5rem;
15 --fs-3xl: 1.875rem;
16 --fs-4xl: 2.25rem;
17 --fs-5xl: 3rem;
18
19 /* Line-heights */
20 --lh-tight: 1.25;
21 --lh-snug: 1.375;
22 --lh-normal: 1.5;
23 --lh-relaxed: 1.625;
24 --lh-loose: 2;
25}
26
27body {
28 font-family: var(--font-sans);
29 font-size: var(--fs-base);
30 line-height: var(--lh-normal);
31}
32
33h1, h2, h3, h4, h5, h6 {
34 font-family: var(--font-serif);
35 line-height: var(--lh-tight);
36 font-weight: 700;
37}
38
39h1 {
40 font-size: var(--fs-4xl);
41 margin-bottom: 1.5rem;
42}
43
44h2 {
45 font-size: var(--fs-3xl);
46 margin-bottom: 1.25rem;
47}
48
49.logo {
50 font-family: var(--font-quantum);
51 font-weight: 700;
52}
53
54code, pre {
55 font-family: var(--font-mono);
56 font-size: var(--fs-sm);
57}
58
59.title-quantum {
60 font-family: var(--font-quantum);
61 font-weight: 700;
62 letter-spacing: -0.025em;
63}Common Problems and Their Solutions
Problem 1: FOUT (Flash of Unstyled Text)
Solution: Use display: 'swap' and make sure fonts are preloaded.
Problem 2: Large Font File Sizes
Solution:
- Limit the number of weights and styles
- Use only necessary subsets
- Consider variable fonts
- Optymalizuj pliki WOFF2 (Next.js robi to automatycznie)
Problem 3: Fonts Delay Page Loading
Solution:
- For less critical fonts, use
display: 'optional' - For fonts used only in specific components, disable preloading
Problem 4: Differences in Appearance Between Fallback and Custom Fonts
Solution: Next.js 16 automatically matches fallback font metrics to target fonts, minimizing shifts. You can also use adjustFontFallback: true.
Browser Compatibility
The Font component in Next.js 16 automatically delivers fonts in WOFF2 format, which is supported by all modern browsers. For older browsers that do not support WOFF2, fallback fonts defined in the configuration are displayed.
Support for Languages with Non-Standard Writing Systems
When working with multilingual applications, remember:
- Appropriate subsets for each language
- Larger file sizes for languages with extensive character systems (e.g., Chinese, Japanese)
- Rendering performance - some complex writing systems can burden the browser
1// Example for a multilingual application
2import { Noto_Sans_JP, Noto_Sans } from 'next/font/google';
3
4// For Latin languages (e.g., English, Polish)
5export const notoSansLatin = Noto_Sans({
6 subsets: ['latin', 'latin-ext'],
7 weight: ['400', '700'],
8 variable: '--font-latin',
9});
10
11// For Japanese language
12export const notoSansJP = Noto_Sans_JP({
13 subsets: ['japanese'],
14 weight: ['400', '700'],
15 variable: '--font-japanese',
16});Summary
The Font component in Next.js 16 provides a comprehensive solution for managing and optimizing fonts in web applications:
- Automatic self-hosting - eliminates external HTTP requests
- Optimized WOFF2 format - smaller files to download
- Layout shift prevention - better CLS
- Display strategies - control over font loading behavior
- Preload and lazy loading - optimal use of network bandwidth
Just like in Metropolis Quantum, where every aspect of visual communication is carefully designed and optimized, a well-implemented font system in Next.js 16 ensures the perfect balance between aesthetics and performance. Thanks to the Font component, Next.js applications can offer a consistent, beautiful, and efficient typographic experience without compromising performance.
In the next chapter, we will discuss managing static assets in the public directory, which will allow us to better understand how to efficiently organize and serve different types of resources in Next.js 16 applications.
Code for this lesson: app/components/DesignSystem.tsx
1// Design System - Quantum UI Library
2'use client';
3
4import styles from './DesignSystem.module.css';
5
6// Design Tokens as a const
7export const tokens = {
8 colors: {
9 primary: { main: '#64ffda', light: '#96ffe6', dark: '#32cc99' },
10 secondary: { main: '#448aff', light: '#80b3ff', dark: '#0056cc' },
11 accent: { main: '#7c4dff', light: '#b47cff', dark: '#4400cc' },
12 neutral: { gray900: '#0f0f23', gray700: '#1a1a2e', gray500: '#3d3d55' }
13 },
14 spacing: { xs: '0.25rem', sm: '0.5rem', md: '1rem', lg: '1.5rem', xl: '2rem' },
15 typography: {
16 fontFamily: { primary: 'Inter, sans-serif', mono: 'Fira Code, monospace' },
17 fontSize: { sm: '0.875rem', base: '1rem', lg: '1.125rem', xl: '1.25rem', '2xl': '1.5rem' },
18 fontWeight: { regular: 400, medium: 500, semibold: 600, bold: 700 }
19 },
20 borderRadius: { sm: '0.25rem', md: '0.5rem', lg: '0.75rem', xl: '1rem' },
21 shadows: {
22 sm: '0 2px 8px rgba(0,0,0,0.15)',
23 md: '0 4px 16px rgba(0,0,0,0.25)',
24 lg: '0 8px 32px rgba(0,0,0,0.35)',
25 neon: '0 0 20px rgba(100,255,218,0.5)'
26 }
27};
28
29export default function DesignSystemDemo() {
30 return (
31 <div className={styles.container}>
32 <h1 className={styles.title}>Quantum Design System</h1>
33
34 {/* Color Palette */}
35 <section className={styles.section}>
36 <h2 className={styles.sectionTitle}>Color Palette</h2>
37 <div className={styles.colorGrid}>
38 <div className={styles.colorCard}>
39 <div className={styles.colorSwatch} style={{background: tokens.colors.primary.main}}></div>
40 <p>Primary</p>
41 <code>{tokens.colors.primary.main}</code>
42 </div>
43 <div className={styles.colorCard}>
44 <div className={styles.colorSwatch} style={{background: tokens.colors.secondary.main}}></div>
45 <p>Secondary</p>
46 <code>{tokens.colors.secondary.main}</code>
47 </div>
48 <div className={styles.colorCard}>
49 <div className={styles.colorSwatch} style={{background: tokens.colors.accent.main}}></div>
50 <p>Accent</p>
51 <code>{tokens.colors.accent.main}</code>
52 </div>
53 </div>
54 </section>
55
56 {/* Typography */}
57 <section className={styles.section}>
58 <h2 className={styles.sectionTitle}>Typography Scale</h2>
59 <div className={styles.typographyDemo}>
60 <p style={{fontSize: tokens.typography.fontSize['2xl'], fontWeight: tokens.typography.fontWeight.bold}}>
61 Heading 2XL
62 </p>
63 <p style={{fontSize: tokens.typography.fontSize.xl, fontWeight: tokens.typography.fontWeight.semibold}}>
64 Heading XL
65 </p>
66 <p style={{fontSize: tokens.typography.fontSize.lg, fontWeight: tokens.typography.fontWeight.medium}}>
67 Heading LG
68 </p>
69 <p style={{fontSize: tokens.typography.fontSize.base}}>
70 Body Text Base
71 </p>
72 <p style={{fontSize: tokens.typography.fontSize.sm}}>
73 Small Text
74 </p>
75 </div>
76 </section>
77
78 {/* Component Library */}
79 <section className={styles.section}>
80 <h2 className={styles.sectionTitle}>Component Library</h2>
81
82 {/* Buttons */}
83 <div className={styles.componentGroup}>
84 <h3>Buttons</h3>
85 <div className={styles.buttonShowcase}>
86 <button className={styles.btnPrimary}>Primary</button>
87 <button className={styles.btnSecondary}>Secondary</button>
88 <button className={styles.btnOutline}>Outline</button>
89 <button className={styles.btnGhost}>Ghost</button>
90 </div>
91 </div>
92
93 {/* Cards */}
94 <div className={styles.componentGroup}>
95 <h3>Cards</h3>
96 <div className={styles.cardShowcase}>
97 <div className={styles.card}>
98 <h4>Standard Card</h4>
99 <p>This is a standard card component with consistent padding and styling.</p>
100 </div>
101 <div className={styles.cardElevated}>
102 <h4>Elevated Card</h4>
103 <p>This card has elevated shadow for emphasis.</p>
104 </div>
105 <div className={styles.cardNeon}>
106 <h4>Neon Card</h4>
107 <p>Cyberpunk-styled card with neon glow effect.</p>
108 </div>
109 </div>
110 </div>
111
112 {/* Form Elements */}
113 <div className={styles.componentGroup}>
114 <h3>Form Elements</h3>
115 <div className={styles.formShowcase}>
116 <input type="text" placeholder="Text Input" className={styles.input} />
117 <select className={styles.select}>
118 <option>Select Option</option>
119 <option>Option 1</option>
120 <option>Option 2</option>
121 </select>
122 <textarea placeholder="Textarea" className={styles.textarea}></textarea>
123 </div>
124 </div>
125 </section>
126
127 {/* Spacing System */}
128 <section className={styles.section}>
129 <h2 className={styles.sectionTitle}>Spacing System</h2>
130 <div className={styles.spacingDemo}>
131 {Object.entries(tokens.spacing).map(([key, value]) => (
132 <div key={key} className={styles.spacingItem}>
133 <div className={styles.spacingBar} style={{width: value}}></div>
134 <span>{key}: {value}</span>
135 </div>
136 ))}
137 </div>
138 </section>
139
140 {/* Shadow System */}
141 <section className={styles.section}>
142 <h2 className={styles.sectionTitle}>Shadow System</h2>
143 <div className={styles.shadowGrid}>
144 <div className={styles.shadowBox} style={{boxShadow: tokens.shadows.sm}}>Small</div>
145 <div className={styles.shadowBox} style={{boxShadow: tokens.shadows.md}}>Medium</div>
146 <div className={styles.shadowBox} style={{boxShadow: tokens.shadows.lg}}>Large</div>
147 <div className={styles.shadowBox} style={{boxShadow: tokens.shadows.neon}}>Neon</div>
148 </div>
149 </section>
150 </div>
151 );
152}Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. CSS Grid is used for:
2. Flexbox is best suited for:
Hands-on tasks in the game
- Click in order
Arrange the Tailwind class syntax with responsive breakpoint:
- Code editor
Create a card component using only Tailwind CSS classes (padding, shadow, border-radius, etc.)
- Horizontal ordering
Arrange the CSS Module import syntax in Next.js:
- Click in order
Arrange the CSS Module import syntax in Next.js
- Code editor
Create CSS with optimization techniques: will-change, transform, contain, content-visibility