$ sudo teach IT

Мы заложили мобильную основу — теперь нужно, чтобы на широких экранах макет менялся: одна колонка превращалась в две и три, меню разворачивалось, отступы росли. Для этого CSS умеет применять стили выборочно, в зависимости от ширины экрана. Делают это медиазапросы @media — блоки правил, которые срабатывают только при выполнении условия. А ширины, на которых макет перестраивается, называют контрольными точками. Это главный инструмент адаптивной вёрстки: именно им сайт подстраивается под телефон, планшет и десктоп.

После этого урока вы сможете писать медиазапросы, задавать контрольные точки и строить макет, который меняет число колонок и вид по мере роста экрана.

Что уже умеем / что добавим

Вы освоили mobile-first и задали базовые мобильные стили. Теперь научимся расширять их под крупные экраны через @media. В сквозном проекте мы сделаем сетку карточек услуг адаптивной: одна колонка на телефоне, две на планшете, три на десктопе.

Что вы узнаете в рамках статьи

  • Как устроен медиазапрос @media и его синтаксис.
  • Что такое контрольные точки (breakpoints) и как их выбирать.
  • Как писать медиазапросы в духе mobile-first через min-width.
  • Как менять макет на разных экранах, наслаивая правила.

Ключевые термины

  • @media — правило CSS, применяющее стили при выполнении условия.
  • Медиа-условие — проверка, например min-width: 768px.
  • Контрольная точка (breakpoint) — ширина, на которой макет перестраивается.
  • min-width / max-width — условие «не уже / не шире заданной ширины».

Синтаксис @media

Медиазапрос — это блок, внутри которого лежат обычные правила CSS, но применяются они только когда выполнено условие в скобках:

@media (min-width: 768px) {
  .services {
    grid-template-columns: 1fr 1fr;
  }
}

Читается это так: «когда ширина экрана не меньше 768 пикселей, сделай в .services два столбца». Пока экран уже 768px, правило спит и действуют базовые стили (одна колонка). Как только ширина достигает порога — правило включается. Внутри @media можно менять любые свойства любых селекторов: колонки, отступы, размеры шрифта, видимость блоков. Это обычный CSS, просто с условием применения.

Контрольные точки

Контрольная точка — это ширина, на которой макет меняется. Обычно ориентируются на типичные классы устройств: узкие телефоны, планшеты, десктопы. Распространённый набор порогов — примерно 480px, 768px и 1024px, но это не жёсткий стандарт.

Хороший принцип: ставьте контрольную точку там, где макет начинает «ломаться» или выглядеть плохо, а не под конкретную модель телефона. Устройств слишком много, чтобы подгонять под каждое; правильнее расширять окно и смотреть, где строка становится слишком длинной или колонки — слишком узкими. Там и нужна точка перестройки. Так вы получаете макет, который хорошо выглядит на любом экране, а не только на нескольких выбранных.

Mobile-first и min-width

В подходе mobile-first медиазапросы пишут через min-width: базовые стили — для мобильных, а каждое условие добавляет изменения для более широких экранов. Правила наслаиваются от меньшего к большему:

/* Базовые: мобильные, одна колонка */
.services {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}

/* Планшет и шире: две колонки */
@media (min-width: 768px) {
  .services {
    grid-template-columns: 1fr 1fr;
  }
}

/* Десктоп и шире: три колонки */
@media (min-width: 1024px) {
  .services {
    grid-template-columns: 1fr 1fr 1fr;
  }
}

По мере роста экрана включаются всё новые правила, каждое переопределяет колонки. Есть и обратный подход — max-width (стили для экранов уже заданной ширины), но при mobile-first именно min-width естественнее: вы всегда идёте от простого мобильного к богатому десктопному, добавляя, а не отменяя.

Меняем макет по точкам

Внутри медиазапросов можно перестраивать не только сетку, но и всё оформление. Например, на десктопе увеличить отступы, а на мобильном спрятать второстепенный блок:

.aside {
  display: none;
}

@media (min-width: 1024px) {
  .aside {
    display: block;
  }

  .page {
    padding: 2rem 4rem;
  }
}

Здесь боковая панель скрыта на мобильном (чтобы не загромождать узкий экран) и появляется только на десктопе, где для неё есть место; заодно на широком экране растут отступы страницы. Так медиазапросы позволяют не просто менять число колонок, а по-настоящему адаптировать интерфейс под возможности экрана — показывать больше там, где есть простор, и убирать лишнее на тесном экране.

Применяем в проекте

Сделаем сетку карточек услуг адаптивной. Базово (на телефоне) — одна колонка, на планшете от 768px — две, на десктопе от 1024px — три. Мы просто наслоим медиазапросы поверх мобильной основы.

/* Базовые мобильные стили */
.services {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}

@media (min-width: 768px) {
  .services {
    grid-template-columns: 1fr 1fr;
  }
}

@media (min-width: 1024px) {
  .services {
    grid-template-columns: 1fr 1fr 1fr;
  }
}

Откройте страницу и плавно расширяйте окно: на узком экране карточки идут в одну колонку, при достижении 768px перестраиваются в две, а на широком экране — в три. Макет живёт вместе с размером окна, и на каждом устройстве услуги показаны оптимально. Это и есть адаптивная сетка — сердце современной вёрстки.

Частые ошибки

  • Точки под конкретные модели.
    Не подгоняйте breakpoints под «айфон такой-то»; ставьте их там, где макет начинает выглядеть плохо.
  • Смешение min-width и max-width.
    В одном проекте держитесь одного подхода (при mobile-first — min-width), иначе правила начнут конфликтовать.
  • Забытый viewport.
    Без мета-тега из прошлого урока медиазапросы сработают по ложной ширине; проверьте, что он на месте.
  • Слишком много точек.
    Десяток контрольных точек трудно поддерживать; обычно хватает двух-трёх ключевых.

Итоги

Прекрасная работа — теперь ваш макет по-настоящему адаптивен! Вы освоили медиазапросы @media, научились выбирать контрольные точки по поведению макета, а не по моделям устройств, и писать правила в духе mobile-first через min-width. Сетка услуг вашего сайта плавно меняет число колонок от телефона к десктопу — именно так устроены современные страницы.

Отличный прогресс! В следующем уроке мы познакомимся с новинкой — контейнерными запросами @container, которые позволяют компоненту подстраиваться не под размер экрана, а под размер своего родителя.

На следующий урок