Media Queries Level 4: эволюция синтаксиса, которую сложно игнорировать — и сложно внедрить без оглядки.
Адаптивная вёрстка — основа современного фронтенда. Долгое время в CSS было всего два способа задать условия ширины: min-width
и max-width
. Они отлично справлялись со своей задачей, но имели свои особенности.
С выходом спецификации Media Queries Level 4 в CSS появился новый, более интуитивный синтаксис для написания диапазонов, приближённый к привычной математике:
@media (width < 900px) { ... }
@media (600px <= width <= 900px) { ... }
Теперь мы можем использовать логические операторы <
, >
, <=
, >=
прямо внутри @media
, без привычного префикса min-
и max-
.
Это не просто синтаксический сахар — новый подход решает ряд тонких проблем классического метода и улучшает читаемость, точность и поддержку адаптивных сценариев.
Что ещё можно сравнивать, кроме width?
Компактная форма записи @media (… > …)
работает не только с width. Есть и другие измеримые характеристики, которые можно сравнивать напрямую:
конечно,
height
— высота области просмотра (viewport);aspect-ratio
— пропорции вьюпорта (ширина / высота);resolution
— плотность пикселей (dpi
,dppx
,dpcm
);color
— глубина цветовой палитры (количество бит на цвет на устройстве вывода);color-index
— число доступных цветов в палитре, которое может отображаться устройством;monochrome
— глубина монохромного дисплея (в битах).
@media (height >= 600px) { ... }
@media (aspect-ratio < 4/3) { ... }
@media (resolution >= 2dppx) { ... }
@media (color >= 8) { ... }
@media (color-index < 256) { ... }
@media (monochrome > 0) { ... }
Логические (hover
, pointer
, prefers-reduced-motion
, orientation
и т.п.) и перечисляемые (display-mode
, update
) фичи не являются числовыми — с ними можно использовать только точное сравнение @media (feature: value)
.
Посмотрим, как этот синтаксис меняет практику написания CSS-медиазапросов, какие технические преимущества он даёт, и стоит ли его внедрять в текущие проекты с учётом реальной поддержки браузерами и инструментами сборки.
Преимущества нового синтаксиса
Избежание «щелей» между брейкпоинтами
@media (max-width: 320px) { /* <= 320px */ } @media (min-width: 321px) { /* >= 321px */ }
Выглядит аккуратно: «до 320» и «после 321». Всё вроде бы логично… пока не всплывает экзистенциальный пиксель — 320.5px.
Он не попадает ни туда, ни сюда.
max-width: 320px
его игнорирует, потому что он слишком широк.min-width: 321px
— потому что недостаточно широк.Итог: стилей нет, интерфейс потёк, разработчик грустит.
Это классическая логическая дыра между брейкпоинтами, которую легко упустить:
на дисплеях с высокой плотностью пикселей;
при масштабировании (зум) в браузере;
при расчётах с
em
,rem
илиvw
.
Один из трюков — слегка повысить точность медиазапроса. Например, установив
320.01px
, мы снижаем риск, что ширина окна застрянет «между двух огней».
Но не всё так просто: на некоторых девайсах появляются проблемы с округлением, код становится сложнее читать и поддерживать, да и браузер может тратить на это лишние ресурсы.Новый синтаксис решает проблему элегантно:
@media (width <= 320px) { ... } @media (width > 320px) { ... }
Теперь каждый пиксель — даже самый пограничный дробный — найдёт себе медиазапрос по душе.
Чёткая и понятная логика диапазонов
В класическом способе мы писали два условия:
@media (min-width: 600px) and (max-width: 900px) { ... }
Теперь — одна компактная строка:
@media (600px <= width <= 900px) { ... }
/* Сложные медиазапросы с несколькими условиями (width + height) */ @media (min-width: 600px) and (max-width: 900px) and (min-height: 400px) and (max-height: 700px) { /* стили */ } /* В новом синтаксисе: */ @media (600px <= width <= 900px) and (400px <= height <= 700px) { /* стили */ }
Видно всю логику диапазонов в одном месте, исключая рассинхронизацию границ. Компактность записи снижает ошибки и ускоряет понимание кода. Легче совмещать условия (например, ширина + высота) с понятной логикой.
Улучшенная читаемость и поддерживаемость
Математический стиль условий ближе к привычной логике, поэтому медиа-запросы становятся понятнее и проще в поддержке.
Такой стиль интуитивно читается даже вне контекста. Больше не нужно вспоминать, что
min-width
— это нижняя граница («от»), аmax-width
— верхняя («до»).
Ограничения и подводные камни
Низкая узнаваемость и непривычность
Не все разработчики знакомы с современным форматом медиазапросов. Он может сбивать с толку при чтении кода, особенно джунов и тех, кто не следит за нововведениями.
Если проект командный — лучше заранее договориться о правилах использования (и добавить правило в Stylelint). Иначе придётся поддерживать смешение старого и нового стиля, что только усложнит восприятие и сопровождение CSS.
Ограниченная поддержка браузерами
Браузеры последних лет справляются с компактными медиадиапазонами без проблем. А вот старички вроде IE или древние Android‑оболочки теряются и делают вид, что ничего не было — даже
@supports
их не переубеждает.Новый синтаксис просто проигнорируется.
Firefox начал экспериментировать с поддержкой ещё в 2018 году (версия 63), но стабильная реализация появилась примерно в версии 117 (сентябрь 2023). Chrome и Edge — с версии 104 (январь 2023), Safari включил поддержку только в версии 16.4 (март 2023).
Если вам важна поддержка специфичных или старых версий, или вы просто сомневаетесь — всегда можно проверить актуальную статистику на сайте Can I Use.
Могут глючить линтеры и форматтеры
Не все инструменты сборки и проверки кода поддерживают логические сравнения вида
<min> <= <feature> <= <max>
.Stylelint старых версий (< 14.16.0) не понимает логические диапазоны и такие медиазапросы будут распознаваться как неизвестные.
Prettier может отформатировать такие выражения некорректно — особенно при длинных строках, что приводит к неожиданной разбивке или потере читаемости.
CSS-парсеры в IDE (например, расширения для VS Code) иногда подсвечивают такие медиазапросы как ошибку, хотя они валидны.
Sass и Less на данный момент (июль 2025) официальные компиляторы Dart Sass и Less не интерпретируют новый синтаксис, но могут его пропустить как «сырой CSS», если внутри нет логики препроцессора.
Это означает, что локально такой код может скомпилироваться, но при более сложных выражениях (например, с переменными) — ошибки всё ещё возможны.
Как обеспечить обратную совместимость
Дублировать медиазапросы
Да, выглядит громоздко, зато работает надёжно.
Сначала пишем классический синтаксис, который понимают все браузеры, потом — новый, более точный. Современные браузеры применят последний валидный блок, а старые просто проигнорируют его и воспользуются первым.
/* Старый синтаксис — поддерживается всеми */ @media (max-width: 599px) { /* правила для ширины меньше 600px */ } /* Новый синтаксис — для современных браузеров */ @media (width < 600px) { /* те же правила или более точные */ }
Не всегда можно полностью положиться на магию сборщика, поэтому в реальной жизни чаще всего используют комбинацию:
Дублируют критичные медиазапросы вручную там, где надо гарантировать поддержку.
В остальном — доверяют PostCSS, чтобы сократить копипаст и облегчить поддержку кода.
Использовать PostCSS
Сам по себе PostCSS не добавит поддержку в старые браузеры, но с правильными плагинами ситуация сильно улучшается:
postcss-preset-env
— универсальный плагин, который позволяет использовать современные CSS-фичи, автоматически трансформируя их под старые браузеры.
Он поддерживает диапазонные медиа-запросы с<=
и>=
, но не умеет обрабатывать<
и>
./* ✔ Новый синтаксис, который обрабатывается postcss-preset-env */ @media (600px <= width <= 900px) { ... } @media (width >= 900px) { ... } @media (width <= 600px) { ... } /* Преобразуется в: */ @media (min-width: 600px) and (max-width: 900px) { ... } @media (min-width: 900px) { ... } @media (max-width: 600px) { ... } /* ✖ Одинарные < или > — нет: */ @media (600px < width < 900px) { ... } @media (width > 900px) { ... } @media (width < 600px) { ... }
postcss-media-minmax
— плагин, который создан специально для поддержки нововведений из спецификации CSS Media Queries уровня 4.
Начиная с версии 2.1.0, он поддерживает преобразование выражений с<
и>
без=
./* ✔ Новый синтаксис с < и >, который обрабатывает postcss-media-minmax */ @media (600px < width < 900px) { ... } @media (width > 900px) { ... } @media (width < 600px) { ... } /* Преобразуется в классические медиа-запросы с учётом смещения: */ @media (min-width: 600.001px) and (max-width: 899.999px) { ... } @media (min-width: 900.001px) { ... } @media (max-width: 599.999px) { ... } /* ✔ Также поддерживает синтаксис с <= и >= */ @media (600px <= width <= 900px) { ... } @media (width >= 900px) { ... } /* Преобразует в: */ @media (min-width: 600px) and (max-width: 900px) { ... } @media (min-width: 900px) { ... }
Для строгих неравенств
<
и>
он добавляет смещение±0.001px
, чтобы избежать логических пересечений между брейкпоинтами.
Маме можно больше не волноваться за мою вёрстку.
Когда использовать какой плагин?
Только простые диапазоны (
<=
,>=
) —postcss-preset-env
.
С включенной Stage 3-фичейmedia-query-ranges
.
Сложные или комбинированные медиазапросы, которые не подходят под ожидаемый шаблон, может оставить без изменений.Полный диапазонный синтаксис (
<=
,>=
,<
,>
) —postcss-media-minmax
.
Надёжно преобразует все формы логических сравнений, включая<
и>
, которые до сих пор плохо поддерживаются браузерами.Если нужен полный охват синтаксиса Media Queries Level 4 (включая все операторы) и одновременно поддержка множества других современных CSS-фич (кастомные свойства, логические свойства,
:has()
,@nest
и т.д.) — безопаснее всего подключать оба плагина:postcss-media-minmax
+postcss-preset-env
.
Интеграция PostCSS: настройка конфига и сборки
Настройка
postcss.config.js
для плагинов:Только postcss-preset-env:
// postcss.config.js module.exports = { plugins: [ require('postcss-preset-env')({ stage: 3, features: { 'media-query-ranges': true, // включает поддержку диапазонного синтаксиса }, }), ], };
Подключает современные CSS-фичи в зависимости от заданного уровня (
stage
). Для медиазапросов важно явно включитьmedia-query-ranges
.Только postcss-media-minmax:
// postcss.config.js module.exports = { plugins: [ require('postcss-media-minmax')(), ], };
Преобразует логические диапазоны в классический формат
min
/max
, делая их совместимыми со старыми браузерами.Оба плагина вместе:
// postcss.config.js module.exports = { plugins: [ require('postcss-media-minmax')(), require('postcss-preset-env')({ stage: 3, features: { 'media-query-ranges': true, }, }), ], };
Часто используются в связке:
preset-env
включает синтаксис, аmedia-minmax
помогает с совместимостью.Vite и Parcel — автоматически подхватывают
postcss.config.js
, ничего дополнительно настраивать не нужно.Webpack
Пример настройки Webpack (с postcss-loader):
// webpack.config.js module.exports = { module: { rules: [ { test: /\.css$/i, use: [ 'style-loader', 'css-loader', { loader: 'postcss-loader', options: { postcssOptions: { plugins: [ require('postcss-preset-env')({ stage: 3, features: { 'media-query-ranges': true, }, }), require('postcss-media-minmax')(), ], }, }, }, ], }, ], }, };
Если используется Webpack, нужно подключить
postcss-loader
и явно указать, где лежитpostcss.config.js
Универсальный
postcss.config.mjs
(ESM-версия)Если твой проект использует Vite, Astro, Webpack 5+ (в ESM-режиме), Next.js (App Router), SvelteKit и прочие современные инструменты, лучше использовать
postcss.config.mjs
сimport
.Пример конфига для ESM-проектов
// postcss.config.mjs import postcssPresetEnv from 'postcss-preset-env' import postcssMediaMinmax from 'postcss-media-minmax' /** @type {import('postcss').ProcessOptions} */ export default { plugins: [ postcssMediaMinmax(), // сначала minmax, чтобы preset-env уже получил преобразованный код postcssPresetEnv({ stage: 3, // включает многие современные фичи CSS autoprefixer: { grid: true }, features: { 'media-query-ranges': true, // включает преобразование диапазонов }, }), ], }
Файл должен иметь расширение
.mjs
, и вpackage.json
должен быть указанtype: "module"
.
Итого
Новый синтаксис медиазапросов — это мощный и удобный инструмент для создания адаптивного UI.
👍 Используйте <=
, >=
, >
, <
, если:
ваш проект для современных браузеров (родившихся после 2023 года);
вы делаете внутренний инструмент, SPA или админку, где аудитория контролируемая;
важна читаемость и точность условий в медиа-запросах.
Чтобы всё работало гладко, новый синтаксис должен поддерживаться не только браузерами, но и инструментами, с которыми вы работаете — линтерами, форматтерами, IDE и сборщиками. И очень важно, чтобы в команде были понятные и общие правила.
Что с этим делать?
Задокументируйте и договоритесь, как именно вы будете писать медиазапросы;
Обновите линтеры, форматтеры и редакторы — пусть знают про новые штуки;
Настройте автоматическую проверку и форматирование, чтобы не было «сюрпризов»;
Помогите команде освоиться и не бояться нового синтаксиса.
❌ Оставайтесь на max-
/ min-
, если:
требуется максимальная кроссбраузерность (например, поддержка Firefox ESR, Safari ниже 16 версии или даже IE);
у проекта широкая и разнородная аудитория, включая любителей Android 4.4;
вы не хотите ощущать душевные страдания из-за несовместимости или дублирования стилей.
Поделитесь опытом: используете ли уже новый синтаксис?