Адаптив: mobile-first, media queries

Адаптив: mobile-first, media queries

Больше половины трафика в вебе - с мобильных. Если сайт не адаптирован - пользователь уйдёт через 3 секунды.

Mobile-first - подход к стилям

Сначала пишешь стили для мобилки (базовые), потом расширяешь для больших экранов через @media (min-width: ...):

/* Базовые стили - для всех (включая мобилки) */
.container {
  padding: 16px;
}

.cards {
  display: grid;
  grid-template-columns: 1fr; /* одна колонка */
  gap: 16px;
}

/* Планшет и больше */
@media (min-width: 768px) {
  .container { padding: 24px; }
  .cards { grid-template-columns: repeat(2, 1fr); }
}

/* Десктоп */
@media (min-width: 1024px) {
  .container { padding: 32px; max-width: 1200px; margin: 0 auto; }
  .cards { grid-template-columns: repeat(3, 1fr); }
}
Mobile-first проще: ты начинаешь с простого (1 колонка) и добавляешь сложность. Desktop-first наоборот - начинаешь сложно и пытаешься упростить, что часто ломается.

Media queries - синтаксис

/* Ширина экрана */
@media (min-width: 768px) { }    /* 768px и шире */
@media (max-width: 600px) { }    /* 600px и уже */

/* Комбинация */
@media (min-width: 768px) and (max-width: 1023px) { }  /* только планшеты */

/* Ориентация */
@media (orientation: landscape) { }  /* горизонтальная */
@media (orientation: portrait) { }   /* вертикальная */

/* Тёмная тема */
@media (prefers-color-scheme: dark) {
  :root {
 --color-bg: #1a202c;
 --color-text: #e2e8f0;
  }
}

/* Уменьшенная анимация (для людей с вестибулярными нарушениями) */
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

Типичные брейкпоинты

< 640px     Телефон     1 колонка, крупные кнопки, гамбургер-меню
640-1024px  Планшет     2 колонки, sidebar может скрываться
1024px+     Десктоп     3+ колонки, sticky sidebar, полное меню
1280px+     Большой     max-width контейнера, контент по центру

Responsive breakpoints: один макет на 320px, 768px и 1280px

Не пиши `@media (width: 375px)` под конкретный iPhone. Устройств тысячи. Выбирай брейкпоинты по контенту: «где контент начинает выглядеть плохо - там ставь брейкпоинт».

viewport - обязательный мета-тег

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

Без него мобильный браузер думает, что ширина экрана 980px, и показывает десктопную версию мелко. С ним - использует реальную ширину устройства.

Адаптивные паттерны

Гамбургер-меню на мобилке

.nav-links {
  display: none; /* скрыто на мобилке */
}

.hamburger {
  display: block; /* показан на мобилке */
}

@media (min-width: 768px) {
  .nav-links {
    display: flex;
    gap: 24px;
  }
  .hamburger {
    display: none; /* скрыт на десктопе */
  }
}

Sidebar скрывается на мобилке

.layout {
  display: grid;
  grid-template-columns: 1fr;
}

.sidebar {
  display: none;
}

@media (min-width: 1024px) {
  .layout {
    grid-template-columns: 250px 1fr;
  }
  .sidebar {
    display: block;
  }
}

Адаптивная типографика

body {
  font-size: 16px;
  line-height: 1.6;
}

h1 {
  font-size: 1.75rem; /* 28px на мобилке */
}

@media (min-width: 768px) {
  h1 {
    font-size: 2.25rem; /* 36px на десктопе */
  }
}

Адаптивные изображения

img {
  max-width: 100%;  /* не вылезает за контейнер */
  height: auto;     /* сохраняет пропорции */
}
<!-- Разные изображения для разных экранов -->
<picture>
  <source media="(min-width: 1024px)" srcset="hero-large.jpg" />
  <source media="(min-width: 640px)" srcset="hero-medium.jpg" />
  <img src="hero-small.jpg" alt="Hero" />
</picture>

clamp() - адаптивные значения без media queries

h1 {
  font-size: clamp(1.5rem, 4vw, 3rem);
  /* минимум 1.5rem, идеально 4vw, максимум 3rem */
}

.container {
  padding: clamp(16px, 3vw, 48px);
}

clamp(min, preferred, max) - плавно меняет значение в зависимости от ширины окна. Одна строка вместо трёх media queries.

Единицы vw, vh, dvh

.hero { height: 100vh; }   /* 100% высоты viewport */
.full { width: 100vw; }    /* 100% ширины viewport */
На мобильных `100vh` включает адресную строку браузера, из-за чего контент прыгает при скролле. Используй `100dvh` (dynamic viewport height) или `min-height: 100vh` вместо `height: 100vh`.

Проверка адаптивности

В DevTools есть режим эмуляции устройств (Ctrl+Shift+M в Chrome). Можно:

  • переключать между размерами устройств
  • тестировать touch-события
  • симулировать медленное соединение
  • проверять тёмный режим через Rendering → Emulate CSS media feature

Мини-задание

  • Сделай карточки: 1 колонка на мобиле, 2 на планшете, 3 на десктопе
  • Спрячь sidebar на мобиле через display: none и @media (min-width: 1024px)
  • Добавь prefers-color-scheme: dark для тёмной темы
  • Попробуй clamp() для адаптивного размера шрифта
  • Открой DevTools и протестируй сайт в режиме мобильного устройства

Зарегистрируйтесь бесплатно, чтобы пройти квиз, решить задание с автопроверкой и вести прогресс.