$ sudo teach IT
Урок 5.3 — Адаптивность

Урок 5.3: Адаптивность

Модуль 5 — Продвинутый CSS

Что такое адаптивный дизайн

Адаптивный (или отзывчивый) дизайн — это подход, при котором сайт одинаково хорошо выглядит на любом устройстве: от 4K-монитора до старого iPhone. Не существует «мобильной версии» и «десктопной версии» — есть один сайт, который подстраивается под размер экрана.

Раньше сайты делали фиксированной ширины (например, 960px). Если открыть такой сайт на телефоне — контент уезжает за правый край, приходится зумить и скроллить по горизонтали. Кошмар. Сейчас так никто не делает.

Адаптивный дизайн строится на трёх китах:

  • Гибкая сетка — элементы используют проценты, а не пиксели
  • Гибкие изображения — картинки масштабируются под контейнер
  • Медиа-запросы — CSS-правила, которые включаются на определённой ширине экрана
/* Главный принцип: контент подстраивается под экран, а не наоборот */

/* Плохо: фиксированная ширина */
.container {
  width: 960px; /* на телефоне вылезет */
}

/* Хорошо: гибкая ширина */
.container {
  max-width: 960px;
  width: 100%;
  padding: 0 16px;
}

Первое правило адаптивности: никогда не используй фиксированную ширину там, где можно использовать max-width или проценты. max-width: 960px + width: 100% означает: «контейнер шириной не больше 960px, но на маленьких экранах — на всю ширину с отступами».

💡 Совет: Начинай проект с мобильной версии, а потом добавляй стили для больших экранов. Это называется Mobile-first. Проще добавить что-то для широкого экрана, чем урезать для узкого.

meta viewport tag — самое важное для мобильных

Без этого тега адаптивность не будет работать. Вообще. Ты можешь написать идеальные медиа-запросы, но на телефоне сайт будет показываться как уменьшенная копия десктопа.

<meta name="viewport" content="width=device-width, initial-scale=1.0">

Что делает этот тег:

  • width=device-width — говорит браузеру: «используй реальную ширину устройства, не выдумывай 980px»
  • initial-scale=1.0 — начальный масштаб 100% (не зум)

Без него iPhone и Android будут рендерить страницу как на десктопе шириной 980px и потом масштабировать. Контент будет мелким. Пользователю придётся зумить пальцами. С этим тегом страница использует реальные пиксели устройства.

Этот тег должен быть в <head> каждого HTML-документа. Если ты забудешь его — всё, что мы будем обсуждать дальше, не имеет смысла.

💡 Совет: Всегда добавляй <meta name="viewport" content="width=device-width, initial-scale=1.0"> в каждую страницу. Даже если ты делаешь «просто страничку». Это стандарт.

@media (max-width: 768px) — точка перелома

@media (медиа-запросы) — это CSS-правила, которые применяются только при определённых условиях. Чаще всего — при определённой ширине экрана.

/* Базовые стили — для всех экранов */
.grid {
  display: flex;
  gap: 20px;
}
.grid .item {
  flex: 1;
  background: #e94560;
  padding: 20px;
}

/* Когда экран УЖЕ 768px или МЕНЬШЕ — включаются эти стили */
@media (max-width: 768px) {
  .grid {
    flex-direction: column;
  }
  .grid .item {
    background: #10b981;
  }
}

max-width: 768px означает: «если ширина экрана меньше или равна 768px, примени эти стили». Это называется точка перелома (breakpoint) — граница, при достижении которой макет перестраивается.

Попробуй изменить ширину окна браузера. Ниже — демонстрация точки перелома на 600px. Когда ширина меньше 600px, блоки встают в колонку и меняют цвет:

Элемент 1
Элемент 2
Элемент 3

Сузь окно до <600px — блоки станут в колонку и покраснеют

Стандартные точки перелома, которые используют в вебе:

  • 320px — старые смартфоны
  • 480px — современные смартфоны
  • 768px — планшеты
  • 1024px — маленькие ноутбуки и iPad в landscape
  • 1280px — десктоп

Но на практике не стоит ориентироваться на конкретные устройства. Точки перелома должны определяться контентом — смотри, в какой момент макет начинает выглядеть плохо, и ставь breakpoint там.

/* Mobile-first подход: сначала база для мобилок */
.grid {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* Потом улучшаем для планшетов */
@media (min-width: 768px) {
  .grid {
    flex-direction: row;
    flex-wrap: wrap;
  }
  .grid .item {
    flex: 1 1 calc(50% - 16px);
  }
}

/* И для десктопа */
@media (min-width: 1024px) {
  .grid .item {
    flex: 1;
  }
}

Обрати внимание: здесь используется min-width, а не max-width. Это Mobile-first подход: стили по умолчанию — для мобильных, а медиа-запросы добавляют улучшения для больших экранов. Это проще и чище, чем наоборот.

💡 Совет: Используй min-width в медиа-запросах (mobile-first), а не max-width. Так ты начинаешь с мобильной версии и добавляешь стили для широких экранов. Меньше шансов что-то сломать.

vw, vh, % — относительные единицы

Пиксели (px) — абсолютные единицы. 100px — это 100px на любом экране. Для адаптивности этого мало. Нужны относительные единицы, которые подстраиваются под размер экрана.

Основные относительные единицы:

  • % — процент от родителя. width: 50% — половина ширины родителя.
  • vw — процент от ширины окна. width: 50vw — половина окна браузера.
  • vh — процент от высоты окна. height: 100vh — на всю высоту окна.
  • em — относительно размера шрифта родителя. padding: 2em — 2 × размер шрифта родителя.
  • rem — относительно корневого шрифта (<html>). margin: 1.5rem — 1.5 × размер шрифта в <html>.
200px
50%
30vw

Меняй ширину окна — относительные единицы (%, vw) меняются, пиксели — нет.

Текст с font-size: 1.2em — размер зависит от родительского шрифта

Где что использовать:

  • % — для ширины колонок, карточек, контейнеров
  • vw — для глобальных отступов, крупных заголовков, секций на всю ширину
  • vh — для секций на всю высоту экрана (hero, full-screen блоки)
  • rem — для отступов, размеров текста (удобно, если пользователь меняет базовый размер шрифта)
  • em — для отступов, которые должны масштабироваться с размером шрифта

Классический пример — секция на всю высоту экрана:

.hero {
  width: 100vw;   /* на всю ширину окна */
  height: 100vh;  /* на всю высоту окна */
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, #667eea, #764ba2);
}

Эта секция будет ровно на весь экран, независимо от размера устройства. Ни тебе фиксированной высоты, ни скролла — чистая адаптивность.

Ещё один приём — адаптивный текст через clamp(). Это CSS-функция, которая задаёт диапазон значений:

/* font-size: от 16px до 32px, пропорционально ширине окна */
h1 {
  font-size: clamp(1.5rem, 4vw, 2.5rem);
}

/* padding: от 16px до 48px */
.container {
  padding: clamp(1rem, 3vw, 3rem);
}

clamp(min, preferred, max) — минимальное значение, желаемое (гибкое), максимальное. Идеально для адаптивных заголовков и отступов.

Практика: меню, которое на телефоне становится вертикальным

Давай сделаем полноценную адаптивную страницу. У нас будет меню, которое на десктопе — горизонтальное, а на мобилке — вертикальное, плюс сетка карточек, которая на телефоне превращается в одну колонку.

Вот полный код. Скопируй, открой в браузере и меняй ширину окна:

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Адаптивный сайт</title>
<style>
  *, *::before, *::after {
    box-sizing: border-box;
  }
  body {
    font-family: 'Segoe UI', system-ui, sans-serif;
    margin: 0;
    background: #f5f5f5;
    color: #333;
  }

  /* Хедер */
  .header {
    background: linear-gradient(135deg, #1a1a2e, #16213e);
    color: #fff;
    padding: 16px 24px;
    display: flex;
    align-items: center;
    justify-content: space-between;
  }
  .header .logo {
    font-size: 1.3em;
    font-weight: bold;
  }

  /* Навигация */
  .nav {
    display: flex;
    gap: 4px;
  }
  .nav a {
    color: #ccc;
    text-decoration: none;
    padding: 8px 18px;
    border-radius: 6px;
    transition: background 0.2s, color 0.2s;
    font-size: 0.95em;
  }
  .nav a:hover {
    background: #533483;
    color: #fff;
  }
  .nav-toggle {
    display: none;
    background: none;
    border: 1px solid rgba(255,255,255,0.3);
    color: #fff;
    padding: 8px 16px;
    border-radius: 6px;
    cursor: pointer;
    font-size: 0.9em;
  }

  /* Контент */
  .content {
    max-width: 1100px;
    margin: 0 auto;
    padding: 40px 24px;
  }
  .content h1 {
    font-size: clamp(1.8rem, 4vw, 2.5rem);
    margin-bottom: 12px;
  }
  .content > p {
    color: #666;
    font-size: 1.05em;
    max-width: 600px;
    margin-bottom: 40px;
    line-height: 1.7;
  }

  /* Сетка карточек */
  .card-grid {
    display: flex;
    gap: 20px;
    flex-wrap: wrap;
  }
  .card {
    background: #fff;
    border-radius: 14px;
    padding: 28px 24px;
    flex: 1 1 calc(33.333% - 14px);
    min-width: 240px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.04);
    transition: transform 0.3s, box-shadow 0.3s;
  }
  .card:hover {
    transform: translateY(-4px);
    box-shadow: 0 8px 24px rgba(0,0,0,0.08);
  }
  .card .icon {
    font-size: 2em;
    margin-bottom: 12px;
  }
  .card h3 {
    margin: 0 0 8px;
    font-size: 1.15em;
  }
  .card p {
    color: #777;
    font-size: 0.9em;
    line-height: 1.6;
    margin: 0;
  }

  /* Футер */
  .footer {
    text-align: center;
    padding: 30px 24px;
    color: #999;
    font-size: 0.85em;
    border-top: 1px solid #e0e0e0;
    margin-top: 40px;
  }

  /* Адаптация: планшеты */
  @media (max-width: 768px) {
    .card {
      flex: 1 1 calc(50% - 10px);
    }
  }

  /* Адаптация: телефоны */
  @media (max-width: 640px) {
    .nav {
      display: none;
      position: absolute;
      top: 60px;
      left: 0;
      width: 100%;
      background: #1a1a2e;
      flex-direction: column;
      padding: 12px;
      border-top: 1px solid #2a2a4a;
    }
    .nav.open {
      display: flex;
    }
    .nav a {
      display: block;
      padding: 14px 16px;
      border-bottom: 1px solid #2a2a4a;
      border-radius: 0;
    }
    .nav a:last-child {
      border-bottom: none;
    }
    .nav-toggle {
      display: block;
    }
    .card {
      flex: 1 1 100%;
    }
    .header {
      position: relative;
    }
  }
</style>
</head>
<body>

  <header class="header">
    <div class="logo">🌟 MySite</div>
    <button class="nav-toggle" onclick="this.nextElementSibling.classList.toggle('open')">☰ Меню</button>
    <nav class="nav">
      <a href="#">Главная</a>
      <a href="#">О нас</a>
      <a href="#">Услуги</a>
      <a href="#">Блог</a>
      <a href="#">Контакты</a>
    </nav>
  </header>

  <main class="content">
    <h1>Адаптивный дизайн — это просто</h1>
    <p>
      Сузь окно браузера — меню превратится в вертикальное, а карточки
      встанут в одну колонку. На десктопе они располагаются в три колонки,
      на планшете — в две, на телефоне — одна под другой.
    </p>

    <div class="card-grid">
      <div class="card">
        <div class="icon">📱</div>
        <h3>Mobile-first</h3>
        <p>Сначала проектируем для мобильных устройств, потом добавляем улучшения для больших экранов.</p>
      </div>
      <div class="card">
        <div class="icon">📐</div>
        <h3>Гибкая сетка</h3>
        <p>Элементы используют проценты, flexbox и относительные единицы вместо фиксированных пикселей.</p>
      </div>
      <div class="card">
        <div class="icon">📏</div>
        <h3>Медиа-запросы</h3>
        <p>CSS-правила, которые включаются на определённой ширине экрана и перестраивают макет.</p>
      </div>
      <div class="card">
        <div class="icon">🖼️</div>
        <h3>Гибкие изображения</h3>
        <p>Картинки масштабируются с помощью max-width: 100%, чтобы не вылезать за контейнер.</p>
      </div>
      <div class="card">
        <div class="icon">🔤</div>
        <h3>Относительные единицы</h3>
        <p>vw, vh, %, rem, em — единицы, которые подстраиваются под размер экрана и шрифта.</p>
      </div>
      <div class="card">
        <div class="icon">🎯</div>
        <h3>Точки перелома</h3>
        <p>Breakpoints в 640px, 768px, 1024px — стандартные границы, где макет перестраивается.</p>
      </div>
    </div>
  </main>

  <footer class="footer">
    © 2026 MySite. Работает на всех устройствах.
  </footer>

  <script>
    // Закрывать меню при клике на ссылку
    document.querySelectorAll('.nav a').forEach(link => {
      link.addEventListener('click', () => {
        document.querySelector('.nav').classList.remove('open');
      });
    });
  </script>
</body>
</html>

Давай разберём, как работает адаптивность в этом примере:

1. meta viewport — первая строка в head. Без неё ничего не работает.

2. Mobile-first меню:

  • На десктопе (шире 640px) — .nav это display: flex, ссылки в ряд.
  • На телефоне (уже 640px) — @media (max-width: 640px) делает .nav скрытым (display: none), кнопка .nav-toggle становится видимой (display: block). При клике на кнопку (onclick) добавляется класс .open, и меню показывается вертикальным списком.

3. Адаптивная сетка карточек:

  • По умолчанию (десктоп) — flex: 1 1 calc(33.333% - 14px), три в ряд.
  • На планшете (≤768px) — flex: 1 1 calc(50% - 10px), две в ряд.
  • На телефоне (≤640px) — flex: 1 1 100%, одна колонка.

4. Гибкий контейнер:

  • max-width: 1100px + авто-отступы — контейнер не становится шире 1100px, но на маленьких экранах использует всю ширину с padding'ами.

5. Адаптивный заголовок:

  • font-size: clamp(1.8rem, 4vw, 2.5rem) — от 1.8rem до 2.5rem в зависимости от ширины окна.

Вот ещё несколько приёмов адаптивности, которые пригодятся:

/* 1. Гибкое изображение */
img {
  max-width: 100%;
  height: auto;
  display: block;
}

/* 2. Адаптивные отступы */
.container {
  padding: clamp(1rem, 3vw, 2rem);
}

/* 3. Скрытие элементов на мобилке */
.desktop-only { display: block; }
.mobile-only { display: none; }

@media (max-width: 640px) {
  .desktop-only { display: none; }
  .mobile-only { display: block; }
}

/* 4. Адаптивный текст */
p {
  font-size: clamp(0.95rem, 2vw, 1.1rem);
}

/* 5. Сетка без медиа-запросов (auto-fill) */
.grid-auto {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 20px;
}

Последний приём — auto-fill — особенно крут. Он автоматически создаёт столько колонок, сколько влезает, при минимальной ширине 280px. Медиа-запросы не нужны — сетка адаптируется сама.

Давай подведём итог. Вот шпаргалка по адаптивности:

/* АДАПТИВНОСТЬ — ШПАРГАЛКА */

/* 1. Всегда в head */
<meta name="viewport" content="width=device-width, initial-scale=1.0">

/* 2. Гибкий контейнер */
.container {
  max-width: 1200px;
  width: 100%;
  margin: 0 auto;
  padding: 0 16px;
}

/* 3. Гибкие изображения */
img, video, iframe {
  max-width: 100%;
  height: auto;
}

/* 4. Mobile-first медиа-запросы */
/* База — для мобилок */
.card { flex: 1 1 100%; }

/* Планшет */
@media (min-width: 768px) {
  .card { flex: 1 1 calc(50% - 10px); }
}

/* Десктоп */
@media (min-width: 1024px) {
  .card { flex: 1 1 calc(33.333% - 14px); }
}

/* 5. Относительные единицы */
width: 100%;           /* от родителя */
height: 100vh;         /* на весь экран */
font-size: clamp(1rem, 3vw, 2rem); /* адаптивный текст */
padding: 2rem;         /* от корневого шрифта */

/* 6. Точки перелома (по контенту!) */
/* 640px — телефоны */
/* 768px — планшеты */
/* 1024px — десктоп */

Главное, что нужно запомнить:

  • <meta name="viewport"> — обязателен для адаптивности
  • Mobile-first: сначала стили для телефона, потом для больших экранов
  • Медиа-запросы — перестраивают макет под размер экрана
  • Относительные единицы (%, vw, vh, rem) — подстраиваются под экран
  • Точки перелома ставятся там, где контент начинает выглядеть плохо
  • max-width: 100% на картинках — чтобы они не вылезали за родителя
  • clamp() — удобная функция для адаптивных размеров

Адаптивность — это не магия и не сложно. Это просто привычка писать гибкие стили. Начни с meta viewport и max-width вместо фиксированной ширины — и ты уже на полпути к сайту, который одинаково хорошо выглядит на любом устройстве.

Поздравляю! Ты прошёл модули 4 и 5. Теперь ты умеешь работать с блочной моделью, flexbox, позиционированием, анимациями и адаптивностью. Это основа современного CSS. В следующих модулях мы перейдём к JavaScript — и там эти знания пригодятся каждый день.

💡 Задание: Возьми любой свой проект или просто HTML-страницу. Добавь <meta name="viewport">, если его нет. Замени фиксированную ширину на max-width с процентами. Добавь один медиа-запрос для телефона, чтобы меню стало вертикальным. Посмотри, как страница преобразится на мобильном устройстве.
Урок 5.3 — Адаптивность | Модуль 5: Продвинутый CSS

Урок 5.3: Адаптивность

5 вопросов