Kurs HTML i CSS · Moduł 5: Responsywność
Projekt główny - Responsywna Galeria Portfolio Fotografa
W tej lekcji7
Znajomy fotograf potrzebuje strony, która pokaże jego zdjęcia równie dobrze na telefonie klienta, jak na monitorze w biurze. W tym projekcie stworzymy profesjonalną, w pełni responsywną galerię portfolio fotografa. Wykorzystamy wszystkie techniki z tego modułu: media queries, jednostki responsywne (vw, vh), viewport, optymalizację obrazów oraz podejście mobile-first. Galeria będzie zawierać nawigację, sekcję hero, siatkę zdjęć z efektami hover, filtrowanie kategorii oraz lightbox do przeglądania zdjęć.
Opis projektu
Nasza galeria portfolio będzie miała następujące funkcjonalności:
- Responsywna nawigacja - hamburger menu na urządzeniach mobilnych
- Sekcja Hero - pełnoekranowa z wykorzystaniem jednostek viewport
- Galeria zdjęć - responsywna siatka z efektami hover
- Filtrowanie kategorii - przyciski filtrowania z interaktywnym designem
- Lightbox - przeglądanie zdjęć w powiększeniu
- Optymalizacja obrazów - różne rozmiary dla różnych urządzeń
Krok 1: Struktura HTML z podejściem Mobile-First
Zaczynamy od struktury HTML pisanej z myślą o telefonach. Zwróć uwagę na znacznik viewport w head i na elementy picture w galerii:
1<!DOCTYPE html>
2<html lang="pl">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>Jan Kowalski - Portfolio Fotografa</title>
7 <link rel="stylesheet" href="styles.css">
8</head>
9<body>
10 <!-- Nawigacja -->
11 <nav class="navbar">
12 <div class="nav-container">
13 <div class="nav-logo">JK Photography</div>
14 <button class="nav-toggle" aria-label="Menu">
15 <span></span>
16 <span></span>
17 <span></span>
18 </button>
19 <ul class="nav-menu">
20 <li><a href="#home">Start</a></li>
21 <li><a href="#portfolio">Portfolio</a></li>
22 <li><a href="#about">O mnie</a></li>
23 <li><a href="#contact">Kontakt</a></li>
24 </ul>
25 </div>
26 </nav>
27
28 <!-- Sekcja Hero -->
29 <section id="home" class="hero">
30 <div class="hero-content">
31 <h1 class="hero-title">Jan Kowalski</h1>
32 <p class="hero-subtitle">Fotografia jest moją pasją</p>
33 <a href="#portfolio" class="hero-button">Zobacz portfolio</a>
34 </div>
35 <div class="hero-overlay"></div>
36 </section>
37
38 <!-- Sekcja Portfolio -->
39 <section id="portfolio" class="portfolio">
40 <div class="container">
41 <h2 class="section-title">Moje Portfolio</h2>
42
43 <!-- Filtry kategorii -->
44 <div class="filter-buttons">
45 <button class="filter-btn active" data-filter="all">Wszystkie</button>
46 <button class="filter-btn" data-filter="nature">Natura</button>
47 <button class="filter-btn" data-filter="portrait">Portrety</button>
48 <button class="filter-btn" data-filter="architecture">Architektura</button>
49 </div>
50
51 <!-- Galeria -->
52 <div class="gallery">
53 <div class="gallery-item" data-category="nature">
54 <picture>
55 <source media="(max-width: 768px)" srcset="img/nature1-mobile.jpg">
56 <source media="(max-width: 1200px)" srcset="img/nature1-tablet.jpg">
57 <img src="img/nature1-desktop.jpg" alt="Krajobraz górski">
58 </picture>
59 <div class="gallery-overlay">
60 <h3>Krajobraz górski</h3>
61 <p>Natura</p>
62 </div>
63 </div>
64
65 <div class="gallery-item" data-category="portrait">
66 <picture>
67 <source media="(max-width: 768px)" srcset="img/portrait1-mobile.jpg">
68 <source media="(max-width: 1200px)" srcset="img/portrait1-tablet.jpg">
69 <img src="img/portrait1-desktop.jpg" alt="Portret kobiety">
70 </picture>
71 <div class="gallery-overlay">
72 <h3>Portret</h3>
73 <p>Portrety</p>
74 </div>
75 </div>
76
77 <!-- Więcej elementów galerii... -->
78 </div>
79 </div>
80 </section>
81
82 <!-- Lightbox -->
83 <div class="lightbox" id="lightbox">
84 <span class="lightbox-close">×</span>
85 <img class="lightbox-content" id="lightbox-img">
86 <div class="lightbox-caption"></div>
87 </div>
88</body>
89</html>Przycisk nav-toggle to hamburger, a jego aria-label mówi czytnikom ekranu, do czego służy. Atrybuty data-category przygotowują filtrowanie. Hamburger, filtry i lightbox ożyją dopiero ze skryptem, który napiszesz po poznaniu JavaScriptu, a CSS przygotuje dla nich stany z klasą active.
Krok 2: CSS Mobile-First z jednostkami responsywnymi
Stylowanie zaczynamy od telefonów i dzielimy arkusz na cztery etapy. Pierwszy to reset, zmienne CSS zapisane raz w :root i wstawiane przez var(), oraz nawigacja z menu schowanym pod hamburgerem:
1/* Reset i podstawowe style */
2* {
3 margin: 0;
4 padding: 0;
5 box-sizing: border-box;
6}
7
8:root {
9 --primary-color: #333;
10 --secondary-color: #f4f4f4;
11 --accent-color: #ff6b6b;
12 --text-light: #fff;
13 --overlay-dark: rgba(0, 0, 0, 0.7);
14}
15
16body {
17 font-family: 'Arial', sans-serif;
18 line-height: 1.6;
19 color: var(--primary-color);
20}
21
22/* Nawigacja - Mobile First */
23.navbar {
24 background-color: var(--primary-color);
25 padding: 1rem;
26 position: fixed;
27 width: 100%;
28 top: 0;
29 z-index: 1000;
30}
31
32.nav-container {
33 display: flex;
34 justify-content: space-between;
35 align-items: center;
36}
37
38.nav-logo {
39 color: var(--text-light);
40 font-size: 1.5rem;
41 font-weight: bold;
42}
43
44/* Hamburger menu dla mobile */
45.nav-toggle {
46 background: none;
47 border: none;
48 cursor: pointer;
49 display: flex;
50 flex-direction: column;
51 gap: 4px;
52}
53
54.nav-toggle span {
55 width: 25px;
56 height: 3px;
57 background-color: var(--text-light);
58 transition: all 0.3s ease;
59}
60
61.nav-menu {
62 position: absolute;
63 top: 100%;
64 left: 0;
65 width: 100%;
66 background-color: var(--primary-color);
67 list-style: none;
68 display: none;
69 flex-direction: column;
70}
71
72.nav-menu.active {
73 display: flex;
74}
75
76.nav-menu li {
77 padding: 1rem;
78 text-align: center;
79}
80
81.nav-menu a {
82 color: var(--text-light);
83 text-decoration: none;
84 transition: color 0.3s ease;
85}box-sizing: border-box sprawia, że wypełnienie nie poszerza elementów. Pasek z position: fixed zostaje na górze podczas przewijania, a menu z display: none czeka, aż skrypt doda mu klasę active. Drugi etap to sekcja hero, portfolio i filtry:
1/* Hero section z jednostkami viewport */
2.hero {
3 height: 100vh;
4 width: 100vw;
5 position: relative;
6 display: flex;
7 align-items: center;
8 justify-content: center;
9 background-image: url('img/hero-mobile.jpg');
10 background-size: cover;
11 background-position: center;
12}
13
14.hero-overlay {
15 position: absolute;
16 top: 0;
17 left: 0;
18 width: 100%;
19 height: 100%;
20 background-color: var(--overlay-dark);
21}
22
23.hero-content {
24 position: relative;
25 z-index: 1;
26 text-align: center;
27 color: var(--text-light);
28 padding: 0 1rem;
29}
30
31.hero-title {
32 font-size: clamp(2rem, 8vw, 4rem);
33 margin-bottom: 1rem;
34}
35
36.hero-subtitle {
37 font-size: clamp(1rem, 4vw, 1.5rem);
38 margin-bottom: 2rem;
39}
40
41.hero-button {
42 display: inline-block;
43 padding: 0.8rem 2rem;
44 background-color: var(--accent-color);
45 color: var(--text-light);
46 text-decoration: none;
47 border-radius: 5px;
48 transition: all 0.3s ease;
49}
50
51/* Portfolio section */
52.portfolio {
53 padding: 4rem 1rem;
54 background-color: var(--secondary-color);
55}
56
57.container {
58 max-width: 1200px;
59 margin: 0 auto;
60}
61
62.section-title {
63 text-align: center;
64 font-size: clamp(1.5rem, 5vw, 2.5rem);
65 margin-bottom: 2rem;
66}
67
68/* Filtry */
69.filter-buttons {
70 display: flex;
71 flex-wrap: wrap;
72 justify-content: center;
73 gap: 0.5rem;
74 margin-bottom: 2rem;
75}
76
77.filter-btn {
78 padding: 0.5rem 1rem;
79 border: 2px solid var(--primary-color);
80 background-color: transparent;
81 cursor: pointer;
82 transition: all 0.3s ease;
83 border-radius: 25px;
84}
85
86.filter-btn.active,
87.filter-btn:hover {
88 background-color: var(--primary-color);
89 color: var(--text-light);
90}height: 100vh to cała wysokość okna. clamp(2rem, 8vw, 4rem) przyjmuje minimum, wartość preferowaną i maksimum, więc tytuł rośnie z ekranem, ale nie spada poniżej 2rem ani nie przekracza 4rem. Kontener z max-width: 1200px trzyma treść pośrodku. Trzeci etap to galeria i lightbox:
1/* Galeria - Mobile First Grid */
2.gallery {
3 display: grid;
4 grid-template-columns: 1fr;
5 gap: 1rem;
6}
7
8.gallery-item {
9 position: relative;
10 overflow: hidden;
11 cursor: pointer;
12 aspect-ratio: 1;
13}
14
15.gallery-item img {
16 width: 100%;
17 height: 100%;
18 object-fit: cover;
19 transition: transform 0.3s ease;
20}
21
22.gallery-overlay {
23 position: absolute;
24 bottom: 0;
25 left: 0;
26 right: 0;
27 background: linear-gradient(to top, var(--overlay-dark), transparent);
28 color: var(--text-light);
29 padding: 1rem;
30 transform: translateY(100%);
31 transition: transform 0.3s ease;
32}
33
34.gallery-item:hover .gallery-overlay {
35 transform: translateY(0);
36}
37
38.gallery-item:hover img {
39 transform: scale(1.1);
40}
41
42/* Lightbox */
43.lightbox {
44 display: none;
45 position: fixed;
46 z-index: 2000;
47 left: 0;
48 top: 0;
49 width: 100vw;
50 height: 100vh;
51 background-color: var(--overlay-dark);
52 align-items: center;
53 justify-content: center;
54}
55
56.lightbox.active {
57 display: flex;
58}
59
60.lightbox-content {
61 max-width: 90vw;
62 max-height: 90vh;
63 object-fit: contain;
64}
65
66.lightbox-close {
67 position: absolute;
68 top: 1rem;
69 right: 1rem;
70 color: var(--text-light);
71 font-size: 2rem;
72 cursor: pointer;
73}Na telefonie galeria ma jedną kolumnę 1fr. aspect-ratio: 1 robi z kafelka kwadrat, a object-fit: cover przycina zdjęcie bez zniekształceń. Lightbox z klasą active staje się kontenerem flex, a max-width: 90vw pilnuje, by zdjęcie mieściło się w oknie. Czwarty etap to progi dla większych ekranów:
1/* Media Queries - Tablet */
2@media (min-width: 768px) {
3 /* Nawigacja dla tabletu */
4 .nav-toggle {
5 display: none;
6 }
7
8 .nav-menu {
9 position: static;
10 display: flex;
11 flex-direction: row;
12 width: auto;
13 }
14
15 .nav-menu li {
16 padding: 0 1rem;
17 }
18
19 /* Hero dla tabletu */
20 .hero {
21 background-image: url('img/hero-tablet.jpg');
22 }
23
24 /* Galeria - 2 kolumny */
25 .gallery {
26 grid-template-columns: repeat(2, 1fr);
27 }
28}
29
30/* Media Queries - Desktop */
31@media (min-width: 1024px) {
32 /* Hero dla desktop */
33 .hero {
34 background-image: url('img/hero-desktop.jpg');
35 }
36
37 /* Galeria - 3 kolumny */
38 .gallery {
39 grid-template-columns: repeat(3, 1fr);
40 gap: 1.5rem;
41 }
42
43 /* Efekty hover tylko na desktop */
44 .gallery-overlay {
45 opacity: 0;
46 transform: translateY(0);
47 background: var(--overlay-dark);
48 }
49
50 .gallery-item:hover .gallery-overlay {
51 opacity: 1;
52 }
53}
54
55/* Media Queries - Duże ekrany */
56@media (min-width: 1440px) {
57 .gallery {
58 grid-template-columns: repeat(4, 1fr);
59 }
60}
61
62/* Orientacja landscape dla mobile */
63@media (max-width: 768px) and (orientation: landscape) {
64 .hero {
65 height: 100vw;
66 }
67
68 .hero-title {
69 font-size: 2rem;
70 }
71}
72
73/* High DPI displays */
74@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
75 .hero {
76 background-image: url('img/hero-mobile@2x.jpg');
77 }
78
79 @media (min-width: 768px) {
80 .hero {
81 background-image: url('img/hero-tablet@2x.jpg');
82 }
83 }
84
85 @media (min-width: 1024px) {
86 .hero {
87 background-image: url('img/hero-desktop@2x.jpg');
88 }
89 }
90}Od 768 pikseli znika hamburger, menu staje w rzędzie, a galeria dostaje dwie kolumny, od 1024 trzy, a od 1440 cztery. Warunek orientation: landscape łapie obrócony telefon, a min-resolution: 192dpi ekrany o podwójnej gęstości pikseli, którym podajemy zdjęcia w wyższej rozdzielczości.
Krok 3: Optymalizacja i najlepsze praktyki
Optymalizacja obrazów:
Element picture pozwala przeglądarce wybrać plik: sprawdza warunek media i to, czy obsługuje format podany w type:
1<!-- Użyj elementu picture dla responsywnych obrazów -->
2<picture>
3 <source media="(max-width: 768px)"
4 srcset="img/photo-mobile.webp"
5 type="image/webp">
6 <source media="(max-width: 768px)"
7 srcset="img/photo-mobile.jpg"
8 type="image/jpeg">
9 <source media="(max-width: 1200px)"
10 srcset="img/photo-tablet.webp"
11 type="image/webp">
12 <source media="(max-width: 1200px)"
13 srcset="img/photo-tablet.jpg"
14 type="image/jpeg">
15 <source srcset="img/photo-desktop.webp"
16 type="image/webp">
17 <img src="img/photo-desktop.jpg"
18 alt="Opis zdjęcia"
19 loading="lazy">
20</picture>Nowoczesne przeglądarki pobiorą lekki WebP, starsze sięgną po JPEG, a loading="lazy" opóźni pobieranie zdjęć spoza ekranu.
Dodatkowe style dla wydajności:
Na koniec kilka reguł dla wydajności, dostępności i trybu ciemnego:
1/* Użyj will-change dla elementów animowanych */
2.gallery-item {
3 will-change: transform;
4}
5
6/* Optymalizacja dla wydajności */
7.gallery-item img {
8 will-change: transform;
9 backface-visibility: hidden;
10}
11
12/* Użyj CSS containment */
13.gallery-item {
14 contain: layout style;
15}
16
17/* Prefers reduced motion */
18@media (prefers-reduced-motion: reduce) {
19 * {
20 animation-duration: 0.01ms !important;
21 animation-iteration-count: 1 !important;
22 transition-duration: 0.01ms !important;
23 }
24}
25
26/* Dark mode support */
27@media (prefers-color-scheme: dark) {
28 :root {
29 --primary-color: #fff;
30 --secondary-color: #1a1a1a;
31 --text-light: #333;
32 }
33
34 body {
35 background-color: #1a1a1a;
36 color: #fff;
37 }
38}contain ogranicza przeliczenia do jednego kafelka, prefers-reduced-motion skraca animacje osobom, które wyłączyły ruch w systemie, a prefers-color-scheme: dark włącza ciemne kolory.
Krok 4: Siatka Grid bez media queries
Galeria korzysta z CSS Grid, który poznasz dokładnie w lokacji mu poświęconej. grid-template-columns: 1fr 1fr 1fr tworzy trzy równe kolumny, bo fr to ułamek wolnego miejsca, a repeat(3, 1fr) to ten sam zapis w skrócie. Grid potrafi też sam dobrać liczbę kolumn:
1.gallery {
2 display: grid;
3 grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
4 gap: 1rem;
5}minmax(250px, 1fr) daje kolumnie co najmniej 250 pikseli, a auto-fit mieści ich tyle, ile się zmieści, więc media queries nie są potrzebne. Grid układa elementy w dwóch wymiarach naraz, a Flexbox w jednym, dlatego szkielet strony to zadanie dla Grida i jego nazwanych obszarów:
1.page {
2 display: grid;
3 grid-template-columns: 200px 1fr 200px;
4 grid-template-areas:
5 "header header header"
6 "nav main aside"
7 "footer footer footer";
8}
9
10header { grid-area: header; }
11nav { grid-area: nav; }
12main { grid-area: main; }
13aside { grid-area: aside; }
14footer { grid-area: footer; }grid-template-areas rysuje plan strony z nazw, jak plan świątyni z salą główną i bocznymi komnatami, a grid-area przypisuje element do obszaru. Na telefonie wystarczy jedna kolumna i obszary jeden pod drugim. Szerokości policzysz też funkcją calc(), na przykład calc(100% - 20px). Tę samą galerię zbudujesz na Flexboksie, zmieniając w media queries flex-basis kafelków ze 100% na calc(50% - 10px) i calc(33.33% - 14px).
Kompletny przykład kodu
HTML (index.html):
W porównaniu z krokiem 1 pełny plik ma opis strony w meta, połączenia preconnect, przykładowe zdjęcia z picsum.photos i skrypt script.js:
1<!DOCTYPE html>
2<html lang="pl">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <meta name="description" content="Portfolio fotograficzne Jana Kowalskiego">
7 <title>Jan Kowalski - Portfolio Fotografa</title>
8 <link rel="stylesheet" href="styles.css">
9 <link rel="preconnect" href="https://fonts.googleapis.com">
10 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11</head>
12<body>
13 <!-- Nawigacja -->
14 <nav class="navbar">
15 <div class="nav-container">
16 <div class="nav-logo">JK Photography</div>
17 <button class="nav-toggle" aria-label="Menu">
18 <span></span>
19 <span></span>
20 <span></span>
21 </button>
22 <ul class="nav-menu">
23 <li><a href="#home">Start</a></li>
24 <li><a href="#portfolio">Portfolio</a></li>
25 <li><a href="#about">O mnie</a></li>
26 <li><a href="#contact">Kontakt</a></li>
27 </ul>
28 </div>
29 </nav>
30
31 <!-- Sekcja Hero -->
32 <section id="home" class="hero">
33 <div class="hero-content">
34 <h1 class="hero-title">Jan Kowalski</h1>
35 <p class="hero-subtitle">Fotografia jest moją pasją</p>
36 <a href="#portfolio" class="hero-button">Zobacz portfolio</a>
37 </div>
38 <div class="hero-overlay"></div>
39 </section>
40
41 <!-- Sekcja Portfolio -->
42 <section id="portfolio" class="portfolio">
43 <div class="container">
44 <h2 class="section-title">Moje Portfolio</h2>
45
46 <!-- Filtry kategorii -->
47 <div class="filter-buttons">
48 <button class="filter-btn active" data-filter="all">Wszystkie</button>
49 <button class="filter-btn" data-filter="nature">Natura</button>
50 <button class="filter-btn" data-filter="portrait">Portrety</button>
51 <button class="filter-btn" data-filter="architecture">Architektura</button>
52 </div>
53
54 <!-- Galeria -->
55 <div class="gallery">
56 <!-- Przykładowe elementy galerii -->
57 <div class="gallery-item" data-category="nature">
58 <picture>
59 <source media="(max-width: 768px)" srcset="https://picsum.photos/400/400?random=1">
60 <source media="(max-width: 1200px)" srcset="https://picsum.photos/600/600?random=1">
61 <img src="https://picsum.photos/800/800?random=1" alt="Krajobraz górski">
62 </picture>
63 <div class="gallery-overlay">
64 <h3>Krajobraz górski</h3>
65 <p>Natura</p>
66 </div>
67 </div>
68
69 <div class="gallery-item" data-category="portrait">
70 <picture>
71 <source media="(max-width: 768px)" srcset="https://picsum.photos/400/400?random=2">
72 <source media="(max-width: 1200px)" srcset="https://picsum.photos/600/600?random=2">
73 <img src="https://picsum.photos/800/800?random=2" alt="Portret">
74 </picture>
75 <div class="gallery-overlay">
76 <h3>Portret</h3>
77 <p>Portrety</p>
78 </div>
79 </div>
80
81 <div class="gallery-item" data-category="architecture">
82 <picture>
83 <source media="(max-width: 768px)" srcset="https://picsum.photos/400/400?random=3">
84 <source media="(max-width: 1200px)" srcset="https://picsum.photos/600/600?random=3">
85 <img src="https://picsum.photos/800/800?random=3" alt="Architektura">
86 </picture>
87 <div class="gallery-overlay">
88 <h3>Nowoczesna architektura</h3>
89 <p>Architektura</p>
90 </div>
91 </div>
92
93 <div class="gallery-item" data-category="nature">
94 <picture>
95 <source media="(max-width: 768px)" srcset="https://picsum.photos/400/400?random=4">
96 <source media="(max-width: 1200px)" srcset="https://picsum.photos/600/600?random=4">
97 <img src="https://picsum.photos/800/800?random=4" alt="Las">
98 </picture>
99 <div class="gallery-overlay">
100 <h3>Leśna ścieżka</h3>
101 <p>Natura</p>
102 </div>
103 </div>
104
105 <div class="gallery-item" data-category="portrait">
106 <picture>
107 <source media="(max-width: 768px)" srcset="https://picsum.photos/400/400?random=5">
108 <source media="(max-width: 1200px)" srcset="https://picsum.photos/600/600?random=5">
109 <img src="https://picsum.photos/800/800?random=5" alt="Portret dziecka">
110 </picture>
111 <div class="gallery-overlay">
112 <h3>Dziecięca radość</h3>
113 <p>Portrety</p>
114 </div>
115 </div>
116
117 <div class="gallery-item" data-category="architecture">
118 <picture>
119 <source media="(max-width: 768px)" srcset="https://picsum.photos/400/400?random=6">
120 <source media="(max-width: 1200px)" srcset="https://picsum.photos/600/600?random=6">
121 <img src="https://picsum.photos/800/800?random=6" alt="Most">
122 </picture>
123 <div class="gallery-overlay">
124 <h3>Most o zachodzie</h3>
125 <p>Architektura</p>
126 </div>
127 </div>
128 </div>
129 </div>
130 </section>
131
132 <!-- Lightbox -->
133 <div class="lightbox" id="lightbox">
134 <span class="lightbox-close">×</span>
135 <img class="lightbox-content" id="lightbox-img">
136 <div class="lightbox-caption"></div>
137 </div>
138
139 <script src="script.js"></script>
140</body>
141</html>Podsumowanie
Ten projekt demonstruje wszystkie kluczowe koncepty responsywnego projektowania:
- Mobile-First Approach - rozpoczynamy od stylów mobilnych
- Media Queries - dostosowujemy layout dla różnych urządzeń
- Jednostki Viewport (vw, vh) - dla pełnoekranowych sekcji
- Responsywne obrazy - element picture z różnymi źródłami
- CSS Grid - responsywna siatka galerii
- Flexbox - elastyczna nawigacja
- Clamp() - responsywne rozmiary czcionek
- Optymalizacja - lazy loading, will-change, contain
- Dostępność - semantyczny HTML, aria-labels
- Nowoczesne funkcje - dark mode, reduced motion
Warstwa HTML i CSS jest gotowa i łatwo ją dostosować do innych celów, a menu, filtry i lightbox potrzebują jeszcze krótkiego skryptu. Moja rada: zanim wyślesz projekt mentorowi, sprawdź go na szerokościach 320, 768, 1024 i 1440 pikseli.
Pamiętaj: responsywna galeria to dziedziniec świątyni, który mieści i garstkę kapłanów, i tłum pielgrzymów, bo jego układ rośnie razem z ekranem.
Widzisz błąd w tej lekcji?
Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. Jaka wartość grid-template-columns tworzy responsywną siatkę?
2. Jak utworzyć siatkę CSS Grid z trzema równymi kolumnami?
To 2 z 4 pytań do tej lekcji. Pozostałe rozwiążesz w grze.
Zadania praktyczne w grze
- Klikanie w kolejności
Ułóż kod CSS tworzący siatkę Grid z 3 kolumnami:
- Edytor kodu
Stwórz responsywną siatkę egipskich bogów z Flexbox. HTML: <div class='pantheon'> + 6 <div class='god'>Bóg X</div> + </div>. CSS bazowy (mobile): .pantheon {display: flex; flex-wrap: wrap; gap: 20px; padding: 20px;} .god {flex-basis: 100%; background: #FFD700; padding: 30px; text-align: center; border: 2px solid #8B4513;}. Tablet: @media (min-width: 768px) {.god {flex-basis: calc(50% - 10px);}}. Desktop: @media (min-width: 1024px) {.god {flex-basis: calc(33.33% - 14px);}}. Obserwuj jak elementy się reorganizują!
- Układanie w pionie
Ułóż deklarację CSS Grid z automatycznym dopasowaniem kolumn (od aktywacji do wartości minmax):
- Edytor kodu
Stwórz auto-responsywną siatkę używając repeat(auto-fit, minmax(250px, 1fr)).
- Edytor kodu
Uzupełnij styl CSS: dodaj właściwości grid-template-columns i grid-template-areas dla widoku mobilnego (1 kolumna), a następnie w media query (min-width: 768px) ustaw layout 2-kolumnowy z sidebar i main obok siebie.
- Układanie w poziomie
Ułóż elementy aby stworzyć poprawne użycie calc():
- Edytor kodu
Stwórz Holy Grail Layout używając CSS Grid. HTML: <div class='temple-layout'><header class='header'>Nagłówek</header><nav class='sidebar-left'>Lewy</nav><main class='main-content'>Treść</main><aside class='sidebar-right'>Prawy</aside><footer class='footer'>Stopka</footer></div>. CSS: .temple-layout {display: grid; grid-template-areas: 'header header header' 'sidebar-left main-content sidebar-right' 'footer footer footer'; grid-template-columns: 200px 1fr 200px; grid-template-rows: auto 1fr auto; min-height: 100vh; gap: 10px;} .header {grid-area: header; background: #FFD700; padding: 20px;} .sidebar-left {grid-area: sidebar-left; background: #F4E4C1; padding: 20px;} .main-content {grid-area: main-content; background: #FFF8DC; padding: 20px;} .sidebar-right {grid-area: sidebar-right; background: #F4E4C1; padding: 20px;} .footer {grid-area: footer; background: #FFD700; padding: 20px;}.
- Edytor kodu
Stwórz responsywną siatkę kart bogów egipskich. HTML: <div class='cards-grid'><div class='card'><h2>Ra</h2><p>Bóg Słońca</p></div><div class='card'><h2>Anubis</h2><p>Bóg Zmarłych</p></div><div class='card'><h2>Isis</h2><p>Bogini Magii</p></div><div class='card'><h2>Horus</h2><p>Bóg Nieba</p></div><div class='card'><h2>Thoth</h2><p>Bóg Wiedzy</p></div><div class='card'><h2>Bastet</h2><p>Bogini Kotów</p></div></div>. CSS: .cards-grid {display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; padding: 20px;} .card {background: #FFD700; padding: 30px; text-align: center; border: 2px solid #8B4513; border-radius: 10px;}.