Проект · Урок 10

Собираем лендинг

Поздравляем — вы дошли до финала! Теперь объединим всё, что узнали: сверстаем лендинг для вымышленной школы веб-разработки «Код». Одна страница, три технологии, никакого магии.

Что делаем

Одностраничник с шапкой и меню, первым экраном, блоком преимуществ, формой обратной связи и подвалом. План простой: каркас → секции → стили → интерактив → полировка.

💡
Этот сайт, на котором вы сейчас читаете, устроен ровно так же. Спокойно откройте DevTools (F12) и посмотрите, как устроены его шапка и карточки.

1. Каркас страницы

Начинаем с семантики: <header> для шапки, <main> для содержимого, <section> для смысловых блоков и <footer> для подвала.

<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Школа «Код» — курс по веб-разработке</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <header class="nav">
    <a href="#" class="logo">Код</a>
    <nav>
      <a href="#about">О школе</a>
      <a href="#program">Программа</a>
      <a href="#contact">Контакты</a>
    </nav>
  </header>

  <main>
    <section class="hero">...</section>
    <section id="about">...</section>
    <section id="program">...</section>
    <section id="contact">...</section>
  </main>

  <footer>© 2026 Школа «Код»</footer>
</body>
</html>

2. Секции

Первый экран — крупный заголовок, короткое описание и кнопка-призыв. Преимущества оформляем карточками, а связь — простой формой. Обратите внимание: у каждой секции есть id, чтобы меню могло прокручивать к ней.

<section class="hero">
  <h1>Станьте разработчиком за 10 уроков</h1>
  <p>HTML, CSS и JavaScript с практикой с первого дня.</p>
  <a href="#program" class="btn">Смотреть программу</a>
</section>

<section id="program">
  <h2>Чему вы научитесь</h2>
  <div class="cards">
    <div class="card">Верстать семантичный HTML</div>
    <div class="card">Стилизовать через Flexbox и Grid</div>
    <div class="card">Добавлять интерактив на JS</div>
  </div>
</section>

3. Стили

Шапку растягиваем через flex + justify-content: space-between, карточки раскладываем готовой грид-функцией repeat(auto-fit, minmax(200px, 1fr)) — она сама подстроит количество колонок под ширину экрана. Мобильную версию дописываем @media-правилом.

/* шапка: логотип слева, меню справа */
.nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 24px;
  padding: 16px 32px;
}

/* карточки: сколько влезет, автоматически */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
}

.card {
  padding: 24px;
  border: 1px solid #dbe3ec;
  border-radius: 12px;
}

/* планшеты и телефоны: укрупняем кнопки и отступы */
@media (max-width: 640px) {
  .nav { flex-direction: column; }
  .nav a { padding: 12px; }
}
ℹ️
Правило «mobile-first»: пишите сначала стили для узкого экрана и добавляйте min-width-брейкпоинты. Меньше кода, меньше ошибок.

4. JavaScript: чуть-чуть жизни

Три маленькие задачи: плавный скролл по якорям, подсветка активного пункта меню и перехват отправки формы. Всё это — знакомые вам addEventListener, querySelectorAll и classList из урока 9.

// 1. плавная прокрутка к секциям по клику
document.querySelectorAll('nav a').forEach(function (link) {
  link.addEventListener('click', function (e) {
    e.preventDefault();
    var target = document.querySelector(link.getAttribute('href'));
    if (target) target.scrollIntoView({ behavior: 'smooth' });
  });
});

// 2. подсветка активного раздела при прокрутке
window.addEventListener('scroll', function () {
  var pos = window.scrollY + 80;
  document.querySelectorAll('section[id]').forEach(function (section) {
    var link = document.querySelector(
      'nav a[href="#' + section.id + '"]'
    );
    if (!link) return;
    var top = section.offsetTop;
    var bottom = top + section.offsetHeight;
    link.classList.toggle('active', pos >= top && pos < bottom);
  });
});

// 3. форма: не отправлять, а поблагодарить
document.querySelector('form').addEventListener('submit', function (e) {
  e.preventDefault();
  this.innerHTML = '<p class="ok">Спасибо! Мы свяжемся с вами.</p>';
});
⚠️
Не вставляйте в форму чужие обработчики без e.preventDefault() — страница перезагрузится и ничего не «отправит». В реальных проектах дальше идёт запрос на сервер.

5. Полировка перед публикацией

🎉
Всё, вы сделали свой первый сайт! Ниже — квиз, чтобы засчитать проект, и песочница, где можно собрать лендинг прямо на этой странице и посмотреть на результат.