
📱 JavaScript: jak określić szerokość ekranu — analog @media zapytań w kodzie
Zdarza się, że układ jest już gotowy, zapytania media w CSS rozpisane, a zachowanie w konkretnym punkcie granicznym trzeba przechwycić właśnie w JavaScript. Pokazać pop-up tylko na urządzeniach mobilnych, przebudować siatkę podczas zmiany rozmiaru, uruchomić animację, gdy ekran jest „wąski", wszystko to wymaga od skryptu znajomości bieżącej szerokości okna.
Problem w tym, że deweloperzy często idą trudną drogą: parsują window.innerWidth, wieszają throttle na resize, porównują z magicznymi liczbami i otrzymują kruchy kod, który żyje niezależnie od punktów granicznych CSS. Tymczasem w przeglądarce od dawna istnieje metoda, która działa z tymi samymi wyrażeniami medialnymi co CSS.
Poniżej trzy praktyczne podejścia: od nowoczesnego matchMedia (działa jak @media w CSS) po wariant jQuery dla projektów legacy. Z działającymi przykładami, które można skopiować i uruchomić od ręki.
💡 Szybki przegląd:
matchMedia, natywna metoda, która przyjmuje wyrażenie medialne CSS i informuje, czy jest ono właśnie spełnione; idealna do synchronizacji logiki JS z punktami granicznymi CSSresize+matchMedia, połączenie reagujące na zmianę rozmiaru okna przeglądarki; skrypt dowiaduje się o przekroczeniu punktu granicznego natychmiast, bez cyklicznego odpytywaniainnerWidth- wariant jQuery, dla projektów, gdzie jQuery jest już na stronie; ten sam
resize, ale bez natywnegomatchMedia, porównanie odbywa się przez$(window).width()
MatchMedia, jedyne źródło prawdy dla szerokości ekranu
Główna wada window.innerWidth, nie ma on pojęcia o Pana punktach granicznych CSS. Ustawia Pan w zapytaniach medialnych 768px, a w JS pisze if (window.innerWidth < 768) i któregoś dnia zaokrąglenie albo pasek przewijania psują synchronizację.
window.matchMedia() rozwiązuje ten problem radykalnie: przyjmuje ten sam ciąg wyrażenia medialnego co reguła CSS @media. Wynik to obiekt MediaQueryList z właściwością .matches (true / false). Żadnych magicznych liczb, żadnej rozbieżności z układem.
Podstawowa składnia:
1 const mq = window.matchMedia("(min-width: 768px)"); 2 3 if (mq.matches) { 4 console.log("Планшет или шире — 768px+"); 5 } else { 6 console.log("Мобильное разрешение — меньше 768px"); 7 }
To samo wywołanie matchMedia("(min-width: 768px)") przeglądarka wykonuje według tych samych zasad co @media (min-width: 768px) w CSS. Jeśli w CSS dla tego punktu granicznego ukryty jest sidebar, JS „widzi" to samo i może na przykład ukryć menu mobilne.
Oprócz .matches obiekt MediaQueryList udostępnia właściwość .media (ciąg pierwotnego zapytania) oraz metodę addEventListener do subskrybowania zmian. Oznacza to, że deklarując raz punkt graniczny w konfiguracji, może Pan używać go jednocześnie w CSS i JS bez duplikowania magicznych liczb, wystarczy wynieść 768 do stałej i podstawić w obu miejscach.
Reakcja na zmianę rozmiaru bez throttle i protez
Sprawdzenie „teraz" to połowa sukcesu. Prawdziwa magia zaczyna się, gdy skrypt dowiaduje się o przekroczeniu punktu granicznego w momencie zmiany okna.
MediaQueryList ma zdarzenie change, które uruchamia się dokładnie wtedy, gdy wartość .matches się przełącza. Nie przy każdym pikselu zmiany rozmiaru, a tylko podczas przejścia przez granicę:
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 });
Dla wstecznej kompatybilności ze starszymi przeglądarkami to samo można zrobić przez ogólny handler resize na 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 });

Różnica jest prosta: change na MediaQueryList to podejście czysto zdarzeniowe (brak zbędnych wywołań podczas zmiany rozmiaru wewnątrz zakresu), a resize na window to fallback zrozumiały dla każdego dewelopera.
Zakres szerokości: między dwoma punktami granicznymi
Częste zadanie: „od 769px do 1024px". matchMedia i tutaj działa jak CSS: łączy Pan min-width i max-width w jednym wyrażeniu:
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 });
Albo jednym wyrażeniem (przeglądarki rozumieją złożone zapytania medialne tak samo jak w 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 });
Który wariant wybrać? change na MediaQueryList, gdy trzeba złapać sam moment przekroczenia granicy (np. przebudować drzewo DOM). resize + matchMedia, gdy logika jest prostsza i wystarczy „sprawdzić teraz" bez subskrypcji przyszłych przejść.
Wariant jQuery: gdy matchMedia jest niedostępne
Jeśli projekt opiera się na jQuery, a polyfille nie wchodzą w grę, ten sam rezultat osiąga się przez porównanie $(window).width() z wartością progową:
1 jQuery(document).ready(function ($) { 2 if ($(window).width() > 1000) { 3 console.log("Ширина экрана больше 1000px"); 4 } else { 5 console.log("Ширина экрана 1000px или меньше"); 6 } 7 });
Ten kod wykonuje się jednorazowo podczas ładowania strony. Aby śledzić zmianę rozmiaru, należy opakować sprawdzenie w handler:
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 });
Proszę jednak pamiętać: $(window).width() i matchMedia mogą różnić się o kilka pikseli z powodu paska przewijania. matchMedia operuje na obszarze widoku (viewport), tak samo jak reguły CSS. Dlatego dla całego nowego kodu rekomenduję właśnie metodę natywną.
MatchMedia kontra innerWidth, w skrócie
Kryterium |
|
|
|---|---|---|
Synchronizacja z CSS | Pełna (te same wyrażenia) | Ręczne dopasowywanie liczb |
Zdarzenie przy przekroczeniu punktu granicznego |
| Tylko |
Uwzględnienie paska przewijania | Jak w CSS (viewport) | Zależy od przeglądarki |
Wykrywanie ciemnego motywu / | Tak (dowolne wyrażenie medialne) | Nie |
⁉️🤔 Często zadawane pytania
Co jest lepsze: matchMedia czy window.innerWidth?
matchMediajest lepsze zawsze, gdy logika jest powiązana z punktami granicznymi CSS. Używa tych samych zasad co@media, wykluczona jest rozbieżność o piksel czy dwa z powodu paska przewijania lub skalowania.innerWidthjest na miejscu tylko wtedy, gdy potrzebna jest dokładna wartość liczbowa (np. do obliczenia liczby mieszczących się elementów), a nie fakt „ekran jest szerszy niż N pikseli".
Czy matchMedia działa w starszych przeglądarkach?
Tak, wsparcie jest szerokie: wszystkie nowoczesne przeglądarki, w tym mobilne, oraz Internet Explorer 10+. IE9 i starsze pozostały z tyłu, dla nich trzeba będzie użyć
window.innerWidthlub wariantu jQuery z artykułu. W praktyce udział IE9 w 2026 roku dąży do zera.
Czy przez matchMedia można sprawdzać nie tylko szerokość?
Tak, metoda przyjmuje dowolne poprawne wyrażenie medialne CSS. Na przykład:
(orientation: portrait), określenie orientacji urządzenia;(prefers-color-scheme: dark), ciemny motyw w systemie operacyjnym;(prefers-reduced-motion: reduce), żądanie wyłączenia animacji. Działa tak samo jak w CSS:window.matchMedia("(prefers-color-scheme: dark)").matcheszwrócitrue, jeśli użytkownik ma włączony ciemny motyw.
Czy trzeba usuwać handler change przy opuszczaniu strony?
W nowoczesnym kodzie, nie. Przeglądarka sama czyści pamięć przy wyładowaniu strony. W SPA (React, Vue), gdzie komponent jest montowany i odmontowywany bez przeładowania strony, koniecznie należy zachować referencję do handlera i usunąć ją przez
removeEventListenerwcomponentWillUnmount/onUnmounted, w przeciwnym razie dojdzie do wycieku pamięci i ponownych wywołań na „martwych" komponentach.
Dlaczego $(window).width() i matchMedia czasem pokazują różną szerokość?
Ponieważ mierzą różne rzeczy.
matchMediaoperuje na szerokości viewport (obszar widoku CSS), tej samej, której używają zapytania medialne.$(window).width()/window.innerWidthuwzględniają szerokość pionowego paska przewijania, jeśli jest widoczny. Różnica to zwykle 15-17 px, czyli właśnie szerokość scrollbara. Stąd zasada: wiąże Pan logikę z punktami granicznymi CSS, proszę używaćmatchMedia; potrzebna jest „uczciwa" szerokość okna w pikselach,innerWidth.
Co zatem stosować: podsumowujący harmonogram
Dla nowego kodu odpowiedź jest jednoznaczna: window.matchMedia(). Żyje ono w jednym kontrakcie z Pana CSS, nie wymaga ręcznego dopasowywania liczb do każdego punktu granicznego i daje model zdarzeniowy „przełączyło się, dowiedziałem się" zamiast ciągłego odpytywania szerokości.
Typowy scenariusz, w którym różnica jest odczuwalna od razu: tworzy Pan kartę produktu, która na desktopie pokazuje galerię z czterech zdjęć, a na urządzeniu mobilnym, jedno, które można przewijać. W CSS ma Pan @media (max-width: 768px), które zmienia układ. W JS zamiast if (window.innerWidth <= 768) pisze Pan matchMedia("(max-width: 768px)") i przeglądarka gwarantuje, że warunek JS zadziała dokładnie wtedy, gdy zmienił się układ. Żadnego „prawie trafiło", żadnych bugów na 767px przez scrollbar.
Podejście jQuery z $(window).width() proszę zostawić do wsparcia starych projektów, działa, ale zmusza do duplikowania punktów granicznych w kodzie i po cichu rozmija się z CSS o szerokość scrollbara.
A jeśli chce Pan zobaczyć wszystko opisane powyżej na żywo, oto 10-minutowy tutorial, w którym matchMedia jest rozkładane od wywołania po model zdarzeniowy:
Proszę spróbować zastąpić najbliższy if (innerWidth < 768) przez matchMedia("(min-width: 768px)"), a od razu odczuje Pan, o ile czystszy staje się kod.



