Media queries w CSS: responsywność, breakpointy i mobile first

Mateusz Bogolubow

24-10-2026

(aktualizacja: 24-10-2026)

Jak działają media queries, dlaczego nie działają na telefonie bez meta viewport, jak wybrać breakpointy i pisać CSS w podejściu mobile first. Z przykładami sprawdzonymi w przeglądarce.

Media queries w CSS: responsywność, breakpointy i mobile first
Media queries to reguły CSS (@media), które stosują style tylko wtedy, gdy spełniony jest warunek, np. szerokość okna przeglądarki. Najczęściej pisze się je w podejściu mobile first: style bazowe są dla telefonu, a kolejne @media (min-width: ...) rozszerzają je dla większych ekranów. W HTML-u musisz też dodać <meta name="viewport" content="width=device-width, initial-scale=1">, bo bez niego telefon udaje szeroki ekran i media queries nie działają.

Strona, która na komputerze wygląda świetnie, a na telefonie wymaga powiększania i przewijania na boki, odstraszy większość użytkowników. Rozwiązaniem jest responsywność (RWD, ang. Responsive Web Design), czyli układ, który dopasowuje się do szerokości ekranu. Najważniejszym narzędziem w CSS są do tego media queries. W tym artykule pokażę, jak je zapisać, jak wybrać breakpointy, jak pisać kod w podejściu mobile first i dlaczego czasem na telefonie w ogóle nie działają.

Czym są media queries w CSS?

Media query (zapytanie o media) to warunek zapisany w CSS za pomocą reguły @media. Style w jej środku są stosowane tylko wtedy, gdy warunek jest spełniony. Najczęściej sprawdza się szerokość okna:

.naglowek {
  font-size: 1.5rem;
}

@media (min-width: 768px) {
  .naglowek {
    font-size: 2.5rem;
  }
}

Przeglądarka zastosuje większy rozmiar tylko wtedy, gdy okno ma co najmniej 768 px szerokości. Dla węższych ekranów zostaje 1.5rem. Przeglądarka sprawdza warunek na bieżąco, więc po zmianie rozmiaru okna lub obróceniu telefonu układ zmienia się sam.

Dlaczego media queries nie działają na telefonie? Meta viewport

To najczęstszy powód, dla którego responsywny CSS „nie działa na telefonie”, choć na komputerze po zmniejszeniu okna wszystko jest w porządku. Telefon bez dodatkowej informacji zakłada, że strona jest zaprojektowana dla komputera. Renderuje ją więc na szerokim, wirtualnym ekranie, a potem pomniejsza. W takim układzie @media (max-width: 600px) nigdy się nie włączy.

Sprawdziłem to w Chromium z emulacją telefonu (ekran 390 px):

Szerokość widoczna dla CSS@media (max-width: 600px)
Bez <meta name="viewport">980 pxnie działa
Z <meta name="viewport">390 pxdziała

Rozwiązaniem jest jedna linijka w sekcji <head>:

<meta name="viewport" content="width=device-width, initial-scale=1">

Mówi ona przeglądarce, żeby szerokość układu równała się szerokości ekranu urządzenia. Dodaj ją do każdej strony, zanim zaczniesz pisać media queries. O jednostkach związanych z viewportem (np. dvh) pisaliśmy w artykule o nowych jednostkach CSS wysokości viewportu.

Jak zapisać media query? Składnia i najczęstsze warunki

Zapytanie składa się ze słowa @media, opcjonalnego typu (np. screen), warunków w nawiasach i bloku stylów. Warunki łączysz operatorem and, a alternatywy rozdzielasz przecinkiem (znaczy „lub”):

/* ekran szerszy niż 600 px I w poziomie */
@media (min-width: 600px) and (orientation: landscape) { ... }

/* węższy niż 600 px LUB wydruk */
@media (max-width: 600px), print { ... }

/* zapis zakresowy: szerokość od 400 do 800 px */
@media (400px <= width <= 800px) { ... }

Zapis zakresowy (400px <= width <= 800px) jest nowszy i czytelniejszy niż para min-width i max-width. Wypróbowałem go w Chromium 151, ale zanim użyjesz go w projekcie, sprawdź wsparcie w przeglądarkach swoich użytkowników.

Najczęściej używane warunki:

WarunekKiedy się włączaPrzykład użycia
min-width / max-widthszerokość okna od / doukład kolumn, menu
orientation: landscape / portraittelefon w poziomie / w pioniegaleria zdjęć
prefers-color-scheme: darkużytkownik ma ciemny motyw systemuciemny wygląd strony
prefers-reduced-motion: reduceużytkownik ograniczył animacjewyłączenie animacji
hover: hoverurządzenie ma wskaźnik z najechaniem (mysz)style :hover tylko dla myszy

Trzy ostatnie warunki nie dotyczą rozmiaru ekranu, ale pomagają dopasować stronę do użytkownika i są ważne dla dostępności. Wszystkie wymienione w tabeli sprawdziłem w Chromium 151.

Mobile first czy desktop first? Który zapis wybrać

Mobile first oznacza, że piszesz style bazowe dla najmniejszego ekranu, a potem rozszerzasz je dla większych za pomocą min-width. Desktop first to odwrotność: style bazowe dla dużego ekranu i max-width do ich „odejmowania”. Mobile first jest zwykle prostszy, bo telefon dostaje najmniej reguł, a kolejne breakpointy tylko coś dodają.

Przykład siatki, która ma jedną kolumnę na telefonie, dwie na tablecie i trzy na komputerze:

<!DOCTYPE html>
<html lang="pl">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Responsywna siatka</title>
  <style>
    .karty {
      display: grid;
      gap: 16px;
      grid-template-columns: 1fr;                    /* telefon: 1 kolumna */
    }

    @media (min-width: 640px) {
      .karty { grid-template-columns: repeat(2, 1fr); }  /* tablet: 2 kolumny */
    }

    @media (min-width: 1024px) {
      .karty { grid-template-columns: repeat(3, 1fr); }  /* komputer: 3 kolumny */
    }
  </style>
</head>
<body>
  <div class="karty">
    <div>Karta 1</div>
    <div>Karta 2</div>
    <div>Karta 3</div>
  </div>
</body>
</html>

Sprawdziłem w przeglądarce, ile kolumn ma siatka przy różnych szerokościach okna:

Szerokość oknaLiczba kolumn
375 px, 639 px1
640 px, 1023 px2
1024 px, 1400 px3

Zwróć uwagę, że przy mobile first kolejność zapisu ma znaczenie. Reguła w @media ma taką samą „wagę” jak zwykła, więc o wyniku decyduje, która jest później w pliku. Jeśli zapiszesz media query przed regułą bazową, ta bazowa je nadpisze:

/* źle: reguła bazowa jest niżej i wygrywa także na szerokim ekranie */
@media (min-width: 600px) {
  .x { color: blue; }
}
.x { color: red; }   /* przy szerokości 900 px tekst jest czerwony */

Stałą zasadą jest więc: najpierw style bazowe, potem kolejne @media od najmniejszego breakpointu do największego.

Jakie breakpointy wybrać?

Nie ma jednej, obowiązującej listy. Często spotykane są wartości w okolicach 480, 768, 1024 i 1280 px. Traktuj je jako punkt wyjścia, a nie regułę: urządzeń jest tyle, że żadna lista ich nie obejmie.

Lepszą metodą jest dobieranie breakpointów do treści. Zmniejszaj powoli okno przeglądarki od największej szerokości. Gdy układ zaczyna się łamać (tekst za wąski, przyciski nachodzą na siebie), dodaj w tym miejscu breakpoint. W ten sposób strona działa też na urządzeniach, o których nie pomyślałeś.

Breakpointy możesz zapisywać w pikselach albo w em. W media queries em i rem liczone są od domyślnego rozmiaru czcionki przeglądarki (zwykle 16 px), a nie od font-size ustawionego w CSS. Sprawdziłem to: przy html { font-size: 32px } i oknie 700 px warunek (min-width: 40em) nadal się spełnia, bo 40em to tu 640 px, a nie 1280 px.

Dlaczego nie mogę użyć zmiennej CSS w media query?

Zmienne CSS (var(--nazwa)) działają we właściwościach, ale nie w warunku @media. Zapis poniżej wygląda sensownie, ale warunek nigdy nie zostanie spełniony:

:root {
  --breakpoint: 600px;
}

@media (min-width: var(--breakpoint)) {
  /* te style nie zadziałają */
}

Zmienne CSS nie są dostępne w warunkach @media, dlatego var() jest tam bez znaczenia. W praktyce wpisz wartość na stałe (600px) albo użyj preprocesora, np. Sass, który podstawi ją podczas kompilacji. Sprawdziłem to w przeglądarce: (min-width: var(--bp)) przy oknie 900 px nie pasuje, a (min-width: 600px) pasuje.

Co się dzieje przy dokładnie tej samej szerokości (pułapka 768 px)?

Jeśli użyjesz max-width: 768px w jednym zapytaniu i min-width: 768px w drugim, to przy szerokości dokładnie 768 px oba będą aktywne. Style z obu bloków nałożą się, a wygra ten, który jest niżej w pliku:

// przy oknie o szerokości dokładnie 768 px
console.log(matchMedia("(max-width: 768px)").matches); // true
console.log(matchMedia("(min-width: 768px)").matches); // true

// zapis zakresowy wyklucza nakładanie
console.log(matchMedia("(width < 768px)").matches);    // false
console.log(matchMedia("(width >= 768px)").matches);   // true

Najprościej unikać takiej sytuacji, stosując w całym projekcie tylko min-width (mobile first). Wtedy żadne dwa zapytania nie „sprzeczają się” o ten sam piksel.

Jak użyć media queries w JavaScripcie (matchMedia)?

Czasem potrzebujesz zareagować na zmianę rozmiaru w kodzie, a nie tylko w CSS. Służy do tego window.matchMedia z tym samym zapisem warunku co w CSS:

const szeroki = matchMedia("(min-width: 600px)");

console.log(szeroki.matches); // true lub false, zależnie od szerokości okna

// reakcja na zmianę rozmiaru okna
szeroki.addEventListener("change", (zdarzenie) => {
  console.log("Okno jest teraz szerokie:", zdarzenie.matches);
});

// preferencje użytkownika
const ciemny = matchMedia("(prefers-color-scheme: dark)").matches;
const mniejRuchu = matchMedia("(prefers-reduced-motion: reduce)").matches;
console.log({ ciemny, mniejRuchu });

Zdarzenie change odpala się tylko wtedy, gdy wynik zapytania się zmieni (np. okno przekroczy 600 px), a nie przy każdej zmianie rozmiaru. Zwykle jest to lepsze rozwiązanie niż nasłuchiwanie na resize, które odpala się przy każdej zmianie rozmiaru. O obsłudze zdarzeń z użyciem funkcji zwrotnych przeczytasz w artykule o callback functions w JavaScript.

Jakie błędy z media queries zdarzają się najczęściej?

BłądSkutekJak naprawić
brak <meta name="viewport">na telefonie @media nie działa (strona ma 980 px)dodaj meta viewport w <head>
@media zapisane przed regułą bazowąreguła bazowa nadpisuje media querynajpierw style bazowe, potem @media
var(--zmienna) w warunkuwarunek nigdy się nie spełniawpisz wartość na stałe lub użyj Sass
max-width: 768px i min-width: 768px jednocześnieprzy 768 px oba aktywneużywaj tylko min-width albo zapisu zakresowego
breakpointy dobrane do modeli telefonówukład łamie się na innych urządzeniachdobieraj breakpointy do treści
brak sprawdzenia na prawdziwym telefoniebłędy dotykowe i hover niewidoczne w oknietestuj też na urządzeniu

Co dalej w nauce responsywności?

Media queries to dopiero początek. Do budowania responsywnych stron potrzebujesz jeszcze jednostek względnych, elastycznych obrazów i układu w CSS Grid. Te tematy omawiamy w module HTML i CSS: Responsywność. Podczas kursu JavaScript z mentorem kursanci wykonują zadania i projekt z tej tematyki, więc od razu sprawdzają w praktyce, jak responsywność działa w prawdziwej aplikacji.

Konsultacja i warsztaty devmentor.pl

Masz pytania?

Partnerzy

Firmy, z którymi współpracujemy

To partnerzy odpowiedzialni za staże po naszych kursach. Organizują je dla najlepszych absolwentów.

Zobacz wszystkich partnerów →
  • VR Medical
  • Sophona
  • Robot Force