Optymalizacja czcionek i komponent Font w Next.js 16
Kurs Next.js · Moduł 3: Stylowanie i optymalizacja wizualna
W Metropolis Quantum, miejscy projektanci wiedzą, że typografia jest kluczowym elementem tożsamości wizualnej miasta. Każdy znak, informacja czy interfejs miejskich terminali wykorzystuje staranne dobrane kroje pisma, które są nie tylko estetyczne, ale również zoptymalizowane pod kątem szybkości wyświetlania i czytelności na różnych urządzeniach. W świecie webowym, czcionki pełnią podobną rolę - są istotnym elementem projektowym, ale mogą też znacząco wpływać na wydajność stron internetowych.
Next.js 16 oferuje zoptymalizowany sposób zarządzania czcionkami poprzez moduł next/font, dostępny od Next.js 13. Ten rozdział poświęcimy poznaniu tego rozwiązania oraz najlepszym praktykom optymalizacji fontów w aplikacjach Next.js.
Dlaczego optymalizacja czcionek jest ważna?
Niestandardowe czcionki internetowe mogą znacząco wpłynąć na wydajność stron:
- Wolniejsze ładowanie strony - czcionki internetowe to dodatkowe zasoby, które muszą zostać pobrane
- Migotanie tekstu (FOUT - Flash of Unstyled Text) - gdy tekst początkowo wyświetla się domyślną czcionką, a następnie zmienia się na niestandardową po jej załadowaniu
- Niewidoczny tekst (FOIT - Flash of Invisible Text) - gdy tekst jest ukryty do momentu załadowania czcionki
- Impact na Core Web Vitals - zwłaszcza na Largest Contentful Paint (LCP) i Cumulative Layout Shift (CLS)
System fontów w Next.js 16 rozwiązuje te problemy, zapewniając:
- Zero dodatkowych żądań HTTP do zewnętrznych serwerów
- Automatyczne samohostowanie plików czcionek
- Automatyczny system fallbacków
- Brak przesunięć układu (layout shift)
- Wbudowane podpowiedzi podmiany czcionek dla przeglądarek
Komponent Font w Next.js 16
Next.js 16 dostarcza moduł next/font, który obsługuje:
- Google Fonts (
next/font/google) - Lokalne pliki czcionek (
next/font/local)
Google Fonts
Oto jak używać czcionek Google w Next.js 16:
1// app/fonts.ts
2import { Inter, Roboto_Mono } from 'next/font/google';
3
4// Zmienne eksportowe pozwalają na ponowne wykorzystanie tych samych instancji fontów
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});Następnie możesz użyć tych czcionek w swoim layoucie:
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: 'Oficjalny portal informacyjny miasta przyszłości',
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
Możesz również używać lokalnych plików czcionek, co jest zalecane w przypadku własnych, niestandardowych krojów pisma:
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});Opcje konfiguracji fontów
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'], // Wybranie konkretnych wag (grubości) czcionki
5 style: ['normal', 'italic'], // Wybranie stylów czcionki
6 subsets: ['latin'], // Wybranie podzbiorów znaków
7 display: 'swap', // Strategia wyświetlania: 'auto', 'block', 'swap', 'fallback', 'optional'
8 preload: true, // Czy preładować czcionkę
9 fallback: ['system-ui', 'Arial'], // Czcionki zapasowe
10 adjustFontFallback: true, // Automatyczne dostosowywanie czcionek zapasowych
11 variable: '--font-roboto', // Zmienna CSS, jeśli używamy API zmiennych
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});Używanie fontów w aplikacji
1. Globalne użycie dla całej aplikacji
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. Używanie zmiennych CSS dla większej elastyczności
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. Używanie dla konkretnych komponentów
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. Optymalizacja subsets dla różnych języków
Jeśli Twoja aplikacja obsługuje wiele języków, możesz zoptymalizować pliki fontów, ładując tylko potrzebne podzestawy znaków:
1import { Roboto } from 'next/font/google';
2
3// Dla strony po polsku
4export const robotoPolish = Roboto({
5 subsets: ['latin', 'latin-ext'], // latin-ext zawiera znaki używane w języku polskim
6 weight: ['400', '700'],
7});
8
9// Dla strony po japońsku
10export const robotoJapanese = Roboto({
11 subsets: ['latin', 'japanese'],
12 weight: ['400', '700'],
13});2. Używanie czcionek zmiennych (variable fonts)
Czcionki zmienne to nowoczesny format fontów, który pozwala na zapisanie wielu stylów i wag w jednym pliku, co znacznie zmniejsza ilość danych do pobrania:
1import { Roboto_Flex } from 'next/font/google';
2
3export const roboto = Roboto_Flex({
4 subsets: ['latin'],
5 display: 'swap',
6 // Variable fonts często oferują szerszy zakres wag
7});3. Preload vs. Lazy loading
Domyślnie Next.js preładuje czcionki, ale możesz wyłączyć tę funkcję dla czcionek, które nie są używane natychmiast:
1import { Roboto } from 'next/font/google';
2
3// Główna czcionka, preładowana
4export const robotoMain = Roboto({
5 subsets: ['latin'],
6 weight: ['400', '700'],
7 preload: true,
8});
9
10// Czcionka używana tylko w niektórych komponentach, bez preładowania
11export const robotoSpecial = Roboto({
12 subsets: ['latin'],
13 weight: ['900'],
14 preload: false,
15});4. Strategie wyświetlania (font-display)
Właściwość display określa, jak przeglądarka powinna obsługiwać etap ładowania czcionki:
swap(domyślne): Natychmiast pokazuje tekst używając czcionki fallback, zamienia ją na niestandardową czcionkę, gdy ta się załaduje.block: Krótko ukrywa tekst, a następnie pokazuje go z czcionką fallback, zamienia na docelową po załadowaniu.fallback: Podobne doswap, ale z krótkim okresem ukrytego tekstu. Jeśli ładowanie trwa zbyt długo, używana jest czcionka fallback na czas sesji.optional: Podobne dofallback, ale przeglądarka może całkowicie pominąć niestandardową czcionkę, bazując na warunkach sieciowych.
1import { Roboto } from 'next/font/google';
2
3// Dla głównego tekstu, używamy swap, aby zapewnić natychmiastową czytelność
4export const robotoBody = Roboto({
5 subsets: ['latin'],
6 weight: ['400'],
7 display: 'swap',
8});
9
10// Dla ozdobnych nagłówków, możemy użyć optional, gdyż nie są one krytyczne
11export const robotoHeading = Roboto({
12 subsets: ['latin'],
13 weight: ['900'],
14 display: 'optional',
15});Implementacja w różnych układach
1. Podstawowy układ z dwiema czcionkami
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 z czcionką monospacjową dla danych
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. System komponentów typograficznych
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}Przykład użycia:
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 Miasto przyszłości, w którym technologia spotyka się z codziennością.
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}Wpływ na Core Web Vitals
Odpowiednia implementacja fontów ma bezpośredni wpływ na kluczowe metryki wydajności:
Largest Contentful Paint (LCP)
Czcionki niestandardowe mogą opóźnić rendering największego elementu treści. Komponent Font w Next.js 16 minimalizuje ten problem przez:
- Automatyczne samohostowanie fontów
- Preładowanie krytycznych fontów
- Strategie wyświetlania umożliwiające natychmiastowe wyświetlanie tekstu
Cumulative Layout Shift (CLS)
Automatyczne obliczanie rozmiarów fontów fallbackowych minimalizuje przesunięcia układu, gdy niestandardowa czcionka jest ostatecznie ładowana.
First Input Delay (FID) i Interaction to Next Paint (INP)
Czcionki nie mają bezpośredniego wpływu na te metryki, ale efektywne ładowanie fontów może zmniejszyć obciążenie wątku głównego przeglądarki.
Analizowanie wydajności czcionek
1. Lighthouse
Używaj narzędzia Lighthouse do analizy wydajności czcionek:
- Otwórz narzędzia deweloperskie Chrome (F12)
- Przejdź do zakładki "Lighthouse"
- Zaznacz "Performance" i uruchom test
- Sprawdź sekcję "Opportunities" i "Diagnostics" pod kątem potencjalnych problemów z czcionkami
2. Network panel w DevTools
Analizuj ładowanie czcionek w zakładce Network:
- Filtruj po "Font" lub "Woff2"
- Sprawdź czas pobierania, rozmiar plików i priorytet ładowania
3. WebPageTest
Narzędzie WebPageTest (webpagetest.org) oferuje szczegółową analizę ładowania zasobów, w tym czcionek, na różnych urządzeniach i łączach internetowych.
Najlepsze praktyki
- Używaj komponentu Font z Next.js 16 zamiast importowania czcionek bezpośrednio z Google Fonts lub innych zewnętrznych źródeł
- Ogranicz liczbę używanych fontów do 2-3 rodzin (np. jedna dla nagłówków, jedna dla tekstu, ewentualnie jedna monospacjowa)
- Wybieraj tylko potrzebne wagi i style - każda dodatkowa waga to dodatkowe dane do pobrania
- Używaj subsets specyficznych dla języków Twojej aplikacji
- Rozważ czcionki zmienne dla rodzin z wieloma wagami
- Dobieraj odpowiednią strategię wyświetlania (
display) w zależności od przeznaczenia czcionki - Używaj zmiennych CSS dla większej elastyczności w stylizacji
- Testuj wydajność na różnych urządzeniach i połączeniach
Przykład kompleksowej implementacji
Poniżej znajduje się przykład kompleksowej implementacji systemu fontów w aplikacji Next.js 16:
1// app/fonts.ts
2import { Inter, Playfair_Display, Roboto_Mono } from 'next/font/google';
3import localFont from 'next/font/local';
4
5// Główna czcionka dla tekstu
6export const inter = Inter({
7 subsets: ['latin', 'latin-ext'],
8 display: 'swap',
9 variable: '--font-sans',
10 weight: ['400', '500', '700'],
11});
12
13// Czcionka dla nagłówków
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// Własna, niestandardowa czcionka (logo i wyróżnione elementy)
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 /* Rozmiary fontów */
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}Typowe problemy i ich rozwiązania
Problem 1: FOUT (Flash of Unstyled Text)
Rozwiązanie: Używaj display: 'swap' i upewnij się, że czcionki są preładowane.
Problem 2: Duży rozmiar plików czcionek
Rozwiązanie:
- Ograniczaj liczbę wag i stylów
- Używaj tylko niezbędnych subsetów
- Rozważ czcionki zmienne
- Optymalizuj pliki WOFF2 (Next.js robi to automatycznie)
Problem 3: Czcionki opóźniają ładowanie strony
Rozwiązanie:
- Dla mniej krytycznych czcionek używaj
display: 'optional' - Dla czcionek używanych tylko w określonych komponentach wyłącz preładowanie
Problem 4: Różnice w wyglądzie czcionek fallbackowych i niestandardowych
Rozwiązanie: Next.js 16 automatycznie dopasowuje metryki czcionek fallbackowych do docelowych czcionek, minimalizując przesunięcia. Możesz też użyć adjustFontFallback: true.
Kompatybilność z przeglądarkami
Komponent Font w Next.js 16 automatycznie dostarcza czcionki w formacie WOFF2, który jest wspierany przez wszystkie nowoczesne przeglądarki. Dla starszych przeglądarek, które nie obsługują WOFF2, wyświetlane są czcionki fallbackowe zdefiniowane w konfiguracji.
Wsparcie dla języków z niestandardowymi systemami pisma
Przy pracy z aplikacjami wielojęzycznymi, pamiętaj o:
- Odpowiednich subsetach dla każdego języka
- Większych rozmiarach plików dla języków z rozbudowanymi systemami znaków (np. chiński, japoński)
- Wydajności renderingu - niektóre złożone systemy pisma mogą obciążać przeglądarkę
1// Przykład dla aplikacji wielojęzycznej
2import { Noto_Sans_JP, Noto_Sans } from 'next/font/google';
3
4// Dla języka łacińskiego (np. angielski, polski)
5export const notoSansLatin = Noto_Sans({
6 subsets: ['latin', 'latin-ext'],
7 weight: ['400', '700'],
8 variable: '--font-latin',
9});
10
11// Dla języka japońskiego
12export const notoSansJP = Noto_Sans_JP({
13 subsets: ['japanese'],
14 weight: ['400', '700'],
15 variable: '--font-japanese',
16});Podsumowanie
Komponent Font w Next.js 16 zapewnia kompleksowe rozwiązanie dla zarządzania i optymalizacji czcionek w aplikacjach webowych:
- Automatyczne samohostowanie - eliminuje zewnętrzne żądania HTTP
- Zoptymalizowany format WOFF2 - mniejsze pliki do pobrania
- Zapobieganie layout shift - lepsze CLS
- Strategie wyświetlania - kontrola nad sposobem ładowania czcionek
- Preload i lazy loading - optymalne wykorzystanie przepustowości sieci
Podobnie jak w Metropolis Quantum, gdzie każdy aspekt wizualnej komunikacji jest starannie zaprojektowany i zoptymalizowany, dobrze zaimplementowany system czcionek w Next.js 16 zapewnia idealną równowagę między estetyką a wydajnością. Dzięki komponentowi Font, aplikacje Next.js mogą oferować spójne, piękne i efektywne doświadczenie typograficzne bez uszczerbku dla wydajności.
W następnym rozdziale omówimy zarządzanie zasobami statycznymi w katalogu public, co pozwoli nam lepiej zrozumieć, jak efektywnie organizować i obsługiwać różne typy zasobów w aplikacjach Next.js 16.
Kod do tej lekcji: app/components/DesignSystem.tsx
1// Design System - Quantum UI Library
2'use client';
3
4import styles from './DesignSystem.module.css';
5
6// Design Tokens jako 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}Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. CSS Grid służy do:
2. Flexbox najlepiej nadaje się do:
Zadania praktyczne w grze
- Klikanie w kolejności
Ułóż składnię klasy Tailwind z responsive breakpoint:
- Edytor kodu
Utwórz card component używając tylko klas Tailwind CSS (padding, shadow, border-radius, etc.)
- Układanie w poziomie
Ułóż składnię importu CSS Module w Next.js:
- Klikanie w kolejności
Ułóż składnię importu CSS Module w Next.js
- Edytor kodu
Utwórz CSS z techniques optymalizacji: will-change, transform, contain, content-visibility