← Все статьи

Медиазапросы CSS: понятное объяснение с примерами для мобильных

Медиа запросы CSS: синтаксис, min-width и max-width, новый синтаксис диапазонов, функции для мобильных, тёмной темы и касаний, частые ошибки.

Медиазапрос CSS применяет блок стилей, только когда устройство или браузер соответствует условию: например, viewport не уже заданной ширины, экран в альбомной ориентации или включена тёмная тема. @media (min-width: 48rem) { ... } означает «применяй эти правила, когда ширина viewport не меньше 48rem». Именно медиазапросы позволяют одной странице менять раскладку на телефонах, планшетах и десктопах.

Базовый синтаксис

@media (min-width: 768px) {
  .sidebar { display: block; }
}

У медиазапроса три необязательные части:

  • тип носителя: screen, print или all (по умолчанию);
  • одна или несколько медиафункций в скобках, например (min-width: 768px) или (orientation: landscape);
  • логические операторы, которые их объединяют: and, , (или) и not.
@media screen and (min-width: 768px) and (orientation: landscape) { ... }
@media (max-width: 480px), (orientation: portrait) { ... }
@media not print { ... }

Медиазапрос можно применить и ко всей таблице стилей: <link rel="stylesheet" href="print.css" media="print">.

min-width или max-width

min-width означает «такой ширины или шире», max-width — «такой ширины или уже». От выбранного направления зависит, как вы пишете остальной CSS.

  • Mobile first (рекомендуется): базовые стили рассчитаны на телефоны, а запросы с min-width добавляют раскладку для больших экранов. Подробнее в статье о подходе mobile first.
  • Desktop first: базовые стили рассчитаны на десктоп, а запросы с max-width отменяют лишнее для маленьких экранов.
/* Mobile first */
.nav { flex-direction: column; }

@media (min-width: 48rem) {
  .nav { flex-direction: row; }
}

Если смешивать оба направления в одном проекте, появляются пересечения и дыры. Выберите одно, а второе используйте только для мелких исключений.

Современный синтаксис диапазонов

В Media Queries Level 4 появились операторы сравнения. Их проще читать, и с ними легче избежать ошибок на единицу:

@media (width >= 48rem) { ... }
@media (40rem <= width < 64rem) { ... }

Синтаксис диапазонов поддерживают все актуальные основные браузеры (Chrome и Edge с версии 104, Firefox с 63, Safari с 16.4). Если нужно поддерживать старые версии Safari, продолжайте писать min-width и max-width или поручите преобразование сборщику.

Учтите, что (width < 768px) и (max-width: 767px) не одно и то же: первый вариант срабатывает и на 767,5 px, а такая ширина бывает на экранах с дробной плотностью пикселей.

Медиазапросы для мобильных: типовые примеры

Колонки друг под другом на маленьких экранах:

.grid { display: grid; gap: 1rem; }

@media (min-width: 40rem) {
  .grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 64rem) {
  .grid { grid-template-columns: repeat(4, 1fr); }
}

Меньшие отступы на телефонах:

.section { padding: 2rem 1rem; }

@media (min-width: 64rem) {
  .section { padding: 6rem 2rem; }
}

Телефон в альбомной ориентации с маленькой высотой:

@media (orientation: landscape) and (max-height: 30rem) {
  .site-header { position: static; }
}

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

Какие ширины выбирать — отдельный вопрос, он разобран в статье о брейкпоинтах для адаптивной вёрстки.

Медиафункции помимо ширины

Функция Пример Для чего
orientation (orientation: landscape) Изменить раскладку при повороте телефона или планшета
hover (hover: hover) Эффекты наведения только на устройствах, где наведение возможно
pointer (pointer: coarse) Крупные зоны нажатия на сенсорных экранах
prefers-color-scheme (prefers-color-scheme: dark) Тёмная тема
prefers-reduced-motion (prefers-reduced-motion: reduce) Отключение анимаций
resolution (min-resolution: 2dppx) Картинки высокой плотности в CSS-фонах
display-mode (display-mode: standalone) Стили для установленного веб-приложения

Функции hover и pointer важнее, чем кажется. У сенсорного ноутбука или планшета с десктопной раскладкой всё равно нет наведения, поэтому меню, которые открываются только по hover, оборачивайте в @media (hover: hover).

Задавайте брейкпоинты в rem или em

Медиазапросы в rem или em учитывают размер шрифта, заданный пользователем в браузере. Если человек увеличит базовый размер текста с 16 px до 24 px, брейкпоинт 48rem сдвинется с 768 px на 1152 px, и при крупном тексте страница переключится на более просторную раскладку. Брейкпоинты в пикселях эту настройку игнорируют. Внутри медиазапросов и rem, и em отсчитываются от исходного размера шрифта браузера, а не от размера шрифта html, который вы задали в CSS.

Медиазапросы и container queries

Медиазапросы реагируют на viewport. Container queries реагируют на размер контейнера элемента:

.card-wrap { container-type: inline-size; }

@container (min-width: 30rem) {
  .card { display: flex; }
}

Используйте медиазапросы для раскладки всей страницы (колонки, навигация), а container queries — для компонентов, которые встречаются в местах разной ширины.

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

  1. Нет метатега viewport. Без него телефоны сообщают ширину viewport около 980 px, и мобильные медиазапросы никогда не срабатывают. Подробнее: метатег viewport.
  2. Пересекающиеся диапазоны, например max-width: 768px и min-width: 768px, которые оба срабатывают ровно на 768 px.
  3. Медиазапрос стоит раньше базового правила. При одинаковой специфичности побеждает более позднее правило, поэтому запрос должен идти после того правила, которое он переопределяет.
  4. Проверка только изменением размера окна. Десктопные браузеры не сужаются до ширины большинства телефонов. Используйте режим устройства или Mobile View Extension, которое задаёт настоящий viewport и user agent, и прочитайте, как проверить адаптивность сайта.

Частые вопросы

Какой медиазапрос нужен для мобильных телефонов?

Единого запроса для телефонов нет. В CSS по принципу mobile first телефоны — это вариант по умолчанию без всякого запроса, а для больших экранов добавляется @media (min-width: 40rem) или похожий. Чтобы нацелиться только на маленькие экраны, используйте @media (max-width: 39.99rem) или (width < 40rem).

В чём задавать медиазапросы: px, em или rem?

rem или em лучше для доступности: тогда брейкпоинты масштабируются вместе с размером шрифта пользователя. px тоже работает, но эту настройку игнорирует.

Где размещать медиазапросы в CSS?

Либо рядом с компонентом, который они меняют, либо группой в конце файла. Рядом с компонентом поддерживать проще, но запрос всё равно должен идти после базовых правил.

Откройте следующий сайт в мобильном виде.

Установите расширение и запускайте превью устройств прямо в той вкладке, где уже работаете.