Potwierdzone sprawdzone punkt po punkcie · 2026-11-05
Pomiń nawigację
Informatyka · INF.03

HTML I CSS · INF.03 · MODUŁ 10

Grid, responsywność i projekt egzaminacyjny

Ostatni krok: łączysz wszystko w projekt, który działa na telefonie i na dużym ekranie.

Wprowadzenie

Flexbox układa elementy w jednej osi — w rzędzie albo w kolumnie. CSS Grid idzie o krok dalej: pozwala budować układ jednocześnie w wierszach i kolumnach. Galeria, katalog produktów czy cała strona z nagłówkiem, menu i stopką to naturalne zastosowania siatki.

Grid najlepiej sprawdza się tam, gdzie treść ma kilka kolumn o wspólnych odstępach. Definiujesz liczbę kolumn przez grid-template-columns, a odstępy przez gap. Zapis repeat(auto-fit, minmax(180px, 1fr)) sprawia, że przeglądarka sama dobiera liczbę kolumn do szerokości ekranu.

Responsywność to dostosowanie strony do telefonu, tabletu i dużego ekranu. Zaczyna się od <meta name="viewport"> w nagłówku dokumentu. Bez niego telefon renderuje stronę tak, jakby był szeroki na około 980 px, i wszystko wygląda jak pomniejszony desktop.

Do zmiany układu służą media queries, np. @media (max-width: 640px). W podejściu mobile-first piszemy najpierw style dla telefonu, a dopiero potem dodajemy układ dla większych ekranów przez min-width. Rozmiary tekstu i odstępów można płynnie ograniczać funkcją clamp().

Grid czy flex?

Gdy układ ma wiersze i kolumny jednocześnie — wybierz Grid. Gdy wystarczy jeden rząd lub jedna kolumna — flexbox jest prostszy.

1. Do czego najlepiej nadaje się CSS Grid?
1. Do czego najlepiej nadaje się CSS Grid?
2. Co robi auto-fit w zapisie repeat(auto-fit, minmax(180px, 1fr))?
2. Co robi auto-fit w zapisie repeat(auto-fit, minmax(180px, 1fr))?
3. Po co w nagłówku dokumentu umieszczamy meta viewport?
3. Po co w nagłówku dokumentu umieszczamy meta viewport?

Najważniejsza własność

W Gridzie najważniejsza jest definicja kolumn, czyli grid-template-columns. Ona decyduje, ile kolumn powstanie i jak szerokie będą. Wiersze tworzą się automatycznie, chyba że ustawisz je osobno przez grid-template-rows.

Responsywna siatka

grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));

@media (max-width: 640px) { grid-template-columns: 1fr; }

WłaściwośćCo robi
display: gridWłącza siatkę na elemencie-rodzicu.
grid-template-columnsUstala liczbę i szerokość kolumn, np. 200px 1fr 1fr.
grid-template-rowsUstala wysokość wierszy, np. 80px auto 60px.
repeat(3, 1fr)Powtarza definicję trzy razy — daje trzy równe kolumny.
minmax(180px, 1fr)Daje kolumnie minimum 180 px, a resztę miejsca rozdziela elastycznie.
auto-fitTworzy tyle kolumn, ile zmieści się w dostępnej szerokości.
gapDodaje odstępy między kolumnami i wierszami.
grid-template-areasNazywa obszary siatki, np. "header header" "nav main" "footer footer".

Media query to reguła warunkowa. Zapis @media (max-width: 640px) oznacza: zastosuj te style, gdy ekran ma najwyżej 640 px szerokości. Zapis @media (min-width: 640px) działa odwrotnie — od 640 px w górę. W podejściu mobile-first częściej używamy min-width, bo style bazowe są już przystosowane do telefonu.

Do responsywnych obrazów wystarczy max-width: 100%; height: auto;. Obraz nigdy nie wyjdzie wtedy poza kontener i zachowa proporcje. Do płynnego rozmiaru tekstu służy clamp(minimum, wartość płynna, maksimum), np. clamp(1.5rem, 4vw, 2.5rem).

Mobile-first oszczędza style

Najpierw ustaw układ jednokolumnowy dla telefonu, a w @media (min-width: 700px) dodaj tylko to, co się zmienia: liczbę kolumn i wielkość odstępów.

Most: od reguły do gotowej siatki

Uzupełnij siatkę i oceń kod

Dwie aktywności prowadzą od składni do krytycznego czytania. Najpierw uzupełnij brakujące fragmenty, potem sprawdź, które linie responsywnego CSS są błędne.

Galeria, która sama dobiera kolumny

uzupełnianie luk

Uzupełnij cztery luki. Galeria ma tworzyć kolumny o minimalnej szerokości 180 px, a na telefonie przechodzić do jednej kolumny.

.galeria {
  display: ;
  grid-template-columns: repeat(
    ,
    minmax(180px, 1fr)
  );
  : 16px;
}

@media (max-width: 640px) {
  .galeria {
    grid-template-columns: ;
  }
}
Uzupełnij cztery luki.

Oceń responsywny kod

code review

Oceń każdą linię: OK, błąd logiczny, brak dostępności albo zła praktyka. W dwie linie wkradł się problem.

Oceń każdą linię.
4. Co robi minmax(180px, 1fr) w definicji kolumn?
4. Co robi minmax(180px, 1fr) w definicji kolumn?
5. Który zapis jest typowy dla podejścia mobile-first?
5. Który zapis jest typowy dla podejścia mobile-first?
6. Do czego służy clamp(1.5rem, 4vw, 2.5rem)?
6. Do czego służy clamp(1.5rem, 4vw, 2.5rem)?

Przykłady

Od samej galerii, przez tę samą stronę na dwóch ekranach, do pełnego projektu egzaminacyjnego. Każdy przykład pokazuje kod i prawdziwy zrzut z przeglądarki.

Przykład 1 — galeria w Gridzie

Sześć zdjęć ma utworzyć siatkę, która sama dobiera liczbę kolumn. Każda kolumna ma mieć co najmniej 180 px, a wolne miejsce ma być rozdzielone równo.

HTML
<div class="galeria">
  <figure>
    <img src="../assets/gory.svg" alt="Górski pejzaż ze słońcem">
    <figcaption>Górski szlak</figcaption>
  </figure>
  <figure>
    <img src="../assets/morze.svg" alt="Błękitne morze i plaża">
    <figcaption>Bałtyk latem</figcaption>
  </figure>
  <figure>
    <img src="../assets/las.svg" alt="Zielony las z drzewami">
    <figcaption>Las o świcie</figcaption>
  </figure>
  <figure>
    <img src="../assets/miasto.svg" alt="Miasto o zachodzie słońca">
    <figcaption>Miasto nocą</figcaption>
  </figure>
  <figure>
    <img src="../assets/gory.svg" alt="Szczyty górskie ze śniegiem">
    <figcaption>Zimowe szczyty</figcaption>
  </figure>
  <figure>
    <img src="../assets/morze.svg" alt="Spokojne morze o zachodzie">
    <figcaption>Port o zachodzie</figcaption>
  </figure>
</div>
CSS
.galeria {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 16px;
  max-width: 720px;
  margin: 22px auto 0;
}
.galeria figure {
  margin: 0;
  overflow: hidden;
  border: 1px solid #dbe3ef;
  border-radius: 14px;
  background: #fff;
}
.galeria img {
  display: block;
  width: 100%;
  height: 120px;
  object-fit: cover;
}
.galeria figcaption {
  padding: 10px 12px;
  font-size: 13px;
  font-weight: 600;
}
Galeria sześciu zdjęć ułożonych w trzy kolumny i dwa rzędy
Efekt repeat(auto-fit, minmax(180px, 1fr)): trzy kolumny, równe odstępy i jednakowa wysokość zdjęć.
  1. display: grid zamienia kontener w siatkę, a jego dzieci stają się komórkami.
  2. auto-fit tworzy tyle kolumn, ile zmieści się w dostępnej szerokości.
  3. minmax(180px, 1fr) pilnuje, żeby kolumna nie była węższa niż 180 px, i dzieli resztę miejsca po równo.
  4. gap: 16px dodaje odstępy bez marginesów na pojedynczych elementach.

Wynik: sześć zdjęć w trzech kolumnach; po zwężeniu okna liczba kolumn zmniejsza się automatycznie.

Przykład 2 — ta sama strona na desktopie i telefonie

Nagłówek, sekcja powitalna i trzy karty usług mają działać na obu ekranach. Na telefonie nawigacja i karty mają ułożyć się pionowo, a na desktopie pozostać w rzędach.

HTML
<header class="naglowek">
  <strong>Studio Web</strong>
  <nav>
    <a href="#">Oferta</a>
    <a href="#">Realizacje</a>
    <a href="#">Kontakt</a>
  </nav>
</header>

<section class="hero">
  <h2>Strony, które działają na każdym ekranie</h2>
  <p>Projektujemy od telefonu, a potem rozszerzamy układ.</p>
</section>

<section class="uslugi">
  <article class="usluga">
    <h3>Projekt strony</h3>
    <p>Układ, kolory i typografia.</p>
  </article>
  <article class="usluga">
    <h3>Wdrożenie</h3>
    <p>Semantyczny HTML i czysty CSS.</p>
  </article>
  <article class="usluga">
    <h3>Responsywność</h3>
    <p>Telefon, tablet i desktop.</p>
  </article>
</section>
CSS — układ i media query
.naglowek {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  padding: 16px 20px;
  background: #0f172a;
  color: #fff;
}
.naglowek nav { display: flex; gap: 14px; }
.hero h2 {
  margin: 0 0 10px;
  font-size: clamp(26px, 5vw, 38px);
}
.uslugi {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
}
@media (max-width: 640px) {
  .naglowek {
    flex-direction: column;
    align-items: flex-start;
  }
  .uslugi { grid-template-columns: 1fr; }
  .hero { padding: 22px 18px; }
}
Strona Studia Web na szerokim ekranie: nawigacja w rzędzie i trzy karty usług obok siebie
Desktop: nawigacja w jednej linii, trzy karty usług w trzech kolumnach.
Ta sama strona na telefonie: nawigacja pod logo, karty usług jedna pod drugą
Telefon: ten sam kod, węższy ekran. Media query zmienia kierunek nawigacji i liczbę kolumn.
  1. Style bazowe ustawiają nagłówek i karty w rzędzie — to widok desktopowy.
  2. @media (max-width: 640px) uruchamia się dopiero na wąskim ekranie.
  3. W środku media query nawigacja dostaje flex-direction: column, a siatka usług jedną kolumnę.
  4. Pliki demo różnią się tylko klasą szerokości (.demo i .demo.mobile). Reguły CSS są identyczne.

Wynik: jedna strona, dwa układy. Na telefonie nic nie wychodzi poza ekran i nie trzeba przewijać w poziomie.

Przykład 3 — pełny projekt „Strona warsztatu”

Projekt egzaminacyjny: nagłówek z logo i telefonem, menu, sekcja powitalna, sześć usług w Gridzie, galeria czterech zdjęć i stopka w trzech kolumnach. Całość ma 960 px szerokości.

HTML — szkielet
<div class="projekt">
  <header class="naglowek">
    <div>
      <p class="firma">Warsztat <span>Podróży</span></p>
      <p class="haslo">Fotografia · góry · morze</p>
    </div>
    <div class="telefon">Zadzwoń<strong>500 600 700</strong></div>
  </header>

  <nav class="menu">
    <a href="#uslugi">Usługi</a>
    <a href="#galeria">Galeria</a>
    <a href="#kontakt">Kontakt</a>
  </nav>

  <section class="hero">
    <p class="kicker">Od 1998 roku</p>
    <h1>Naucz się podróżować świadomie</h1>
    <p>Warsztaty fotograficzne, wyjazdy w góry i weekendy nad morzem.</p>
    <a class="cta" href="#kontakt">Zarezerwuj miejsce</a>
  </section>

  <section class="sekcja" id="uslugi">
    <h2>Nasze usługi</h2>
    <div class="uslugi">
      <article class="usluga">
        <span class="nr">01</span>
        <h3>Warsztaty fotograficzne</h3>
        <p>Kompozycja, światło i ustawienia aparatu.</p>
      </article>
      <article class="usluga">
        <span class="nr">02</span>
        <h3>Wyjazdy w góry</h3>
        <p>Trzy dni z planem zdjęciowym i przewodnikiem.</p>
      </article>
      <!-- cztery kolejne karty usług -->
    </div>
  </section>

  <section class="sekcja" id="galeria">
    <h2>Warsztat w praktyce</h2>
    <div class="galeria">
      <img src="../assets/gory.svg" alt="Górski pejzaż">
      <img src="../assets/morze.svg" alt="Morze i plaża">
      <img src="../assets/las.svg" alt="Zielony las">
      <img src="../assets/miasto.svg" alt="Miasto o zachodzie słońca">
    </div>
  </section>

  <footer class="stopka" id="kontakt">
    <div><h3>Kontakt</h3><p>ul. Wędrowna 12<br>500 600 700</p></div>
    <div><h3>Godziny</h3><p>pon.–pt. 9:00–17:00</p></div>
    <div><h3>Napisz</h3><p>biuro@warsztat-podrozy.pl</p></div>
  </footer>
</div>
CSS — najważniejsze reguły
.projekt { width: 960px; max-width: 100%; padding: 0; overflow: hidden; }

.naglowek {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 24px;
  padding: 22px 40px;
  background: #0f172a;
  color: #fff;
}
.menu { display: flex; gap: 26px; padding: 14px 40px; background: #1e293b; }

.hero {
  padding: 54px 40px 58px;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, .95), rgba(15, 23, 42, .35)),
    url("../assets/gory.svg") center / cover;
  color: #fff;
}
.hero h1 { margin: 0 0 12px; font-size: 40px; line-height: 1.15; }

.sekcja { padding: 40px; }
.uslugi { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.usluga { padding: 18px; border: 1px solid #e2e8f0; border-radius: 12px; }
.galeria { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
.galeria img { width: 100%; height: 120px; object-fit: cover; border-radius: 10px; }

.stopka {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
  padding: 30px 40px;
  background: #0f172a;
  color: #cbd5e1;
}

@media (max-width: 720px) {
  .naglowek { flex-direction: column; align-items: flex-start; }
  .uslugi { grid-template-columns: 1fr; }
  .galeria { grid-template-columns: repeat(2, 1fr); }
  .stopka { grid-template-columns: 1fr; }
}
Pełna strona warsztatu: ciemny nagłówek, menu, duża sekcja powitalna ze zdjęciem gór, sześć usług w trzech kolumnach, galeria czterech zdjęć i stopka
Projekt 960 px: header, nav, hero, usługi w Gridzie, galeria i footer. Każda sekcja ma wspólny margines i spójne kolory.
  1. Nagłówek i stopka korzystają z flexboxa, bo wystarczy jeden rząd lub jedna kolumna.
  2. Sekcja usług używa repeat(3, 1fr), bo zawsze mają być trzy równe kolumny na desktopie.
  3. Galeria używa repeat(4, 1fr), a na telefonie przechodzi na dwie kolumny.
  4. Media query zmienia tylko to, co trzeba: kierunek nagłówka i liczbę kolumn. Reszta stylów zostaje wspólna.

Wynik: kompletna strona projektu z czytelnym podziałem na sekcje i układem, który nadal działa po zwężeniu okna.

Most: policz kolumny przed uruchomieniem

Przewidź wynik siatki

Zanim otworzysz przeglądarkę, policz, ile kolumn powstanie. To najczęstsze pytanie przy czytaniu kodu z auto-fit i minmax.

Ile kolumn w galerii?

przewidywanie

Kontener ma 660 px szerokości. Ile kolumn utworzy ta siatka?

.galeria {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 20px;
  width: 660px;
}
Wybierz jedną odpowiedź.
7. Galeria ma grid-template-columns: repeat(3, 1fr) i siedem zdjęć. Ile zdjęć znajdzie się w pierwszym rzędzie?
7. Galeria ma grid-template-columns: repeat(3, 1fr) i siedem zdjęć. Ile zdjęć znajdzie się w pierwszym rzędzie?
8. Na telefonie karty usług mają stać jedna pod drugą. Co ustawisz w media query?
8. Na telefonie karty usług mają stać jedna pod drugą. Co ustawisz w media query?
9. Co daje gap: 16px w kontenerze display: grid?
9. Co daje gap: 16px w kontenerze display: grid?

Spróbuj samodzielnie

Cztery zadania prowadzą od pojedynczej reguły do pełnej sekcji projektu. W każdym rozwiązaniu zwróć uwagę nie tylko na wynik, ale i na kolejność decyzji.

  1. Galeria ma mieć kolumny o minimalnej szerokości 200 px i same dopasowywać się do ekranu. Napisz regułę dla kontenera i wyjaśnij, co robi każda część zapisu.

    Pokaż rozwiązanie
    .galeria {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
      gap: 16px;
    }

    display: grid włącza siatkę. repeat powtarza definicję kolumny. auto-fit dobiera liczbę powtórzeń do miejsca, a minmax(200px, 1fr) mówi, że kolumna ma co najmniej 200 px i może rosnąć. gap dodaje odstępy.

  2. Masz stronę z nagłówkiem .naglowek i sekcją kart .karty. Napisz style mobile-first: na telefonie nagłówek ma być w kolumnie, a karty jedna pod drugą; od 700 px nagłówek ma być w rzędzie, a karty w trzech kolumnach.

    Pokaż rozwiązanie
    .naglowek {
      display: flex;
      flex-direction: column;
      gap: 10px;
    }
    .karty {
      display: grid;
      grid-template-columns: 1fr;
      gap: 16px;
    }
    
    @media (min-width: 700px) {
      .naglowek { flex-direction: row; justify-content: space-between; }
      .karty { grid-template-columns: repeat(3, 1fr); }
    }

    Style bazowe opisują telefon, więc nie trzeba ich później nadpisywać. Media query z min-width dodaje tylko układ dla szerszego ekranu.

  3. Uczeń twierdzi, że strona jest responsywna, ale na telefonie pojawia się poziomy pasek przewijania, a obraz wychodzi poza kartę. Wskaż dwie przyczyny i popraw kod.

    <meta charset="utf-8">
    <title>Moja strona</title>
    
    .kontener { width: 1100px; }
    .kontener img { width: 800px; }
    Pokaż rozwiązanie

    Brakuje <meta name="viewport">, więc telefon nie dopasowuje strony do ekranu. Dodatkowo stałe szerokości 1100 px i 800 px są szersze niż ekran telefonu.

    <meta name="viewport" content="width=device-width, initial-scale=1">
    
    .kontener {
      width: 100%;
      max-width: 1100px;
      margin: 0 auto;
    }
    .kontener img {
      max-width: 100%;
      height: auto;
    }

    max-width pozwala elementowi zwężyć się na telefonie, ale nie rozpycha go ponad 1100 px na dużym ekranie. Obraz z max-width: 100% nigdy nie wyjdzie poza rodzica.

  4. Zbuduj sekcję usług: nagłówek h2, krótki opis i trzy karty w Gridzie. Każda karta ma mieć numer, tytuł i opis. Na telefonie karty mają ułożyć się pionowo. Napisz HTML i CSS z media query.

    Pokaż rozwiązanie
    <section class="sekcja">
      <h2>Nasze usługi</h2>
      <p class="lead">Wybierz formę dla siebie.</p>
      <div class="uslugi">
        <article class="usluga">
          <span class="nr">01</span>
          <h3>Warsztaty</h3>
          <p>Praktyka w małej grupie.</p>
        </article>
        <article class="usluga">
          <span class="nr">02</span>
          <h3>Wyjazdy</h3>
          <p>Trzy dni w górach.</p>
        </article>
        <article class="usluga">
          <span class="nr">03</span>
          <h3>Online</h3>
          <p>Szkolenia bez wychodzenia z domu.</p>
        </article>
      </div>
    </section>
    .uslugi {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 16px;
    }
    .usluga {
      padding: 18px;
      border: 1px solid #e2e8f0;
      border-radius: 12px;
    }
    @media (max-width: 640px) {
      .uslugi { grid-template-columns: 1fr; }
    }

    Desktop ma trzy równe kolumny. Media query zmienia tylko definicję kolumn, więc karty same ustawią się pionowo. Nie trzeba zmieniać HTML ani dodawać nowych klas.

Podsumowanie modułu

Grid buduje układ w dwóch wymiarach: grid-template-columns ustala kolumny, repeat powtarza definicję, a minmax i auto-fit pozwalają siatce dopasować się do ekranu. gap pilnuje odstępów, a grid-template-areas nazywa większe obszary strony. Responsywność zaczyna się od meta viewport, a media queries zmieniają układ przy wybranej szerokości. Mobile-first oznacza style dla telefonu jako bazę i min-width dla większych ekranów. clamp() ogranicza rozmiary, a max-width: 100% chroni obrazy przed wychodzeniem poza kontener.

10. Chcesz, aby galeria miała tyle kolumn, ile zmieści się przy minimalnej szerokości 200 px. Który zapis wybierzesz?
10. Chcesz, aby galeria miała tyle kolumn, ile zmieści się przy minimalnej szerokości 200 px. Który zapis wybierzesz?
11. Strona wygląda dobrze na telefonie, ale na desktopie treść jest za wąska. Co dodasz?
11. Strona wygląda dobrze na telefonie, ale na desktopie treść jest za wąska. Co dodasz?
12. Jak w CSS zapewnić, aby duży obraz nie wychodził poza swój kontener?
12. Jak w CSS zapewnić, aby duży obraz nie wychodził poza swój kontener?