</> Praktum

Главная / CSS / Медиазапросы CSS

Справочник · CSS

Медиазапросы: стили под экран и устройство

Редакция PraktumОбновлено 7 мин чтенияУровень: новичок

Медиазапрос — блок @media (условие) { … }, правила внутри которого применяются только при выполнении условия: ширина окна не меньше 768px, тёмная тема в системе, страница отправлена на печать. Чаще всего медиазапросами меняют раскладку на разных ширинах экрана.

Коротко
  • @media (min-width: 768px) { … } — стили для экранов от 768px.
  • Mobile first: базовые стили для телефона, медиазапросы добавляют широкие экраны.
  • Точки перелома выбирают по содержимому, а не по моделям телефонов.
  • Новая запись: @media (width >= 768px).
  • Кроме ширины проверяют hover, prefers-color-scheme, prefers-reduced-motion, print.

Минимальный пример

.cards {
  display: grid;
  gap: 16px;
}

@media (min-width: 720px) {
  .cards { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 1100px) {
  .cards { grid-template-columns: repeat(3, 1fr); }
}

На телефоне карточки стоят в одну колонку, от 720px — в две, от 1100px — в три. Внутри медиазапроса пишут только отличия: display и gap уже заданы в базовом правиле.

Медиазапросы работают, только если в head есть тег <meta name="viewport" content="width=device-width, initial-scale=1">. Без него телефон притворяется экраном шириной около 980px, и стили для узких экранов не включатся.

Синтаксис

@media (min-width: 768px) { … }                 /* от 768px и шире */
@media (max-width: 767.98px) { … }              /* уже 768px */
@media (min-width: 768px) and (max-width: 1023px) { … } /* диапазон */
@media (width >= 768px) { … }                   /* новая запись */
@media (768px <= width < 1024px) { … }          /* диапазон новой записью */
@media screen and (orientation: landscape) { … }
@media (hover: none), (max-width: 600px) { … }  /* запятая — «или» */
@media not print { … }

and соединяет условия «и», запятая — «или», not отрицает весь запрос. Запись диапазонов с >= и < понятнее, чем пара min/max, и не требует хитростей вроде 767.98px.

Что можно проверить

Частые характеристики медиазапросов
ХарактеристикаПримерЗачем
width / min-width / max-width(min-width: 48rem)раскладка под ширину окна
orientation(orientation: landscape)альбомная или портретная ориентация
hover(hover: hover)есть ли наведение мышью
pointer(pointer: coarse)грубый указатель — палец, кнопки крупнее
prefers-color-scheme(prefers-color-scheme: dark)тёмная тема в системе
prefers-reduced-motion(prefers-reduced-motion: reduce)человек просил меньше анимации
print@media printвид при печати

Mobile first: от узкого к широкому

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

Обратный путь — сверстать монитор и потом через max-width всё отменять — приводит к длинным спискам переопределений и забытым горизонтальным прокруткам. Если проект уже написан desktop first, переписывать не обязательно, но новые компоненты удобнее делать от телефона.

Как выбрать точки перелома

Точку перелома (breakpoint) ставят там, где ломается содержимое, а не там, где «начинается планшет». Открой страницу, медленно сужай окно в режиме устройства DevTools и отметь ширину, где меню перестаёт помещаться или строка карточек становится тесной. Это и есть точка.

/* условие нельзя записать через var(), поэтому точки держат в одном месте файла */
@media (min-width: 40rem) { /* 640px */ }
@media (min-width: 64rem) { /* 1024px */ }

Двух-трёх точек на весь сайт обычно хватает. В медиазапросах удобно использовать rem или em: если человек увеличил размер шрифта в браузере, раскладка перестроится раньше, и текст не будет зажат. CSS-переменные внутри условия медиазапроса не работают.

Тёмная тема и меньше движения

:root { --bg: #fff; --text: #171923; }

@media (prefers-color-scheme: dark) {
  :root { --bg: #14161f; --text: #e8eaf2; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

prefers-color-scheme подстраивает цвета под системную тему. prefers-reduced-motion выключает крупные анимации для тех, кому от движения становится плохо. Это настройки самого человека, и уважать их — часть доступности.

Наведение и сенсорные экраны

@media (hover: hover) {
  .card:hover { transform: translateY(-2px); }
}

@media (pointer: coarse) {
  .menu a { padding-block: 12px; } /* крупнее под палец */
}

На сенсорных экранах наведения нет, а эмуляция hover после касания выглядит как залипание. (hover: hover) включает эффекты наведения только там, где есть мышь. Важные действия всё равно не прячь за hover.

Стили для печати

@media print {
  header nav, .sidebar, .button { display: none; }
  body { color: #000; background: #fff; }
  a[href^="http"]::after { content: " (" attr(href) ")"; }
}

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

Медиазапрос или контейнерный запрос

Медиазапрос смотрит на ширину окна. Но карточка может стоять и в широкой основной колонке, и в узкой боковой — при одной ширине окна. Контейнерные запросы @container проверяют ширину родителя, а не окна, и делают компонент самостоятельным. Они поддерживаются современными браузерами; для раскладки страницы целиком по-прежнему используют медиазапросы.

.sidebar, .main { container-type: inline-size; }
@container (min-width: 400px) {
  .card { display: flex; gap: 16px; }
}

min-width или max-width

min-width

Mobile first: базовые стили для телефона, условие добавляет возможности широким экранам.

max-width

Desktop first: базовые стили для монитора, условие отменяет и упрощает для узких. Больше переопределений.

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

  • Забывают meta viewport, и на телефоне медиазапросы не срабатывают.
  • Делают отдельную точку под каждую модель телефона.
  • Копируют весь блок правил в медиазапрос вместо одних отличий.
  • Пишут медиазапрос выше базового правила, и базовое его перебивает.
  • Пытаются использовать var() в условии медиазапроса — это не работает.

Доступность

Проверяй страницу при увеличении шрифта до 200%: точки перелома в rem перестраивают раскладку и для этого случая. Уважай prefers-reduced-motion и не делай важные элементы доступными только на широких экранах — содержание на телефоне должно быть тем же, меняется только раскладка.

Поддержка браузерами

Медиазапросы по ширине, hover, pointer, prefers-color-scheme и prefers-reduced-motion поддерживаются всеми актуальными браузерами. Запись диапазонов (width >= 768px) работает в браузерах с 2023 года, а контейнерные запросы — тоже в свежих версиях; для старых оставляй min-width.

Практика

Сделай сетку карточек: одна колонка на телефоне, две от 40rem, три от 64rem (mobile first). Добавь подъём карточки при наведении только для устройств с мышью и отключи анимации для тех, кто попросил меньше движения. При печати скрой меню.

Показать решение
.cards { display: grid; gap: 16px; }
@media (min-width: 40rem) { .cards { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 64rem) { .cards { grid-template-columns: repeat(3, 1fr); } }

.card { transition: transform .2s; }
@media (hover: hover) { .card:hover { transform: translateY(-3px); } }
@media (prefers-reduced-motion: reduce) { .card { transition: none; } }

@media print { .menu { display: none; } }

Открыть песочницу

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

Почему медиазапросы не работают на телефоне?

Скорее всего, в head нет meta viewport. Без него мобильный браузер считает ширину страницы около 980px.

Какие брать breakpoints?

Те, где ломается твоя вёрстка. Сужай окно и ставь точку там, где содержимому становится тесно. Двух-трёх точек обычно достаточно.

Что лучше: min-width или max-width?

Для новых проектов удобнее min-width (mobile first): базовые стили простые, а сложность добавляется для широких экранов.

Можно ли использовать CSS-переменные в медиазапросе?

Внутри блока — да, в самом условии — нет: @media (min-width: var(--md)) не сработает.

Чем медиазапрос отличается от контейнерного запроса?

Медиазапрос смотрит на окно, контейнерный (@container) — на ширину родительского элемента. Второй удобен для компонентов, которые стоят в колонках разной ширины.

Источники

Практикум по теме

Ещё в разделе CSS