Урок 50. Примеры: Итоговый проект: адаптивный многостраничный сайт

📁 Раздел: Итоговый проект ⏱️ Время изучения: ~120 мин 🎯 Сложность: Продвинутая
#min #width #minmax #clamp #font-size #media #focus-visible #prefers-reduced-motion

⚡ Кратко

Собираем сайт по фрагментам: адаптивный header (flex) → hero (grid) → сетка карточек (auto-fit) → форма → footer. Рядом с каждым кодом — живой результат; меняй значения и предсказывай поведение.

Каждый фрагмент — кусочек собираемого сайта. Сверху живой результат, ниже код. Идём по возрастанию: от шапки до футера.

1. Адаптивный header / nav (Flexbox)

Логотип слева, меню справа; flex-wrap переносит меню под логотип на узком экране.

📄 final-project/index.html
<header class="site-header">
  <a class="logo" href="index.html">Studio</a>
  <nav aria-label="Главная навигация">
    <a href="work.html">Работы</a>
    <a href="about.html">О нас</a>
    <a href="contact.html">Контакты</a>
  </nav>
</header>
.site-header {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  justify-content: space-between;
  align-items: center;
  padding-block: 1rem;
}

2. Hero: Grid + fluid-типографика (clamp)

Текст и картинка рядом; заголовок плавно меняет размер через clamp(). На узком экране колонки схлопнутся в одну (см. медиазапрос в примере 5).

Адаптивный сайт

Семантика, Grid, Flexbox, изображения и доступность.

hero image
📄 final-project/index.html
<section class="hero">
  <div>
    <h1>Адаптивный многостраничный сайт</h1>
    <p>Семантика, Grid, Flexbox, изображения и доступность.</p>
  </div>
  <picture>
    <source type="image/webp" srcset="hero.webp 960w, hero@2x.webp 1920w"
            sizes="(min-width: 64rem) 50vw, 100vw">
    <img src="hero.jpg" alt="Пример главной страницы" width="960" height="640">
  </picture>
</section>
.hero { display: grid; gap: clamp(1rem, 4vw, 3rem); }
.hero h1 { font-size: clamp(1.5rem, 4vw, 3rem); }
@media (min-width: 64rem) {
  .hero { grid-template-columns: 1fr 1fr; align-items: center; }
}

3. Сетка карточек (Grid auto-fit / minmax)

Карточки сами решают, сколько колонок поместится: repeat(auto-fit, minmax(180px, 1fr)). Никаких ручных медиазапросов для самой сетки.

Проект 1

Лендинг

Проект 2

Магазин

Проект 3

Блог

Проект 4

Дашборд

📄 final-project/styles.css
.work-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1rem;
}

4. Доступная форма контактов

Каждое поле связано с <label> через for/id — клик по подписи ставит фокус в поле, скринридер озвучивает поле правильно.

📄 final-project/contact.html
<form class="contact-form">
  <label for="name">Имя</label>
  <input id="name" name="name" type="text" required>

  <label for="email">E-mail</label>
  <input id="email" name="email" type="email" required>

  <button type="submit">Отправить</button>
</form>

5. Footer + mobile-first медиазапрос

Footer на Flexbox; базовые стили — под телефон, а min-width добавляет раскладку на широком экране.

📄 final-project/styles.css
/* mobile-first: базовый стиль для узкого экрана */
.hero { display: grid; gap: clamp(1rem, 4vw, 3rem); }

/* широкий экран — добавляем колонки */
@media (min-width: 64rem) {
  .hero { grid-template-columns: 1fr 1fr; align-items: center; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms;
    transition-duration: 0.01ms;
    scroll-behavior: auto;
  }
}
Эксперимент: открой пример 3 в DevTools (F12) и тяни ширину окна — карточки сами перестроятся с 4 колонок до 1. Это auto-fit в действии, без единого медиазапроса.

Навигация