Final Project: Responsive Landing Page "Egyptian Adventure"
HTML and CSS course ยท Module 9: Modern CSS
Welcome to the final chamber of our Egyptian journey! I am Mohamed and today we face the ultimate challenge: creating a complete, professional landing page that will combine ALL the skills you've gained in this module! You already know dozens of tools, but you have practiced each of them separately. The real test begins when the grid, containers, the form and accessibility have to work together on a single page.
Just as building the Great Pyramid of Giza required combining all the skills of ancient builders, from basics to the most advanced techniques, your final project will be a synthesis of all your HTML and CSS knowledge!
Project Goal
You'll create a responsive landing page for a fictional travel agency "Egyptian Adventure" that organizes trips to ancient Egypt. The page will utilize:
- Semantic HTML - accessible structure
- CSS Grid and Flexbox - advanced layouts
- Container Queries - responsive components
- Modern CSS - latest CSS features
- Animations - smooth transitions and effects
- Performance - optimization and best practices
Project Structure
Page Sections:
- Hero Section - main banner with CTA (Call To Action)
- Features - feature cards using container queries
- Tours - tour gallery in CSS Grid
- Testimonials - customer reviews with carousel
- Pricing - pricing section
- Contact Form - contact form
- Footer - footer with social links
Technical Requirements
1. Semantic HTML
We start with the skeleton: a header with navigation, sections with identifiers, cards in article elements, reviews in blockquote and a form with labels. The code is long, so read it section by section:
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <meta name="description" content="Discover the secrets of ancient Egypt with Egyptian Adventure - the best travel agency">
7 <title>Egyptian Adventure - Trips to Ancient Egypt</title>
8 <link rel="stylesheet" href="styles.css">
9</head>
10<body>
11 <!-- Navigation -->
12 <header class="header" role="banner">
13 <nav class="nav" role="navigation" aria-label="Main navigation">
14 <div class="container">
15 <a href="#" class="logo">
16 <span class="logo-icon"></span>
17 <span class="logo-text">Egyptian Adventure</span>
18 </a>
19 <ul class="nav-list">
20 <li><a href="#features">Why Us</a></li>
21 <li><a href="#tours">Tours</a></li>
22 <li><a href="#testimonials">Reviews</a></li>
23 <li><a href="#pricing">Pricing</a></li>
24 <li><a href="#contact" class="btn-primary">Contact</a></li>
25 </ul>
26 </div>
27 </nav>
28 </header>
29
30 <!-- Hero Section -->
31 <section class="hero" id="hero">
32 <div class="hero-content">
33 <h1 class="hero-title">
34 Discover the Secrets of<br>
35 <span class="gradient-text">Ancient Egypt</span>
36 </h1>
37 <p class="hero-subtitle">
38 Travel 5,000 years back in time and experience the wonders of pharaohs,
39 pyramids, and hieroglyphs on the unforgettable journey of a lifetime!
40 </p>
41 <div class="hero-cta">
42 <a href="#tours" class="btn btn-large btn-primary">
43 Browse Tours
44 </a>
45 <a href="#contact" class="btn btn-large btn-secondary">
46 Contact Us
47 </a>
48 </div>
49 </div>
50 <div class="hero-image">
51 <div class="pyramid-illustration"></div>
52 </div>
53 </section>
54
55 <!-- Features -->
56 <section class="features" id="features">
57 <div class="container">
58 <h2 class="section-title">Why Egyptian Adventure?</h2>
59 <p class="section-subtitle">
60 We have been leaders in organizing trips to Egypt for 20 years
61 </p>
62
63 <div class="features-grid">
64 <article class="feature-card">
65 <div class="feature-icon"></div>
66 <h3>Exclusive Access</h3>
67 <p>Access to places unavailable to regular tourists,
68 including private visits to pyramid chambers</p>
69 </article>
70
71 <article class="feature-card">
72 <div class="feature-icon"></div>
73 <h3>Egyptology Experts</h3>
74 <p>Guides with academic degrees, passionate about the history
75 of ancient Egypt</p>
76 </article>
77
78 <article class="feature-card">
79 <div class="feature-icon"></div>
80 <h3>Luxury Hotels</h3>
81 <p>Accommodation in the best 5* hotels, with views of the Nile
82 and pyramids</p>
83 </article>
84
85 <article class="feature-card">
86 <div class="feature-icon"></div>
87 <h3>Authentic Cuisine</h3>
88 <p>Tasting traditional Egyptian dishes prepared
89 by local chefs</p>
90 </article>
91 </div>
92 </div>
93 </section>
94
95 <!-- Tours Grid -->
96 <section class="tours" id="tours">
97 <div class="container">
98 <h2 class="section-title">Our Tours</h2>
99 <p class="section-subtitle">
100 Choose a tour tailored to your dreams
101 </p>
102
103 <div class="tours-grid">
104 <article class="tour-card tour-card--featured">
105 <div class="tour-image">
106 <img src="/api/placeholder/600/400" alt="Pyramids of Giza">
107 <span class="tour-badge">Bestseller</span>
108 </div>
109 <div class="tour-content">
110 <h3>Classic Egypt</h3>
111 <p class="tour-duration">โฑ7 days / 6 nights</p>
112 <p class="tour-description">
113 Cairo, Giza, Luxor, Valley of the Kings, Nile cruise
114 </p>
115 <ul class="tour-highlights">
116 <li>Great Pyramid of Giza</li>
117 <li>Egyptian Museum in Cairo</li>
118 <li>Karnak Temple</li>
119 <li>Nile River Cruise</li>
120 </ul>
121 <div class="tour-footer">
122 <div class="tour-price">
123 <span class="price-from">from</span>
124 <span class="price-amount">4,999</span>
125 <span class="price-currency">PLN</span>
126 </div>
127 <a href="#contact" class="btn btn-primary">Book Now</a>
128 </div>
129 </div>
130 </article>
131
132 <article class="tour-card">
133 <div class="tour-image">
134 <img src="/api/placeholder/600/400" alt="Abu Simbel">
135 </div>
136 <div class="tour-content">
137 <h3>Egyptian Wonders</h3>
138 <p class="tour-duration">โฑ10 days / 9 nights</p>
139 <p class="tour-description">
140 All major attractions + Abu Simbel and Alexandria
141 </p>
142 <ul class="tour-highlights">
143 <li>Everything from Classic Egypt</li>
144 <li>Abu Simbel Temples</li>
145 <li>Library of Alexandria</li>
146 <li>Siwa Oasis</li>
147 </ul>
148 <div class="tour-footer">
149 <div class="tour-price">
150 <span class="price-from">from</span>
151 <span class="price-amount">7,499</span>
152 <span class="price-currency">PLN</span>
153 </div>
154 <a href="#contact" class="btn btn-primary">Book Now</a>
155 </div>
156 </div>
157 </article>
158
159 <article class="tour-card">
160 <div class="tour-image">
161 <img src="/api/placeholder/600/400" alt="Diving in the Red Sea">
162 </div>
163 <div class="tour-content">
164 <h3>Egypt + Red Sea</h3>
165 <p class="tour-duration">โฑ12 days / 11 nights</p>
166 <p class="tour-description">
167 History + relaxation and diving in Hurghada
168 </p>
169 <ul class="tour-highlights">
170 <li>Monument sightseeing</li>
171 <li>5 days all inclusive in Hurghada</li>
172 <li>Diving with coral reef</li>
173 <li>Desert safari</li>
174 </ul>
175 <div class="tour-footer">
176 <div class="tour-price">
177 <span class="price-from">from</span>
178 <span class="price-amount">6,299</span>
179 <span class="price-currency">PLN</span>
180 </div>
181 <a href="#contact" class="btn btn-primary">Book Now</a>
182 </div>
183 </div>
184 </article>
185 </div>
186 </div>
187 </section>
188
189 <!-- Testimonials -->
190 <section class="testimonials" id="testimonials">
191 <div class="container">
192 <h2 class="section-title">What Our Clients Say</h2>
193
194 <div class="testimonials-grid">
195 <blockquote class="testimonial-card">
196 <div class="testimonial-rating"></div>
197 <p class="testimonial-text">
198 "An incredible experience! The guides were extremely knowledgeable,
199 and the tour organization was top-notch. The pyramids in person
200 are a thousand times more impressive than in photos!"
201 </p>
202 <cite class="testimonial-author">
203 <strong>Anna Kowalska</strong>
204 <span>Warsaw</span>
205 </cite>
206 </blockquote>
207
208 <blockquote class="testimonial-card">
209 <div class="testimonial-rating"></div>
210 <p class="testimonial-text">
211 "As an Egyptologist I was skeptical, but this tour exceeded
212 my expectations. Access to places not shown on
213 standard tours was priceless!"
214 </p>
215 <cite class="testimonial-author">
216 <strong>Dr. Jan Nowak</strong>
217 <span>Krakow</span>
218 </cite>
219 </blockquote>
220
221 <blockquote class="testimonial-card">
222 <div class="testimonial-rating"></div>
223 <p class="testimonial-text">
224 "The trip of a lifetime! I was especially impressed by the Nile cruise and
225 visiting the Valley of the Kings. Everything was perfectly organized."
226 </p>
227 <cite class="testimonial-author">
228 <strong>Maria Wisniewska</strong>
229 <span>Gdansk</span>
230 </cite>
231 </blockquote>
232 </div>
233 </div>
234 </section>
235
236 <!-- Contact Form -->
237 <section class="contact" id="contact">
238 <div class="container">
239 <div class="contact-grid">
240 <div class="contact-info">
241 <h2>Book Your Adventure</h2>
242 <p>Fill out the form and our consultant will contact you
243 within 24 hours!</p>
244
245 <div class="contact-details">
246 <div class="contact-item">
247 <span class="contact-icon"></span>
248 <div>
249 <strong>Phone</strong>
250 <p>+48 123 456 789</p>
251 </div>
252 </div>
253 <div class="contact-item">
254 <span class="contact-icon"></span>
255 <div>
256 <strong>Email</strong>
257 <p>contact@egyptianadventure.com</p>
258 </div>
259 </div>
260 <div class="contact-item">
261 <span class="contact-icon"></span>
262 <div>
263 <strong>Address</strong>
264 <p>123 Pyramid Street, 00-001 Warsaw</p>
265 </div>
266 </div>
267 </div>
268 </div>
269
270 <form class="contact-form" action="#" method="POST">
271 <div class="form-group">
272 <label for="name">Full Name</label>
273 <input type="text" id="name" name="name" required>
274 </div>
275
276 <div class="form-group">
277 <label for="email">Email</label>
278 <input type="email" id="email" name="email" required>
279 </div>
280
281 <div class="form-group">
282 <label for="phone">Phone</label>
283 <input type="tel" id="phone" name="phone" required>
284 </div>
285
286 <div class="form-group">
287 <label for="tour">Choose a Tour</label>
288 <select id="tour" name="tour" required>
289 <option value="">Select...</option>
290 <option value="classic">Classic Egypt - 7 days</option>
291 <option value="wonders">Egyptian Wonders - 10 days</option>
292 <option value="red-sea">Egypt + Red Sea - 12 days</option>
293 </select>
294 </div>
295
296 <div class="form-group">
297 <label for="message">Message (optional)</label>
298 <textarea id="message" name="message" rows="4"></textarea>
299 </div>
300
301 <button type="submit" class="btn btn-primary btn-large">
302 Send Inquiry
303 </button>
304 </form>
305 </div>
306 </div>
307 </section>
308
309 <!-- Footer -->
310 <footer class="footer">
311 <div class="container">
312 <div class="footer-grid">
313 <div class="footer-section">
314 <h3>Egyptian Adventure</h3>
315 <p>Discovering the secrets of ancient Egypt since 2004</p>
316 <div class="social-links">
317 <a href="#" aria-label="Facebook"></a>
318 <a href="#" aria-label="Instagram"></a>
319 <a href="#" aria-label="Twitter"></a>
320 <a href="#" aria-label="YouTube"></a>
321 </div>
322 </div>
323
324 <div class="footer-section">
325 <h4>Tours</h4>
326 <ul>
327 <li><a href="#">Classic Egypt</a></li>
328 <li><a href="#">Egyptian Wonders</a></li>
329 <li><a href="#">Egypt + Red Sea</a></li>
330 <li><a href="#">Group Tours</a></li>
331 </ul>
332 </div>
333
334 <div class="footer-section">
335 <h4>Information</h4>
336 <ul>
337 <li><a href="#">About Us</a></li>
338 <li><a href="#">Terms & Conditions</a></li>
339 <li><a href="#">Privacy Policy</a></li>
340 <li><a href="#">FAQ</a></li>
341 </ul>
342 </div>
343
344 <div class="footer-section">
345 <h4>Contact</h4>
346 <ul>
347 <li>+48 123 456 789</li>
348 <li>contact@egyptianadventure.com</li>
349 <li>123 Pyramid Street, Warsaw</li>
350 </ul>
351 </div>
352 </div>
353
354 <div class="footer-bottom">
355 <p>© 2024 Egyptian Adventure. All rights reserved.</p>
356 </div>
357 </div>
358 </footer>
359</body>
360</html>Every section has its own id, so links in the navigation scroll the page to the right place. Form fields are tied to their labels through for and id, and the required attribute blocks sending an empty field. lang="en" tells screen readers which language to read the content in.
2. CSS - Complete Styles
Comments divide the stylesheet into sections: reset and variables, header, hero, features, tours and the other parts of the page. The palette, spacing and shadows live in CSS variables on :root:
1/* ==========================================
2 CSS RESET & BASE STYLES
3 ========================================== */
4*, *::before, *::after {
5 margin: 0;
6 padding: 0;
7 box-sizing: border-box;
8}
9
10:root {
11 /* Colors - Egyptian theme */
12 --color-primary: #D4AF37; /* Gold */
13 --color-primary-dark: #B8941F;
14 --color-secondary: #2C3E50; /* Dark blue */
15 --color-accent: #E67E22; /* Orange */
16
17 --color-bg: #FFFFFF;
18 --color-bg-alt: #F8F9FA;
19 --color-text: #2C3E50;
20 --color-text-light: #6C757D;
21
22 /* Spacing */
23 --spacing-xs: 0.5rem;
24 --spacing-sm: 1rem;
25 --spacing-md: 2rem;
26 --spacing-lg: 4rem;
27 --spacing-xl: 6rem;
28
29 /* Typography */
30 --font-primary: 'Segoe UI', system-ui, sans-serif;
31 --font-size-base: 1rem;
32 --font-size-lg: 1.125rem;
33 --font-size-xl: 1.25rem;
34 --font-size-2xl: 1.5rem;
35 --font-size-3xl: 2rem;
36 --font-size-4xl: 3rem;
37
38 /* Layout */
39 --container-max-width: 1200px;
40 --border-radius: 12px;
41
42 /* Shadows */
43 --shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.1);
44 --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
45 --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
46
47 /* Transitions */
48 --transition: all 0.3s ease;
49}
50
51html {
52 scroll-behavior: smooth;
53}
54
55body {
56 font-family: var(--font-primary);
57 font-size: var(--font-size-base);
58 line-height: 1.6;
59 color: var(--color-text);
60 background: var(--color-bg);
61}
62
63img {
64 max-width: 100%;
65 height: auto;
66 display: block;
67}
68
69a {
70 color: inherit;
71 text-decoration: none;
72}
73
74ul {
75 list-style: none;
76}
77
78/* ==========================================
79 UTILITIES
80 ========================================== */
81.container {
82 max-width: var(--container-max-width);
83 margin: 0 auto;
84 padding: 0 var(--spacing-md);
85}
86
87.section-title {
88 font-size: var(--font-size-3xl);
89 font-weight: 700;
90 text-align: center;
91 margin-bottom: var(--spacing-sm);
92 color: var(--color-secondary);
93}
94
95.section-subtitle {
96 font-size: var(--font-size-lg);
97 text-align: center;
98 color: var(--color-text-light);
99 margin-bottom: var(--spacing-lg);
100}
101
102.gradient-text {
103 background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-accent) 100%);
104 -webkit-background-clip: text;
105 -webkit-text-fill-color: transparent;
106 background-clip: text;
107}
108
109/* Buttons */
110.btn {
111 display: inline-block;
112 padding: var(--spacing-sm) var(--spacing-md);
113 border-radius: var(--border-radius);
114 font-weight: 600;
115 text-align: center;
116 cursor: pointer;
117 transition: var(--transition);
118 border: 2px solid transparent;
119}
120
121.btn-primary {
122 background: var(--color-primary);
123 color: var(--color-secondary);
124}
125
126.btn-primary:hover {
127 background: var(--color-primary-dark);
128 transform: translateY(-2px);
129 box-shadow: var(--shadow-md);
130}
131
132.btn-secondary {
133 background: transparent;
134 border-color: var(--color-primary);
135 color: var(--color-primary);
136}
137
138.btn-secondary:hover {
139 background: var(--color-primary);
140 color: var(--color-secondary);
141}
142
143.btn-large {
144 padding: var(--spacing-md) var(--spacing-lg);
145 font-size: var(--font-size-lg);
146}
147
148/* ==========================================
149 HEADER & NAVIGATION
150 ========================================== */
151.header {
152 position: sticky;
153 top: 0;
154 background: rgba(255, 255, 255, 0.98);
155 backdrop-filter: blur(10px);
156 box-shadow: var(--shadow-sm);
157 z-index: 1000;
158}
159
160.nav .container {
161 display: flex;
162 justify-content: space-between;
163 align-items: center;
164 padding-top: var(--spacing-sm);
165 padding-bottom: var(--spacing-sm);
166}
167
168.logo {
169 display: flex;
170 align-items: center;
171 gap: var(--spacing-sm);
172 font-size: var(--font-size-xl);
173 font-weight: 700;
174 color: var(--color-secondary);
175}
176
177.logo-icon {
178 font-size: var(--font-size-2xl);
179}
180
181.nav-list {
182 display: flex;
183 gap: var(--spacing-md);
184 align-items: center;
185}
186
187.nav-list a {
188 transition: var(--transition);
189}
190
191.nav-list a:not(.btn-primary):hover {
192 color: var(--color-primary);
193}
194
195/* ==========================================
196 HERO SECTION
197 ========================================== */
198.hero {
199 display: grid;
200 grid-template-columns: 1fr 1fr;
201 gap: var(--spacing-lg);
202 align-items: center;
203 min-height: calc(100vh - 80px);
204 padding: var(--spacing-xl) var(--spacing-md);
205 background: linear-gradient(135deg, #F8F9FA 0%, #E9ECEF 100%);
206}
207
208.hero-content {
209 max-width: 600px;
210}
211
212.hero-title {
213 font-size: var(--font-size-4xl);
214 font-weight: 800;
215 line-height: 1.2;
216 margin-bottom: var(--spacing-md);
217}
218
219.hero-subtitle {
220 font-size: var(--font-size-xl);
221 color: var(--color-text-light);
222 margin-bottom: var(--spacing-lg);
223}
224
225.hero-cta {
226 display: flex;
227 gap: var(--spacing-md);
228 flex-wrap: wrap;
229}
230
231.hero-image {
232 display: flex;
233 justify-content: center;
234 align-items: center;
235}
236
237.pyramid-illustration {
238 width: 400px;
239 height: 400px;
240 background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-accent) 100%);
241 clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
242 animation: float 6s ease-in-out infinite;
243}
244
245@keyframes float {
246 0%, 100% { transform: translateY(0); }
247 50% { transform: translateY(-20px); }
248}
249
250/* ==========================================
251 FEATURES SECTION
252 ========================================== */
253.features {
254 padding: var(--spacing-xl) 0;
255 background: var(--color-bg);
256}
257
258.features-grid {
259 display: grid;
260 grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
261 gap: var(--spacing-lg);
262 container-type: inline-size;
263}
264
265.feature-card {
266 background: white;
267 padding: var(--spacing-lg);
268 border-radius: var(--border-radius);
269 box-shadow: var(--shadow-md);
270 text-align: center;
271 transition: var(--transition);
272}
273
274.feature-card:hover {
275 transform: translateY(-8px);
276 box-shadow: var(--shadow-lg);
277}
278
279.feature-icon {
280 font-size: 4rem;
281 margin-bottom: var(--spacing-md);
282}
283
284.feature-card h3 {
285 font-size: var(--font-size-xl);
286 margin-bottom: var(--spacing-sm);
287 color: var(--color-secondary);
288}
289
290/* Container query for feature cards */
291@container (max-width: 300px) {
292 .feature-card {
293 padding: var(--spacing-md);
294 }
295
296 .feature-icon {
297 font-size: 3rem;
298 }
299}
300
301/* ==========================================
302 TOURS SECTION
303 ========================================== */
304.tours {
305 padding: var(--spacing-xl) 0;
306 background: var(--color-bg-alt);
307}
308
309.tours-grid {
310 display: grid;
311 grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
312 gap: var(--spacing-lg);
313}
314
315.tour-card {
316 background: white;
317 border-radius: var(--border-radius);
318 overflow: hidden;
319 box-shadow: var(--shadow-md);
320 transition: var(--transition);
321 container-type: inline-size;
322}
323
324.tour-card:hover {
325 transform: translateY(-8px);
326 box-shadow: var(--shadow-lg);
327}
328
329.tour-card--featured {
330 grid-column: span 2;
331}
332
333@media (max-width: 768px) {
334 .tour-card--featured {
335 grid-column: span 1;
336 }
337}
338
339.tour-image {
340 position: relative;
341 aspect-ratio: 16 / 9;
342 overflow: hidden;
343}
344
345.tour-image img {
346 width: 100%;
347 height: 100%;
348 object-fit: cover;
349 transition: var(--transition);
350}
351
352.tour-card:hover .tour-image img {
353 transform: scale(1.1);
354}
355
356.tour-badge {
357 position: absolute;
358 top: var(--spacing-md);
359 right: var(--spacing-md);
360 background: var(--color-accent);
361 color: white;
362 padding: var(--spacing-xs) var(--spacing-md);
363 border-radius: 50px;
364 font-weight: 600;
365 font-size: 0.875rem;
366}
367
368.tour-content {
369 padding: var(--spacing-lg);
370}
371
372.tour-content h3 {
373 font-size: var(--font-size-2xl);
374 margin-bottom: var(--spacing-sm);
375 color: var(--color-secondary);
376}
377
378.tour-duration {
379 color: var(--color-text-light);
380 margin-bottom: var(--spacing-sm);
381}
382
383.tour-highlights {
384 margin: var(--spacing-md) 0;
385}
386
387.tour-highlights li {
388 padding: var(--spacing-xs) 0;
389 color: var(--color-text);
390}
391
392.tour-footer {
393 display: flex;
394 justify-content: space-between;
395 align-items: center;
396 margin-top: var(--spacing-md);
397 padding-top: var(--spacing-md);
398 border-top: 1px solid var(--color-bg-alt);
399}
400
401.tour-price {
402 display: flex;
403 align-items: baseline;
404 gap: var(--spacing-xs);
405}
406
407.price-amount {
408 font-size: var(--font-size-3xl);
409 font-weight: 700;
410 color: var(--color-primary);
411}
412
413.price-from,
414.price-currency {
415 font-size: var(--font-size-base);
416 color: var(--color-text-light);
417}
418
419/* ==========================================
420 TESTIMONIALS SECTION
421 ========================================== */
422.testimonials {
423 padding: var(--spacing-xl) 0;
424 background: var(--color-bg);
425}
426
427.testimonials-grid {
428 display: grid;
429 grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
430 gap: var(--spacing-lg);
431}
432
433.testimonial-card {
434 background: white;
435 padding: var(--spacing-lg);
436 border-radius: var(--border-radius);
437 box-shadow: var(--shadow-md);
438 border-left: 4px solid var(--color-primary);
439}
440
441.testimonial-rating {
442 font-size: var(--font-size-lg);
443 margin-bottom: var(--spacing-md);
444}
445
446.testimonial-text {
447 font-size: var(--font-size-lg);
448 line-height: 1.8;
449 margin-bottom: var(--spacing-md);
450 font-style: italic;
451 color: var(--color-text);
452}
453
454.testimonial-author {
455 display: flex;
456 flex-direction: column;
457 gap: var(--spacing-xs);
458 font-style: normal;
459}
460
461.testimonial-author strong {
462 color: var(--color-secondary);
463 font-size: var(--font-size-lg);
464}
465
466.testimonial-author span {
467 color: var(--color-text-light);
468}
469
470/* ==========================================
471 CONTACT SECTION
472 ========================================== */
473.contact {
474 padding: var(--spacing-xl) 0;
475 background: var(--color-bg-alt);
476}
477
478.contact-grid {
479 display: grid;
480 grid-template-columns: 1fr 1fr;
481 gap: var(--spacing-xl);
482}
483
484@media (max-width: 768px) {
485 .contact-grid {
486 grid-template-columns: 1fr;
487 }
488}
489
490.contact-info h2 {
491 font-size: var(--font-size-3xl);
492 margin-bottom: var(--spacing-md);
493 color: var(--color-secondary);
494}
495
496.contact-details {
497 margin-top: var(--spacing-lg);
498}
499
500.contact-item {
501 display: flex;
502 gap: var(--spacing-md);
503 margin-bottom: var(--spacing-md);
504}
505
506.contact-icon {
507 font-size: var(--font-size-2xl);
508}
509
510.contact-form {
511 background: white;
512 padding: var(--spacing-lg);
513 border-radius: var(--border-radius);
514 box-shadow: var(--shadow-md);
515}
516
517.form-group {
518 margin-bottom: var(--spacing-md);
519}
520
521.form-group label {
522 display: block;
523 margin-bottom: var(--spacing-xs);
524 font-weight: 600;
525 color: var(--color-secondary);
526}
527
528.form-group input,
529.form-group select,
530.form-group textarea {
531 width: 100%;
532 padding: var(--spacing-sm);
533 border: 2px solid var(--color-bg-alt);
534 border-radius: var(--border-radius);
535 font-family: inherit;
536 font-size: var(--font-size-base);
537 transition: var(--transition);
538}
539
540.form-group input:focus,
541.form-group select:focus,
542.form-group textarea:focus {
543 outline: none;
544 border-color: var(--color-primary);
545}
546
547/* ==========================================
548 FOOTER
549 ========================================== */
550.footer {
551 background: var(--color-secondary);
552 color: white;
553 padding: var(--spacing-xl) 0 var(--spacing-md);
554}
555
556.footer-grid {
557 display: grid;
558 grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
559 gap: var(--spacing-lg);
560 margin-bottom: var(--spacing-lg);
561}
562
563.footer-section h3,
564.footer-section h4 {
565 margin-bottom: var(--spacing-md);
566 color: var(--color-primary);
567}
568
569.footer-section ul li {
570 margin-bottom: var(--spacing-xs);
571}
572
573.footer-section a:hover {
574 color: var(--color-primary);
575}
576
577.social-links {
578 display: flex;
579 gap: var(--spacing-md);
580 margin-top: var(--spacing-md);
581 font-size: var(--font-size-2xl);
582}
583
584.footer-bottom {
585 text-align: center;
586 padding-top: var(--spacing-md);
587 border-top: 1px solid rgba(255, 255, 255, 0.1);
588 color: rgba(255, 255, 255, 0.7);
589}
590
591/* ==========================================
592 RESPONSIVE DESIGN
593 ========================================== */
594@media (max-width: 768px) {
595 .hero {
596 grid-template-columns: 1fr;
597 text-align: center;
598 }
599
600 .hero-title {
601 font-size: var(--font-size-3xl);
602 }
603
604 .pyramid-illustration {
605 width: 250px;
606 height: 250px;
607 }
608
609 .hero-cta {
610 justify-content: center;
611 }
612
613 .nav-list {
614 flex-wrap: wrap;
615 gap: var(--spacing-sm);
616 }
617}Notice three places. The features grid is a container, so the cards change their spacing through @container. The featured tour takes two columns and goes back to one below 768px. The tour images keep their proportions thanks to aspect-ratio: 16 / 9.
3. The Eye of Horus: the :has() Selector
One more tool is missing. The :has() pseudo-class selects an element if it contains a specific child, so a parent can react to what it holds inside, like the Eye of Horus looking into a chamber:
1/* A card with a badge (e.g. Bestseller) gets a golden outline */
2.tour-card:has(.tour-badge) {
3 outline: 3px solid var(--color-primary);
4}
5
6/* The label of a field the user filled in incorrectly */
7.form-group:has(input:user-invalid) label {
8 color: #c0392b;
9}
10
11/* An article whose direct child is an image */
12article:has(> img) {
13 border: 2px solid gold;
14}Only the card with the Bestseller badge gets the outline, because the others do not have one. :user-invalid kicks in only after the user interacts with a field, so an empty form does not glow red from the start. > img means a direct child, and article:not(:has(img, video)) selects articles without images or videos. :has() has worked in all major browsers since the end of 2023.
Implementation Tips
1. Performance
Load images below the first screen lazily, and announce key resources to the browser early:
1<!-- Lazy loading for images -->
2<img src="image.jpg" alt="Description" loading="lazy">
3
4<!-- Preload for key resources -->
5<link rel="preload" as="image" href="hero-image.jpg">Watch out for one thing: do not lazy-load the image in the hero section, because it is visible right away and you would delay its display. That is exactly what preload is for.
2. Accessibility
Semantic elements and ARIA labels help screen readers understand the page:
1<!-- Use semantic elements -->
2<nav role="navigation" aria-label="Main navigation">
3<main role="main">
4<footer role="contentinfo">
5
6<!-- Add aria-labels where needed -->
7<button aria-label="Close modal">x</button>The roles in this example are redundant, because nav, main and footer have them by default. The rule is: do not add a role the element already has. aria-label, on the other hand, is essential for buttons that contain only an icon.
3. SEO
Meta tags describe the page to search engines and social networks:
1<!-- Meta tags for SEO -->
2<meta name="description" content="Page description">
3<meta name="keywords" content="egypt, tours, pyramids">
4<meta property="og:title" content="Egyptian Adventure">
5<meta property="og:description" content="Best tours to Egypt">
6<meta property="og:image" content="og-image.jpg">The description text often appears in search results, and the Open Graph tags build the link preview. You can skip keywords, because Google has not taken it into account since 2009.
Summary
Congratulations, young builder! You've created a complete, professional landing page that combines:
- Semantic HTML - accessible structure
- CSS Grid & Flexbox - advanced layouts
- Container Queries - responsive components
- Modern CSS - latest features
- Animations - smooth effects
- Performance - optimization
Just as building the Great Pyramid of Giza was the culmination of ancient builders' knowledge, your final project is a synthesis of everything you've learned in this module! In the final task you will also build an Egyptian dashboard that combines Container Queries, :has(), nesting, @layer, logical properties, clamp(), aspect-ratio, :is() and :where(), scroll-snap, color-mix(), @supports and accent-color. My advice: add them one at a time and check the page in two browsers after each one. In the sandbox below you will find an Egyptian dashboard where you can practice these techniques.
Code for this lesson: index.html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>Master Architecture Dashboard Totha</title>
7 <link rel="stylesheet" href="style.css">
8</head>
9<body>
10 <div class="egyptian-container">
11 <header class="pharaoh-header">
12 <div class="header-content">
13 <span class="ankh-symbol"></span>
14 <h1 class="pharaoh-title">Master Architecture Dashboard Totha</h1>
15 <span class="eye-of-horus">๐</span>
16 </div>
17 <p class="header-subtitle">Sum of all software architecture wisdom from the Necropolis of Giza</p>
18 </header>
19
20 <!-- Clean Architecture Layers -->
21 <section class="pyramid-section">
22 <h2 class="section-title">
23 <span class="hieroglyph"></span>
24 Clean Architecture - Temple Hierarchy
25 </h2>
26 <div class="pyramid-diagram">
27 <div class="pyramid-layer pyramid-layer--entities">
28 <div class="layer-content">
29 <h3>Entities</h3>
30 <p>Encje Biznesowe</p>
31 <span class="layer-icon"></span>
32 </div>
33 </div>
34 <div class="pyramid-layer pyramid-layer--usecases">
35 <div class="layer-content">
36 <h3>Use Cases</h3>
37 <p>Use Cases</p>
38 <span class="layer-icon"></span>
39 </div>
40 </div>
41 <div class="pyramid-layer pyramid-layer--adapters">
42 <div class="layer-content">
43 <h3>Interface Adapters</h3>
44 <p>Interface Adapters</p>
45 <span class="layer-icon"></span>
46 </div>
47 </div>
48 <div class="pyramid-layer pyramid-layer--frameworks">
49 <div class="layer-content">
50 <h3>Frameworks & Drivers</h3>
51 <p>Frameworki i Sterowniki</p>
52 <span class="layer-icon"></span>
53 </div>
54 </div>
55 </div>
56 </section>
57
58 <!-- Design Patterns Categories -->
59 <section class="papyrus-section">
60 <h2 class="section-title">
61 <span class="hieroglyph"></span>
62 Design Patterns - Scrolls of Wisdom
63 </h2>
64 <div class="patterns-grid">
65 <article class="pattern-category pattern-category--creational">
66 <div class="pattern-header">
67 <h3>Creational Patterns</h3>
68 <span class="pattern-icon"></span>
69 </div>
70 <ul class="pattern-list">
71 <li class="pattern-item">Singleton</li>
72 <li class="pattern-item">Factory</li>
73 <li class="pattern-item">Builder</li>
74 <li class="pattern-item">Prototype</li>
75 </ul>
76 </article>
77
78 <article class="pattern-category pattern-category--structural">
79 <div class="pattern-header">
80 <h3>Structural Patterns</h3>
81 <span class="pattern-icon"></span>
82 </div>
83 <ul class="pattern-list">
84 <li class="pattern-item">Adapter</li>
85 <li class="pattern-item">Decorator</li>
86 <li class="pattern-item">Facade</li>
87 <li class="pattern-item">Proxy</li>
88 </ul>
89 </article>
90
91 <article class="pattern-category pattern-category--behavioral">
92 <div class="pattern-header">
93 <h3>Behavioral Patterns</h3>
94 <span class="pattern-icon"></span>
95 </div>
96 <ul class="pattern-list">
97 <li class="pattern-item">Observer</li>
98 <li class="pattern-item">Strategy</li>
99 <li class="pattern-item">Command</li>
100 <li class="pattern-item">State</li>
101 </ul>
102 </article>
103
104 <article class="pattern-category pattern-category--architectural">
105 <div class="pattern-header">
106 <h3>Architectural Patterns</h3>
107 <span class="pattern-icon"></span>
108 </div>
109 <ul class="pattern-list">
110 <li class="pattern-item">MVC</li>
111 <li class="pattern-item">MVVM</li>
112 <li class="pattern-item">Hexagonal</li>
113 <li class="pattern-item">Layered</li>
114 </ul>
115 </article>
116 </div>
117 </section>
118
119 <!-- Microservices Patterns -->
120 <section class="obelisk-section">
121 <h2 class="section-title">
122 <span class="hieroglyph"></span>
123 Microservices - Obelisks of the Empire
124 </h2>
125 <div class="microservices-grid">
126 <div class="microservice-card microservice-card--gateway">
127 <div class="card-icon"></div>
128 <h3>API Gateway</h3>
129 <p>Palace Gate</p>
130 <div class="card-status status--active">Active</div>
131 </div>
132
133 <div class="microservice-card microservice-card--discovery">
134 <div class="card-icon"></div>
135 <h3>Service Discovery</h3>
136 <p>Mapa Imperium</p>
137 <div class="card-status status--active">Active</div>
138 </div>
139
140 <div class="microservice-card microservice-card--breaker">
141 <div class="card-icon"></div>
142 <h3>Circuit Breaker</h3>
143 <p>Gate Guardian</p>
144 <div class="card-status status--active">Active</div>
145 </div>
146
147 <div class="microservice-card microservice-card--saga">
148 <div class="card-icon"></div>
149 <h3>Saga Pattern</h3>
150 <p>Event Chronicles</p>
151 <div class="card-status status--active">Active</div>
152 </div>
153
154 <div class="microservice-card microservice-card--sourcing">
155 <div class="card-icon">โณ</div>
156 <h3>Event Sourcing</h3>
157 <p>Kingdom History</p>
158 <div class="card-status status--active">Active</div>
159 </div>
160
161 <div class="microservice-card microservice-card--cqrs">
162 <div class="card-icon"></div>
163 <h3>CQRS</h3>
164 <p>Division of Power</p>
165 <div class="card-status status--active">Active</div>
166 </div>
167 </div>
168 </section>
169
170 <!-- Performance Patterns -->
171 <section class="granary-section">
172 <h2 class="section-title">
173 <span class="hieroglyph"></span>
174 Performance - Grain Warehouses
175 </h2>
176 <div class="performance-grid">
177 <div class="performance-metric">
178 <div class="metric-header">
179 <span class="metric-icon"></span>
180 <h3>Caching</h3>
181 </div>
182 <div class="metric-strategies">
183 <span class="strategy-badge">LRU</span>
184 <span class="strategy-badge">TTL</span>
185 <span class="strategy-badge">Write-through</span>
186 <span class="strategy-badge">Cache-aside</span>
187 </div>
188 <div class="metric-bar">
189 <div class="metric-fill metric-fill--high"></div>
190 </div>
191 </div>
192
193 <div class="performance-metric">
194 <div class="metric-header">
195 <span class="metric-icon"></span>
196 <h3>Load Balancing</h3>
197 </div>
198 <div class="metric-strategies">
199 <span class="strategy-badge">Round Robin</span>
200 <span class="strategy-badge">Least Conn</span>
201 <span class="strategy-badge">IP Hash</span>
202 </div>
203 <div class="metric-bar">
204 <div class="metric-fill metric-fill--high"></div>
205 </div>
206 </div>
207
208 <div class="performance-metric">
209 <div class="metric-header">
210 <span class="metric-icon"></span>
211 <h3>Database Sharding</h3>
212 </div>
213 <div class="metric-strategies">
214 <span class="strategy-badge">Geographic</span>
215 <span class="strategy-badge">Hash-based</span>
216 <span class="strategy-badge">Range-based</span>
217 </div>
218 <div class="metric-bar">
219 <div class="metric-fill metric-fill--medium"></div>
220 </div>
221 </div>
222
223 <div class="performance-metric">
224 <div class="metric-header">
225 <span class="metric-icon"></span>
226 <h3>Optimization</h3>
227 </div>
228 <div class="metric-strategies">
229 <span class="strategy-badge">Profiling</span>
230 <span class="strategy-badge">Indexing</span>
231 <span class="strategy-badge">Compression</span>
232 </div>
233 <div class="metric-bar">
234 <div class="metric-fill metric-fill--high"></div>
235 </div>
236 </div>
237 </div>
238 </section>
239
240 <!-- Security Layers -->
241 <section class="fortress-section">
242 <h2 class="section-title">
243 <span class="hieroglyph"></span>
244 Security - Fortyfikacje Faraona
245 </h2>
246 <div class="security-layers">
247 <div class="security-layer security-layer--authentication">
248 <div class="layer-number">1</div>
249 <div class="layer-details">
250 <h3>Authentication</h3>
251 <p>Identity authentication</p>
252 <div class="security-badges">
253 <span class="sec-badge">JWT</span>
254 <span class="sec-badge">OAuth 2.0</span>
255 <span class="sec-badge">SSO</span>
256 </div>
257 </div>
258 </div>
259
260 <div class="security-layer security-layer--authorization">
261 <div class="layer-number">2</div>
262 <div class="layer-details">
263 <h3>Authorization</h3>
264 <p>Access control and permissions</p>
265 <div class="security-badges">
266 <span class="sec-badge">RBAC</span>
267 <span class="sec-badge">ABAC</span>
268 <span class="sec-badge">ACL</span>
269 </div>
270 </div>
271 </div>
272
273 <div class="security-layer security-layer--validation">
274 <div class="layer-number">3</div>
275 <div class="layer-details">
276 <h3>Input Validation</h3>
277 <p>Walidacja i sanityzacja danych</p>
278 <div class="security-badges">
279 <span class="sec-badge">XSS Protection</span>
280 <span class="sec-badge">SQL Injection</span>
281 <span class="sec-badge">CSRF</span>
282 </div>
283 </div>
284 </div>
285
286 <div class="security-layer security-layer--encryption">
287 <div class="layer-number">4</div>
288 <div class="layer-details">
289 <h3>Data Encryption</h3>
290 <p>Encryption danych</p>
291 <div class="security-badges">
292 <span class="sec-badge">TLS/SSL</span>
293 <span class="sec-badge">AES-256</span>
294 <span class="sec-badge">RSA</span>
295 </div>
296 </div>
297 </div>
298
299 <div class="security-layer security-layer--monitoring">
300 <div class="layer-number">5</div>
301 <div class="layer-details">
302 <h3>Audit & Monitoring</h3>
303 <p>Logging and security monitoring</p>
304 <div class="security-badges">
305 <span class="sec-badge">SIEM</span>
306 <span class="sec-badge">IDS/IPS</span>
307 <span class="sec-badge">Alerting</span>
308 </div>
309 </div>
310 </div>
311 </div>
312 </section>
313
314 <!-- Footer with blessing -->
315 <footer class="pharaoh-footer">
316 <div class="footer-content">
317 <p class="blessing">
318 <span class="ankh-symbol"></span>
319 Blessing of Thoth - God of Wisdom and Writing
320 <span class="ankh-symbol"></span>
321 </p>
322 <p class="footer-quote">
323 "Architecture worthy of the Pyramids of Giza - enduring and monumental for millennia"
324 </p>
325 </div>
326 </footer>
327 </div>
328</body>
329</html>Remember: This is just the beginning of your journey! These foundations will allow you to build ever larger and more advanced projects. Good luck, young pharaoh of the internet!
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. What does the :has() pseudo-class do in CSS?
Hands-on tasks in the game
- Click in order
Arrange the :has() selector syntax for styling a parent that contains an image:
- Code editor
Create: article:has(img) { border: 2px solid gold }, article:has(video) { background: #1a1a2e }, article:not(:has(img, video)) { opacity: 0.7 }. Test with different content - the parent reacts to its children!