
📱 JavaScript: как определить ширину экрана — аналог @media запросов в коде
Бывает, вёрстка уже готова, CSS-медиазапросы расставлены, а поведение на конкретном брейкпойнте нужно отловить именно в JavaScript. Показать попап только на мобильных, перестроить сетку при ресайзе, запустить анимацию когда экран «узкий», всё это требует от скрипта понимания текущей ширины окна.
Проблема в том, что разработчики часто идут сложным путём: парсят window.innerWidth, вешают throttle на resize, сравнивают с магическими числами, и получают хрупкий код, который живёт отдельно от CSS-брейкпойнтов. А ведь в браузере давно есть метод, работающий с теми же медиавыражениями, что и CSS.
Ниже, три практических подхода: от современного matchMedia (работает как @media в CSS) до jQuery-варианта для legacy-проектов. С живыми примерами, которые можно скопировать и запустить прямо сейчас.
💡 Быстрый обзор:
matchMedia, нативный метод, принимающий CSS-медиавыражение и сообщающий, выполняется ли оно прямо сейчас; идеален для синхронизации JS-логики с CSS-брейкпойнтамиresize+matchMedia, связка, реагирующая на изменение окна браузера; скрипт узнаёт о пересечении брейкпойнта мгновенно, без периодического опросаinnerWidth- jQuery-вариант, для проектов, где jQuery уже на странице; тот же
resize, но без нативногоmatchMedia, сравнение идёт через$(window).width()
matchMedia, единый источник правды для ширины экрана
Главный недостаток window.innerWidth, он ничего не знает о ваших CSS-брейкпойнтах. Вы ставите в медиазапросах 768px, а в JS пишете if (window.innerWidth < 768), и однажды округление или полоса прокрутки ломают синхронизацию.
window.matchMedia() решает эту проблему радикально: он принимает ту же строку медиавыражения, что и CSS-правило @media. Результат, объект MediaQueryList со свойством .matches (true / false). Никаких магических чисел, никакого расхождения с вёрсткой.
Базовый синтаксис:
1 const mq = window.matchMedia("(min-width: 768px)"); 2 3 if (mq.matches) { 4 console.log("Планшет или шире — 768px+"); 5 } else { 6 console.log("Мобильное разрешение — меньше 768px"); 7 }
Тот же вызов matchMedia("(min-width: 768px)") браузер выполняет по тем же правилам, что и @media (min-width: 768px) в CSS. Если в CSS для этого брейкпойнта спрятан сайдбар, JS «видит» то же самое и может, например, скрыть мобильное меню.
Кроме .matches, объект MediaQueryList даёт свойство .media (строка исходного запроса) и метод addEventListener для подписки на изменения. Это значит, что один раз объявив брейкпойнт в конфиге, вы можете использовать его одновременно и в CSS, и в JS без дублирования магических чисел, достаточно вынести 768 в константу и подставлять в оба места.
Реакция на ресайз без throttle и костылей
Проверка «сейчас», это полдела. Настоящая магия начинается, когда скрипт узнаёт о пересечении брейкпойнта в момент изменения окна.
У MediaQueryList есть событие change, оно срабатывает ровно когда значение .matches переключается. Не на каждый пиксель ресайза, а только при переходе через границу:
1 const mq = window.matchMedia("(min-width: 500px)"); 2 3 mq.addEventListener("change", function (e) { 4 if (e.matches) { 5 console.log("Экран расширился до 500px или больше"); 6 } else { 7 console.log("Экран сузился меньше 500px"); 8 } 9 });
Для обратной совместимости со старыми браузерами то же самое можно сделать через общий обработчик resize на window:
1 window.addEventListener("resize", function () { 2 if (window.matchMedia("(min-width: 500px)").matches) { 3 console.log("Ширина экрана — минимум 500px"); 4 } else { 5 console.log("Меньше 500px"); 6 } 7 });

Разница простая: change на MediaQueryList, событийно-чистый подход (нет лишних вызовов при ресайзе внутри диапазона), а resize на window, fallback, понятный любому разработчику.
Диапазон ширины: между двумя брейкпойнтами
Частая задача, «от 769px до 1024px». matchMedia и здесь работает как CSS: комбинируйте min-width и max-width в одном выражении:
1 window.addEventListener("resize", function () { 2 if ( 3 window.matchMedia("(min-width: 769px)").matches && 4 window.matchMedia("(max-width: 1024px)").matches 5 ) { 6 console.log("Планшетный диапазон: 769px – 1024px"); 7 } else { 8 console.log("За пределами планшетного диапазона"); 9 } 10 });
Либо одним выражением (браузеры понимают составные медиазапросы так же, как в CSS):
1 const tablet = window.matchMedia("(min-width: 769px) and (max-width: 1024px)"); 2 3 tablet.addEventListener("change", function (e) { 4 console.log(e.matches ? "Вошли в планшетный диапазон" : "Вышли из планшетного диапазона"); 5 });
Какой вариант выбрать? change на MediaQueryList, когда нужно поймать именно момент пересечения границы (например, перестроить DOM-дерево). resize + matchMedia, когда логика проще и нужно просто «проверить сейчас» без подписки на будущие переходы.
jQuery-вариант: когда matchMedia недоступен
Если проект на jQuery и полифилы не вариант, тот же результат достигается сравнением $(window).width() с пороговым значением:
1 jQuery(document).ready(function ($) { 2 if ($(window).width() > 1000) { 3 console.log("Ширина экрана больше 1000px"); 4 } else { 5 console.log("Ширина экрана 1000px или меньше"); 6 } 7 });
Этот код выполняется однократно при загрузке страницы. Для отслеживания ресайза оберните проверку в обработчик:
1 jQuery(document).ready(function ($) { 2 function checkWidth() { 3 if ($(window).width() > 1000) { 4 console.log("Ширина > 1000px"); 5 } else { 6 console.log("Ширина ≤ 1000px"); 7 } 8 } 9 10 checkWidth(); // первый запуск 11 $(window).on("resize", checkWidth); 12 });
Но помните: $(window).width() и matchMedia могут разойтись на несколько пикселей из-за полосы прокрутки. matchMedia работает с областью просмотра (viewport), так же, как CSS-правила. Поэтому для всего нового кода я рекомендую именно нативный метод.
matchMedia против innerWidth, коротко
Критерий |
|
|
|---|---|---|
Синхронизация с CSS | Полная (те же выражения) | Ручная подгонка чисел |
Событие при пересечении брейкпойнта |
| Только |
Учёт полосы прокрутки | Как в CSS (viewport) | Зависит от браузера |
Обнаружение тёмной темы / | Да (любое медиавыражение) | Нет |
⁉️🤔 Частые вопросы
Что лучше: matchMedia или window.innerWidth?
matchMediaлучше всегда, когда логика привязана к CSS-брейкпойнтам. Он использует те же правила, что и@media, исключено расхождение на пиксель-другой из-за полосы прокрутки или масштабирования.innerWidthуместен только если нужно точное числовое значение (например, для расчёта количества помещающихся элементов), а не факт «экран шире N пикселей».
Работает ли matchMedia в старых браузерах?
Да, поддержка широкая: все современные браузеры, включая мобильные, и Internet Explorer 10+. IE9 и ниже остались за бортом, для них придётся использовать
window.innerWidthили jQuery-вариант из статьи. На практике доля IE9 в 2026 году стремится к нулю.
Можно ли через matchMedia проверять не только ширину?
Да, метод принимает любое валидное CSS-медиавыражение. Например:
(orientation: portrait), определение ориентации устройства;(prefers-color-scheme: dark), тёмная тема в ОС;(prefers-reduced-motion: reduce), запрос на отключение анимаций. Работает так же, как в CSS:window.matchMedia("(prefers-color-scheme: dark)").matchesвернётtrue, если у пользователя включена тёмная тема.
Нужно ли удалять обработчик change при уходе со страницы?
В современном коде, нет. Браузер сам очищает память при выгрузке страницы. В SPA (React, Vue), где компонент монтируется и размонтируется без перезагрузки страницы, обязательно сохраните ссылку на обработчик и удалите через
removeEventListenerвcomponentWillUnmount/onUnmounted, иначе получите утечку памяти и повторные срабатывания на «мёртвых» компонентах.
Почему $(window).width() и matchMedia иногда показывают разную ширину?
Потому что они измеряют разное.
matchMediaработает с шириной viewport (область просмотра CSS), той самой, которую используют медиазапросы.$(window).width()/window.innerWidthвключают ширину вертикальной полосы прокрутки, если она есть. Разница обычно 15-17 px, как раз ширина скроллбара. Отсюда правило: привязываете логику к CSS-брейкпойнтам, используйтеmatchMedia; нужна «честная» ширина окна в пикселях,innerWidth.
Так что использовать: итоговый расклад
Для нового кода ответ однозначен, window.matchMedia(). Он живёт в одном контракте с вашим CSS, не требует ручной подгонки чисел под каждый брейкпойнт и даёт событийную модель «переключилось, узнал» вместо постоянного опроса ширины.
Типичный сценарий, где разница ощутима сразу: вы верстаете карточку товара, которая на десктопе показывает галерею из четырёх изображений, а на мобильном, свайпаемое одно. В CSS у вас @media (max-width: 768px), меняющее раскладку. В JS вместо if (window.innerWidth <= 768) вы пишете matchMedia("(max-width: 768px)"), и браузер гарантирует, что JS-условие сработает ровно тогда же, когда сменилась вёрстка. Никаких «почти попало», никаких багов на 767px из-за скроллбара.
jQuery-подход с $(window).width() оставьте для поддержки старых проектов, он работает, но заставляет дублировать брейкпойнты в коде и молча расходится с CSS на ширину скроллбара.
А если хотите увидеть всё вышеописанное вживую, вот 10-минутный туториал, где matchMedia разбирается от вызова до событийной модели:
Попробуйте заменить ближайший if (innerWidth < 768) на matchMedia("(min-width: 768px)"), и вы сразу почувствуете, насколько чище становится код.



