Медиа-запрос в CSS — это правило @media, которое включает стили только при выполнении условия: ширина окна больше 768 пикселей, экран повёрнут горизонтально, в системе включена тёмная тема. Чтобы сайт перестраивался под телефон, добавьте в <head> метатег viewport, напишите базовые стили для узкого экрана и допишите блоки @media (min-width: 768px) { … } для широких.
Ниже разберём синтаксис, соберём адаптивную сетку карточек по шагам и покажем ошибки, из-за которых медиа-запрос не срабатывает. Если вы только начинаете, сначала загляните в разбор того, что такое CSS и как его подключать, и в обзор того, какие бывают виды вёрстки.
Как устроен медиа-запрос

Запись состоит из трёх частей: директива @media, условие и блок стилей. Стили внутри блока работают поверх обычных, пока условие истинно.
@media screen and (min-width: 768px) {
.cards {
grid-template-columns: repeat(2, 1fr);
}
}
- Тип устройства:
screen(экран),print(печать) илиall. Его можно не писать: по умолчанию подставляетсяall. - Медиафункция в круглых скобках. Это характеристика, которую проверяет браузер:
min-width,orientation,prefers-color-scheme. - Логические операторы склеивают условия в одно выражение.
Операторов четыре, и путают их чаще всего запятую с and:
| Оператор | Что делает | Пример |
|---|---|---|
and |
все условия должны выполниться | (min-width: 768px) and (orientation: landscape) |
| запятая | хватит любого условия из списка | (orientation: portrait), (min-width: 1024px) |
not |
переворачивает весь запрос | not print |
only |
прячет запрос от очень старых браузеров, на современные не влияет | only screen and (min-width: 768px) |
Современные браузеры понимают и запись диапазоном из спецификации Media Queries Level 4. Она короче и не оставляет дыр на границе:
/* старая запись */
@media (min-width: 768px) and (max-width: 1199.98px) { … }
/* новая запись */
@media (768px <= width < 1200px) { … }
По данным справочника MDN, диапазоны поддерживают Chrome с версии 104, Firefox с 102 и Safari с 16.4. Если проект должен открываться на старых iPhone, оставьте пары min-width и max-width.
Пошаговая инструкция: адаптивная сетка карточек
Соберём типичный блок: на телефоне карточки идут в одну колонку, на планшете в две, на широком мониторе в три. Код ниже мы проверили в Chrome 154 на ширине 375, 767, 768, 1199 и 1200 пикселей.
- Добавьте метатег viewport в
<head>. Без него телефон рисует страницу шириной около 980 пикселей и уменьшает её, и запросы под мобильные не сработают:<meta name="viewport" content="width=device-width, initial-scale=1"> - Напишите базовые стили для самого узкого экрана. Это одна колонка без всяких условий:
.cards { display: grid; grid-template-columns: 1fr; gap: 16px; } - Добавьте запрос для планшета. С 768 пикселей карточки встают по две:
@media (min-width: 768px) { .cards { grid-template-columns: repeat(2, 1fr); } } - Добавьте запрос для десктопа ниже предыдущего. Порядок важен: при одинаковой специфичности побеждает правило, которое стоит в файле позже:
@media (min-width: 1200px) { .cards { grid-template-columns: repeat(3, 1fr); } } - Проверьте результат. В Chrome откройте инструменты разработчика (F12 в Windows, Cmd+Option+I в macOS) и включите режим устройств: Ctrl+Shift+M или Cmd+Shift+M. Тяните край окна и следите, на какой ширине меняется сетка.
Так выглядит та же страница на трёх ширинах. В правом верхнем углу плашка показывает ширину окна и число колонок, которое насчитал браузер.

На 820 пикселях сработал первый запрос: сетка стала двухколоночной, а вместо значка меню появились ссылки. Меню переключается тем же блоком @media (min-width: 768px), в нём просто больше правил.

С 1200 пикселей включается второй запрос, и карточки встают по три. Ширину колонок под каждый экран обычно берут из макета: как его подготовить, рассказываем в статье о том, как сделать макет сайта самому.

Mobile first или desktop first и какие брейкпоинты брать

Направление определяет, какие условия вы пишете. При mobile first базовые стили рассчитаны на телефон, а запросы с min-width добавляют правила для экранов шире. При desktop first наоборот: за основу берут десктоп и урезают его запросами с max-width.
| Mobile first | Desktop first | |
|---|---|---|
| Условия | min-width, по возрастанию |
max-width, по убыванию |
| Что получает телефон | только базовые стили, без переопределений | десктопные стили плюс правки поверх них |
| Когда удобно | новый проект, большая доля мобильного трафика | адаптация готового десктопного сайта |
Для новых проектов чаще выбирают mobile first: кода на телефоне меньше, а усложнять макет проще, чем упрощать. Тот же подход заложен в Bootstrap и Tailwind: их классы вида col-md-6 и md:flex срабатывают от указанной ширины и выше.
Макеты под телефон и десктоп обычно рисует веб-дизайнер, а верстальщик решает, на какой ширине один вариант сменяет другой.
Брейкпоинты, то есть ширины переключения, у популярных фреймворков такие:
| Фреймворк | Брейкпоинты, px | Источник |
|---|---|---|
| Bootstrap 5.3 | 576, 768, 992, 1200, 1400 | документация Bootstrap |
| Tailwind CSS 4 | 640, 768, 1024, 1280, 1536 (в rem: 40, 48, 64, 80, 96) | документация Tailwind |
Обе сетки сходятся на 768 пикселях, поэтому эта граница почти всегда отделяет телефон от планшета. Остальные лучше ставить по контенту: сузьте окно и найдите ширину, на которой строка меню перестала помещаться или таблица вылезла за край. О том, как вести себя с широкими таблицами, есть отдельный раздел в инструкции про таблицы в HTML.
Медиафункции, которые пригодятся кроме ширины
Ширина окна закрывает большую часть задач, но браузер умеет проверять и другие вещи. Полный список ведёт руководство MDN по медиавыражениям, а в работе обычно хватает этих:
| Медиафункция | Что проверяет | Зачем |
|---|---|---|
orientation: landscape |
окно шире, чем выше | галерея и видео на повёрнутом телефоне |
hover: hover и pointer: fine |
есть мышь или тачпад | эффекты при наведении только там, где их можно увидеть |
prefers-color-scheme: dark |
в системе включена тёмная тема | тёмная версия сайта без переключателя |
prefers-reduced-motion: reduce |
пользователь просил меньше анимации | отключить параллакс и автопрокрутку |
min-resolution: 2dppx |
плотный экран, как у Retina | подставить фон в двойном разрешении |
print (тип устройства) |
страницу печатают | спрятать меню и рекламу при печати |
На телефоне с сенсорным экраном условие (hover: hover) and (pointer: fine) не выполняется, мы проверили это в эмуляции Chrome. Поэтому выпадающее меню, которое открывается только при наведении, на таком устройстве нужно дублировать открытием по нажатию.
Тёмная тема и уменьшение анимации пишутся так же, как запрос по ширине:
@media (prefers-color-scheme: dark) {
body { background: #16141f; color: #ece9f6; }
}
@media (prefers-reduced-motion: reduce) {
* { animation: none; transition: none; }
}
Стили для печати
Запрос print выручает, когда статью или прайс распечатывают. Меню, кнопки и баннеры на бумаге не нужны, а у гиперссылок полезно напечатать адрес прямо в тексте:
@media print {
header, nav, .banner { display: none; }
a[href^="http"]::after { content: " (" attr(href) ")"; }
}
Проверить печатную версию без принтера можно в DevTools: меню из трёх точек → More tools → Rendering → Emulate CSS media type → print.
Медиа-запросы в HTML и JavaScript
Условие можно поставить и вне CSS-файла. Атрибут media есть у <link>: такой файл стилей применится только на подходящем экране. Браузер всё равно скачает его, просто с низким приоритетом.
<link rel="stylesheet" href="print.css" media="print">
<link rel="stylesheet" href="wide.css" media="(min-width: 1200px)">
У элемента <picture> атрибут media выбирает картинку. На телефоне загрузится узкий кадр, на десктопе широкий:
<picture>
<source media="(min-width: 768px)" srcset="hero-wide.jpg">
<img src="hero-narrow.jpg" alt="Главный экран">
</picture>
В JavaScript то же условие проверяет метод matchMedia. Он возвращает объект со свойством matches и сообщает о смене состояния событием change. Это полезно, когда меню собирается скриптом и при повороте телефона его надо пересобрать. Как скрипт находит и меняет элементы страницы, мы разбирали в статье про DOM-дерево в JavaScript.
const tablet = window.matchMedia('(min-width: 768px)');
function render(e) {
console.log(e.matches ? 'две колонки' : 'одна колонка');
}
render(tablet);
tablet.addEventListener('change', render);
Мы проверили этот код в Chrome: при ширине 375 пикселей в консоли «одна колонка», после растягивания окна до 900 пикселей событие сработало и вывело «две колонки», после сужения до 500 снова «одна колонка».
Когда @media не нужен
Две современные техники закрывают часть задач без медиа-запросов.
- Контейнерные запросы
@containerпроверяют ширину родительского блока. Карточка в узкой боковой колонке и та же карточка в широкой ленте получают разную раскладку из одного CSS. По руководству MDN (страница на английском), они работают в Chrome с 105, Safari с 16 и Firefox с 110. - Функция
clamp()плавно меняет размер шрифта вместе с шириной экрана, без ступенек на брейкпоинтах.
.wrap { container-type: inline-size; }
@container (min-width: 400px) {
.card { display: flex; }
}
h1 { font-size: clamp(1rem, 0.75rem + 1.2vw, 1.5rem); }
В нашей проверке заголовок с таким clamp() занимал 16,5 пикселя на ширине 375, 21,2 на 767 и упирался в потолок 24 пикселя с 1000 пикселей. Карточка внутри контейнера шириной 300 пикселей осталась блоком, в контейнере на 500 пикселей стала flex-строкой при одинаковом окне.
Частые ошибки и что с ними делать

Почти всё, на чём ломаются медиа-запросы, мы воспроизвели в Chrome. Пять случаев встречаются чаще прочих.
- На телефоне ничего не меняется. Причина почти всегда в отсутствии метатега viewport. Без него окно эмулированного телефона шириной 375 пикселей сообщило странице 981, и сработал планшетный запрос. Решение: строка из первого шага инструкции.
- На ширине ровно 768 пикселей вёрстка ведёт себя странно. Запросы
(max-width: 768px)и(min-width: 768px)выполняются одновременно, и побеждает тот, что ниже в файле. Решение:max-width: 767.98pxили запись диапазономwidth < 768px. - Запрос не работает вообще. Проверьте пробел между
andи скобкой. Записьscreen and(min-width: 768px)браузер считает ошибкой и выбрасывает весь блок. - Правило внутри запроса не применяется, хотя условие верное. Медиа-запрос не прибавляет специфичности. Селектор
.menu .linkвне запроса перебьёт.linkвнутри него. Решение: тот же селектор в обоих местах. - Десктопные стили затирают мобильные. При mobile first запросы с
min-widthдолжны идти по возрастанию, при desktop first запросы сmax-widthпо убыванию. Перемешанный порядок даёт результат, который зависит от того, какой блок оказался последним.
Решение для отладки: в DevTools на вкладке Elements выберите элемент и посмотрите панель Styles. Сработавшие запросы показаны над правилами, а перечёркнутые свойства подскажут, кто их перебил.
Где освоить вёрстку системно
Медиа-запросы проходят на любом курсе вёрстки вместе с Flexbox, Grid и подготовкой макета. Если хотите разобраться в адаптиве целиком, загляните в подборку курсов по навыку адаптивная вёрстка или в более широкий каталог курсов по CSS.
Чем такой специалист занимается каждый день и сколько получает, мы рассказали в статье о профессии HTML-верстальщика. Если вёрстка для вас первый шаг к JavaScript и фреймворкам, пригодится план как стать фронтенд-разработчиком.
| Курс | Школа | Стоимость со скидкой | В рассрочку | Длительность | Обзор курса от Checkroi |
|---|---|---|---|---|---|
| HTML и CSS с нуля Перейти на сайт курса | 91 626 ₽ | 7635 ₽/мес. | 11 месяцев | Обзор курса | |
| HTML и CSS. Адаптивная вёрстка и автоматизация Перейти на сайт курса | 23 400 ₽ | 3900 ₽/мес. | 2 месяца | Обзор курса | |
| Основы вёрстки HTML и CSS Перейти на сайт курса | 32 676 ₽ | 2723 ₽/мес. | 3 месяца | Обзор курса | |
| HTML и CSS с нуля | 195 160 ₽ | 7972 ₽/мес. | 12 месяцев | Обзор курса | |
| Frontend-разработчик: сайты на HTML/CSS/JavaScript Перейти на сайт курса | 9200 ₽ | - | 3 месяца | Обзор курса |
Больше программ — в полном каталоге курсов по CSS




