Przejdź do głównej treści
INF.03-08-26.06-SGCzerwiec 2026 · 46 kroków · ok. 81 min · 35 kryteriów z klucza

Rozwiązanie krok po kroku: Portal wypożyczalni gier (Nowoczesny kod (flex, try/catch))

To drugi sposób rozwiązania tego samego arkusza. Wynik jest ten sam - baza bazagier z czterema zapytaniami, grafika gra10.jpg, strony index.html i onas.html oraz licznik wejść w localStorage - i tak samo spełnia każde kryterium klucza. Inna jest droga:

  • flexbox zamiast float: ciało strony jest kontenerem z zawijaniem - dwa nagłówki stają w jednym wierszu (40% i 60%), blok główny i stopka zajmują całą szerokość bez clear; galeria to osobny kontener flex, który zawija i wyśrodkowuje miniatury,
  • zapytania z aliasami tabel i warunkami złączeń w ON,
  • skrypt odporny od pierwszej linii: try … catch wokół localStorage (przeglądarka z zablokowaną pamięcią nie przerywa skryptu), zabezpieczenie przed zapisem, który nie jest liczbą, textContent i szablon tekstowy; funkcja dopięta przez addEventListener('load', ...) zamiast atrybutu onload w każdym pliku.

Na końcu krótkie porównanie z wersją podstawową (zakładka obok). Baza i obrazy pochodzą z prawdziwego archiwum pliki18, zapytania zostały wykonane na tej bazie w MariaDB. Ramka podglądu nie ma dostępu do pamięci przeglądarki - dzięki try … catch licznik i tak pokazuje w niej pierwsze wejście, bez żadnego zamiennika.

Jak liczą się punkty. Klucz ma 35 kryteriów (R.1.1 - R.5.6), każde za 1 punkt. Próg zdania to 75%, czyli 27 punktów. Przy każdym kroku jest napisane, które kryteria spełnia.

  1. Etap 1: Baza danych

    Kroki 1-7 · po tym etapie masz 6 z 35 kryteriów (pkt)

    Krok 1: Baza danych bazagier

    ok. 2 min
    Polecenie z arkusza

    Utwórz bazę danych o nazwie bazagier, z zestawem znaków utf8mb4_unicode_ci.

    Archiwum pliki18.7z rozpakuj hasłem WypożyczalniaGierWideo (z literą „ż”). W phpMyAdmin Nowa → bazagier, porównywanie dokładnie utf8mb4_unicode_ci:

    CREATE DATABASE bazagier CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
    

    utf8mb4 to pełny UTF-8 (także emoji); utf8 w MySQL obsługuje tylko znaki do 3 bajtów.

  2. Krok 2: Import tabel z pliku bazagier.sql

    ok. 2 min
    Polecenie z arkusza

    Do utworzonej bazy zaimportuj tabele z pliku bazagier.sql.

    Import → bazagier.sql. Trzy tabele z ilustracji 1: gry z kluczami obcymi id_producenta i id_wydawcy, producenci i wydawcy.

  3. Krok 3: Zrzut ekranu import.png

    Kryteria:

    R.1.1 Wykonany import tabel do bazy danych bazagier - plik import .png

    ok. 2 min
    Polecenie z arkusza

    Wykonaj zrzut ekranu po imporcie. Zapisz zrzut w formacie PNG pod nazwą import. Nie kadruj zrzutu. Powinien on obejmować cały ekran monitora, z widocznym paskiem zadań. Na zrzucie powinny być widoczne elementy wskazujące na poprawnie wykonany import tabel.

    Import w PNG, a zrzuty zapytań w JPEG - arkusz podaje formaty osobno.

    Typowe błędy

    Wykadrowany zrzut nie jest oceniany.

  4. Krok 4: Zapytanie 1: gry niezależne z lat 2018 - 2023

    Kryteria: ,

    R.1.2 W pliku kwerendy.txt zapisane co najmniej jedno zapytanie SQL, wynikające z treści zadania

    R.1.3 Wykonane zapytanie 1 wybierające jedynie tytuł i gatunek gier wydanych w latach 2018 ÷ 2023, dla których jednym z gatunków jest „Niezależne”. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT tytul, gatunek FROM gry WHERE gatunek LIKE '%Niezależne%' AND data_wydania BETWEEN '2018-01-01' AND '2023-12-31';(poprawnie też z operatorami porównania) oraz na zrzucie widoczne są dokładnie 2 rekordy, z danymi dla: The Invincible, Moonlighter

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 1: wybierające jedynie tytuły i gatunki gier wydanych w latach 2018 ÷ 2023, dla których jednym z gatunków jest „Niezależne”.

    LIKE '%Niezależne%' szuka fragmentu w polu z gatunkami po przecinkach; BETWEEN z pełnymi datami to przedział domknięty z obu stron. Drugi warunek w osobnej linii z AND z przodu. Wynik: The Invincible i Moonlighter. Zrzut kw1.jpg.

    Typowe błędy

    BETWEEN 2018 AND 2023 na polu typu date porównuje datę z liczbą i nie zwraca nic.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT tytul, gatunek
    FROM gry
    WHERE gatunek LIKE '%Niezależne%'
      AND data_wydania BETWEEN '2018-01-01' AND '2023-12-31';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: liczba gier każdego producenta

    Kryteria:

    R.1.4 Wykonane zapytanie 2 wybierające jedynie nazwę każdego z producentów w bazie oraz liczbę gier (alias liczba_gier) , które ten producent wyprodukował, zgrupowane po nazwie producenta. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT producenci.nazwa, COUNT(gry.id_gry) AS liczba_gier FROM producenci LEFT JOIN gry USING(id_producenta) GROUP BY producenci.nazwa; (możliwe porównanie kluczy po ON lub WHERE, LEFT JOIN obowiązkowe, AS opcjonalne) oraz na zrzucie widocznych jest 8 rekordów, w tym dla producenta "Deep Silver" liczba_gier jest równa 0

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie nazwę każdego producenta w bazie oraz liczbę gier, które ten producent wyprodukował, zgrupowane po nazwie producenta. Kolumnie z liczbą gier należy nadać nazwę (alias) „liczba_gier”. Należy posłużyć się relacją i odpowiednim rodzajem złączenia (wybrani są wszyscy producenci, nawet z zerową liczbą gier).

    • FROM producenci AS p LEFT JOIN gry AS g - złączenie lewostronne: każdy producent jest w wyniku, także bez gier,
    • ON g.id_producenta = p.id_producenta - warunek złączenia; przy aliasach ON mówi wprost, która kolumna z której tabeli,
    • COUNT(g.id_gry) liczy tylko wiersze z grą (NULL pomija), więc producent bez gier ma 0.

    Wynik: 8 wierszy, Deep Silver z liczbą 0. Zrzut kw2.jpg.

    Typowe błędy

    JOIN zamiast LEFT JOIN gubi Deep Silver, a COUNT(*) liczy mu jedną grę - wiersz z samymi NULL też jest wierszem.

    kwerendy.txt Tekst zmienione: 6 linii
    -- Zapytanie 1
    SELECT tytul, gatunek
    FROM gry
    WHERE gatunek LIKE '%Niezależne%'
      AND data_wydania BETWEEN '2018-01-01' AND '2023-12-31';
    
    -- Zapytanie 2
    SELECT p.nazwa, COUNT(g.id_gry) AS liczba_gier
    FROM producenci AS p
    LEFT JOIN gry AS g ON g.id_producenta = p.id_producenta
    GROUP BY p.nazwa;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: gra, producent i wydawca

    Kryteria:

    R.1.5 Wykonane zapytanie 3 wybierające id_gry oraz tytuł gry z tabeli gry, odpowiadającą jej nazwę producenta z tabeli producenci oraz odpowiadającą jej nazwę wydawcy z tabeli wydawcy. Nazwa producenta - alias "producent", a nazwa wydawcy - alias "wydawca". W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT gry.id_gry, gry.tytul, producenci.nazwa AS producent, wydawcy.nazwa AS wydawca FROM gry JOIN producenci USING(id_producenta) JOIN wydawcy USING(id_wydawcy); (możliwe porównanie kluczy po ON lub WHER E, AS opcjonalne ) oraz na zrzucie widocznych jest 10 rekordów

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 3: wybierające identyfikatory i tytuły gier, odpowiadającą im nazwę producenta z tabeli producenci oraz odpowiadającą im nazwę wydawcy z tabeli wydawcy. Kolumnie z nazwą producenta należy nadać nazwę (alias) „producent”, a kolumnie z nazwą wydawcy – (alias) „wydawca”. Należy posłużyć się złożoną relacją.

    Trzy tabele z aliasami g, p, w i dwa złączenia: gra z producentem i gra z wydawcą. Obie dołączone tabele mają kolumnę nazwa - aliasy kolumn producent i wydawca je rozróżniają. Wynik: 10 wierszy. Zrzut kw3.jpg.

    Typowe błędy

    Samo nazwa bez przedrostka tabeli kończy się błędem „Column 'nazwa' in field list is ambiguous”.

    kwerendy.txt Tekst zmienione: 6 linii
    -- Zapytanie 1
    SELECT tytul, gatunek
    FROM gry
    WHERE gatunek LIKE '%Niezależne%'
      AND data_wydania BETWEEN '2018-01-01' AND '2023-12-31';
    
    -- Zapytanie 2
    SELECT p.nazwa, COUNT(g.id_gry) AS liczba_gier
    FROM producenci AS p
    LEFT JOIN gry AS g ON g.id_producenta = p.id_producenta
    GROUP BY p.nazwa;
    
    -- Zapytanie 3
    SELECT g.id_gry, g.tytul, p.nazwa AS producent, w.nazwa AS wydawca
    FROM gry AS g
    JOIN producenci AS p ON p.id_producenta = g.id_producenta
    JOIN wydawcy AS w ON w.id_wydawcy = g.id_wydawcy;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: kolumna ocena z wartością domyślną

    Kryteria:

    R.1.6 Wykonane zapytanie 4 dodające do tabeli gry kolumnę o nazwie ocena typu liczbowego, kolumna nie może być pusta, wartość domyślna to 5. W pliku z kwerendami lub na zrzucie istnieje zapis np.: ALTER TABLE gry ADD COLUMN ocena INT NOT NULL DEFAULT 5; (dowolny typ liczbowy) oraz na zrzucie jest widoczny komunikat o poprawnym wykonaniu kwerendy lub zmieniona struktura tabeli

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: dodające do tabeli gry kolumnę ocena typu liczbowego, kolumna nie może być pusta, a jej wartość domyślna to 5.

    ALTER TABLE … ADD COLUMN, NOT NULL i DEFAULT 5. Typ TINYINT UNSIGNED (0 - 255, jeden bajt) wystarcza na ocenę - klucz dopuszcza dowolny typ liczbowy, a dobrany do danych typ to mniej miejsca na dysku i w pamięci przy dużych tabelach. Istniejące gry od razu dostają 5. Zrzut struktury: kw4.jpg.

    kwerendy.txt Tekst zmienione: 4 linie
    -- Zapytanie 1
    SELECT tytul, gatunek
    FROM gry
    WHERE gatunek LIKE '%Niezależne%'
      AND data_wydania BETWEEN '2018-01-01' AND '2023-12-31';
    
    -- Zapytanie 2
    SELECT p.nazwa, COUNT(g.id_gry) AS liczba_gier
    FROM producenci AS p
    LEFT JOIN gry AS g ON g.id_producenta = p.id_producenta
    GROUP BY p.nazwa;
    
    -- Zapytanie 3
    SELECT g.id_gry, g.tytul, p.nazwa AS producent, w.nazwa AS wydawca
    FROM gry AS g
    JOIN producenci AS p ON p.id_producenta = g.id_producenta
    JOIN wydawcy AS w ON w.id_wydawcy = g.id_wydawcy;
    
    -- Zapytanie 4
    ALTER TABLE gry
    ADD COLUMN ocena TINYINT UNSIGNED NOT NULL DEFAULT 5;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strony HTML

    Kroki 8-26 · po tym etapie masz 18 z 35 kryteriów (pkt)

    Krok 8: Grafika gra10.jpg: skala i kadr

    Kryteria:

    R.2.1 Grafika gra10.jpg przedstawia przeskalowany obraz gra10.png i ma rozmiar: 1024 px szerokości i 576 px wysokości

    ok. 4 min
    Polecenie z arkusza

    Plik gra10.png, wypakowany z archiwum, należy przeskalować do szerokości 1024 px z zachowaniem proporcji obrazu, a następnie wykadrować w pionie do wymiaru 576 px. Tak przygotowaną grafikę należy zapisać w pliku gra10.jpg.

    W GIMP-ie Skaluj obraz do szerokości 1024 przy zamkniętym łańcuchu, potem Rozmiar płótna - wysokość 576, obraz wyśrodkowany w pionie, Spłaszcz obraz i eksport jako gra10.jpg (1024 × 576, jak pozostałe obrazy).

    Typowe błędy

    Skalowanie od razu do 1024 × 576 bez proporcji spłaszcza obraz.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 8
  9. Krok 9: Plik index.html w HTML5

    ok. 1 min
    Polecenie z arkusza

    Zapisane w języku HTML5.

    Najpierw index.html; onas.html powstanie z jego kopii - cechy wspólne wpisuje się raz.

    index.html HTML nowy plik
    <!DOCTYPE html>
    <html>
    <head>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  10. Krok 10: Język strony

    Kryteria:

    R.2.2 W plikach index.html lub onas.html znajduje się deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości: polski np. <html lang="pl">

    ok. 1 min
    Polecenie z arkusza

    Zadeklarowany polski język zawartości witryny.

    lang="pl" w <html> (R.2.2).

    index.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  11. Krok 11: Kodowanie polskich znaków

    ok. 1 min
    Polecenie z arkusza

    Jawnie zastosowany właściwy standard kodowania polskich znaków.

    <meta charset="UTF-8"> jako pierwszy element <head>.

    index.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  12. Krok 12: Tytuł strony głównej

    Kryteria:

    R.2.3 W sekcji head znajduje się jawnie podany standard kodowania polskich znaków oraz na stronie głównej tytuł "Najlepsze gry | PoGRAJmy!" lub na stronie o nas tytuł "O nas | PoGRAJmy!"

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony widoczny na karcie przeglądarki: „Najlepsze gry | PoGRAJmy!”.

    <title> z pionową kreską jak w arkuszu; obok <meta name="viewport"> dla telefonów (arkusz tego nie wymaga).

    index.html HTML zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Najlepsze gry | PoGRAJmy!</title>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  13. Krok 13: Podpięcie arkusza stylów

    Kryteria:

    R.3.2 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl_gier.css formatowanie CSS pochodzi jedynie z tego arkusza

    ok. 1 min
    Polecenie z arkusza

    Arkusz stylów styl_gier.css właściwie połączony z kodem strony.

    Nazwa z podkreśleniem: styl_gier.css (R.3.2).

    index.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Najlepsze gry | PoGRAJmy!</title>
        <link rel="stylesheet" href="styl_gier.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  14. Krok 14: Podpięcie pliku skryptu z defer

    ok. 1 min
    Polecenie z arkusza

    Plik skryptu skrypty.js właściwie połączony z kodem strony.

    <script src="skrypty.js" defer></script> w <head>: przeglądarka pobiera skrypt równolegle z HTML-em i wykonuje go dopiero po wczytaniu całego dokumentu - nie wstrzymuje wyświetlania strony.

    index.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Najlepsze gry | PoGRAJmy!</title>
        <link rel="stylesheet" href="styl_gier.css">
        <script src="skrypty.js" defer></script>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  15. Krok 15: Bloki: dwa nagłówkowe, główny, stopka

    Kryteria:

    R.2.4 W sekcji body zdefiniowany jest podział na bloki za pomocą semantycznych znaczników HTML 5: header+header, main, footer (dopuszcza się stosowanie bloków pomocniczych)

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: nagłówkowy 1, nagłówkowy 2, główny, stopki. Podział zrealizowany za pomocą semantycznych znaczników języka HTML5 tak, aby po uruchomieniu w przeglądarce układ bloków był zgodny z ilustracją 3.

    Dwa <header>, <main> i <footer> - układ z klucza R.2.4. Nagłówki różnią się stylem, więc dostają identyfikatory.

    index.html HTML zmienione: 8 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Najlepsze gry | PoGRAJmy!</title>
        <link rel="stylesheet" href="styl_gier.css">
        <script src="skrypty.js" defer></script>
    </head>
    <body>
        <header id="header1">
        </header>
        <header id="header2">
        </header>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  16. Krok 16: Logo: nagłówek z odnośnikiem

    Kryteria:

    R.2.5 W bloku nagłówkowym 1 znajduje się <h2>: „PoGRAJmy!”

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku nagłówkowego 1: Nagłówek drugiego stopnia zawierający odnośnik do pliku index.html o treści „PoGRAJmy!”.

    Odnośnik <a> wewnątrz <h2> (R.2.5).

    index.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Najlepsze gry | PoGRAJmy!</title>
        <link rel="stylesheet" href="styl_gier.css">
        <script src="skrypty.js" defer></script>
    </head>
    <body>
        <header id="header1">
            <h2><a href="index.html">PoGRAJmy!</a></h2>
        </header>
        <header id="header2">
        </header>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  17. Krok 17: Menu: lista z dwoma odnośnikami w nav

    Kryteria: ,

    R.2.6 W bloku nagłówkowym 2 znajduje się lista nieuporządkowana zawierająca elementy "Strona główna", "O nas", (zastosowane <ul>, <li>)

    R.3.3 Kliknięcie odnośnika: "Strona główna" lub odnośnika "PoGRAJmy!" prowadzi do pliku index.html , kliknięcie "O nas" prowadzi do pliku onas.html

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku nagłówkowego 2: Lista punktowana (nieuporządkowana), której elementami są: odnośnik do pliku index.html o treści „Strona główna”, odnośnik do pliku onas.html o treści „O nas”.

    Lista <ul> z dwoma odnośnikami (R.2.6, R.3.3), owinięta w <nav> - znacznik głównej nawigacji witryny, po którym czytnik ekranu pozwala przeskoczyć prosto do menu. Klucz dopuszcza bloki pomocnicze, a blok nagłówkowy 2 nadal jest <header>.

    index.html HTML zmienione: 6 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Najlepsze gry | PoGRAJmy!</title>
        <link rel="stylesheet" href="styl_gier.css">
        <script src="skrypty.js" defer></script>
    </head>
    <body>
        <header id="header1">
            <h2><a href="index.html">PoGRAJmy!</a></h2>
        </header>
        <header id="header2">
            <nav>
                <ul>
                    <li><a href="index.html">Strona główna</a></li>
                    <li><a href="onas.html">O nas</a></li>
                </ul>
            </nav>
        </header>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  18. Krok 18: Stopka: autor pogrubiony znacznikiem ważności

    ok. 1 min
    Polecenie z arkusza

    Zawartość stopki: Paragraf o treści: „Autor:” dalej wstawiony numer zdającego. Numer zdającego należy zapisać przy użyciu znacznika semantycznego oznaczającego tekst ważny domyślnie formatowany jako pogrubiony.

    Tekst ważny to <strong>. Na egzaminie wpisujesz swój numer zdającego (PESEL) - tutaj stoi imię i nazwisko autora rozwiązania.

    index.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Najlepsze gry | PoGRAJmy!</title>
        <link rel="stylesheet" href="styl_gier.css">
        <script src="skrypty.js" defer></script>
    </head>
    <body>
        <header id="header1">
            <h2><a href="index.html">PoGRAJmy!</a></h2>
        </header>
        <header id="header2">
            <nav>
                <ul>
                    <li><a href="index.html">Strona główna</a></li>
                    <li><a href="onas.html">O nas</a></li>
                </ul>
            </nav>
        </header>
        <main>
        </main>
        <footer>
            <p>Autor: <strong>Bartosz Bryniarski</strong></p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  19. Krok 19: Stopka: miejsce na licznik

    Kryteria:

    R.2.7 W stopce znajdują się dwa <p>, w tym jeden z numerem zdającego

    ok. 1 min
    Polecenie z arkusza

    Paragraf zawierający efekt działania funkcji licznik ze skryptu.

    Pusty akapit counter - wypełni go skrypt. Dwa akapity w stopce to R.2.7.

    index.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Najlepsze gry | PoGRAJmy!</title>
        <link rel="stylesheet" href="styl_gier.css">
        <script src="skrypty.js" defer></script>
    </head>
    <body>
        <header id="header1">
            <h2><a href="index.html">PoGRAJmy!</a></h2>
        </header>
        <header id="header2">
            <nav>
                <ul>
                    <li><a href="index.html">Strona główna</a></li>
                    <li><a href="onas.html">O nas</a></li>
                </ul>
            </nav>
        </header>
        <main>
        </main>
        <footer>
            <p>Autor: <strong>Bartosz Bryniarski</strong></p>
            <p id="counter"></p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  20. Krok 20: Strona główna: nagłówek pierwszego stopnia

    Kryteria:

    R.2.8 W bloku głównym znajduje się <h1>: „Oto nasz wybór najciekawszych gier” lub „Twoje centrum rozrywki”

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku głównego: Nagłówek pierwszego stopnia o treści: „Oto nasz wybór najciekawszych gier”.

    <h1> w <main> (R.2.8).

    index.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Najlepsze gry | PoGRAJmy!</title>
        <link rel="stylesheet" href="styl_gier.css">
        <script src="skrypty.js" defer></script>
    </head>
    <body>
        <header id="header1">
            <h2><a href="index.html">PoGRAJmy!</a></h2>
        </header>
        <header id="header2">
            <nav>
                <ul>
                    <li><a href="index.html">Strona główna</a></li>
                    <li><a href="onas.html">O nas</a></li>
                </ul>
            </nav>
        </header>
        <main>
            <h1>Oto nasz wybór najciekawszych gier</h1>
        </main>
        <footer>
            <p>Autor: <strong>Bartosz Bryniarski</strong></p>
            <p id="counter"></p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  21. Krok 21: Galeria dziesięciu miniatur

    Kryteria:

    R.2.9 Na stronie głównej znajduje się blok zawierający co najmniej jeden obraz z alt = "Miniatura gry" oraz title = "Tytuł gry"

    ok. 3 min
    Polecenie z arkusza

    Blok zawierający dziesięć obrazów od gra1.jpg do gra10.jpg, każdy obraz ma ustawiony: Tekst alternatywny „Miniatura gry”. Podpowiedź (dymek pojawiający się po najechaniu kursorem na obraz) „Tytuł gry”.

    Blok gallery z dziesięcioma obrazami: alt dla czytnika ekranu i gdy obraz się nie wczyta, title - dymek po najechaniu (R.2.9).

    Typowe błędy

    Dymek daje title, a nie alt.

    index.html HTML zmienione: 12 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Najlepsze gry | PoGRAJmy!</title>
        <link rel="stylesheet" href="styl_gier.css">
        <script src="skrypty.js" defer></script>
    </head>
    <body>
        <header id="header1">
            <h2><a href="index.html">PoGRAJmy!</a></h2>
        </header>
        <header id="header2">
            <nav>
                <ul>
                    <li><a href="index.html">Strona główna</a></li>
                    <li><a href="onas.html">O nas</a></li>
                </ul>
            </nav>
        </header>
        <main>
            <h1>Oto nasz wybór najciekawszych gier</h1>
            <div class="gallery">
                <img src="gra1.jpg" alt="Miniatura gry" title="Tytuł gry">
                <img src="gra2.jpg" alt="Miniatura gry" title="Tytuł gry">
                <img src="gra3.jpg" alt="Miniatura gry" title="Tytuł gry">
                <img src="gra4.jpg" alt="Miniatura gry" title="Tytuł gry">
                <img src="gra5.jpg" alt="Miniatura gry" title="Tytuł gry">
                <img src="gra6.jpg" alt="Miniatura gry" title="Tytuł gry">
                <img src="gra7.jpg" alt="Miniatura gry" title="Tytuł gry">
                <img src="gra8.jpg" alt="Miniatura gry" title="Tytuł gry">
                <img src="gra9.jpg" alt="Miniatura gry" title="Tytuł gry">
                <img src="gra10.jpg" alt="Miniatura gry" title="Tytuł gry">
            </div>
        </main>
        <footer>
            <p>Autor: <strong>Bartosz Bryniarski</strong></p>
            <p id="counter"></p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  22. Krok 22: Strona onas.html z kopii i jej tytuł

    ok. 2 min
    Polecenie z arkusza

    Cechy strony onas.html: Tytuł strony widoczny na karcie przeglądarki: „O nas | PoGRAJmy!”.

    Kopia index.html jako onas.html: nowy tytuł i pusty blok główny. Nagłówki, menu, stopka i podpięcie skryptu przechodzą z kopią.

    onas.html HTML nowy plik
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>O nas | PoGRAJmy!</title>
        <link rel="stylesheet" href="styl_gier.css">
        <script src="skrypty.js" defer></script>
    </head>
    <body>
        <header id="header1">
            <h2><a href="index.html">PoGRAJmy!</a></h2>
        </header>
        <header id="header2">
            <nav>
                <ul>
                    <li><a href="index.html">Strona główna</a></li>
                    <li><a href="onas.html">O nas</a></li>
                </ul>
            </nav>
        </header>
        <main>
        </main>
        <footer>
            <p>Autor: <strong>Bartosz Bryniarski</strong></p>
            <p id="counter"></p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (onas.html)
  23. Krok 23: O nas: nagłówek pierwszego stopnia

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku głównego: Nagłówek pierwszego stopnia o treści: „Twoje centrum rozrywki”.

    <h1> drugiej strony.

    onas.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>O nas | PoGRAJmy!</title>
        <link rel="stylesheet" href="styl_gier.css">
        <script src="skrypty.js" defer></script>
    </head>
    <body>
        <header id="header1">
            <h2><a href="index.html">PoGRAJmy!</a></h2>
        </header>
        <header id="header2">
            <nav>
                <ul>
                    <li><a href="index.html">Strona główna</a></li>
                    <li><a href="onas.html">O nas</a></li>
                </ul>
            </nav>
        </header>
        <main>
            <h1>Twoje centrum rozrywki</h1>
        </main>
        <footer>
            <p>Autor: <strong>Bartosz Bryniarski</strong></p>
            <p id="counter"></p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (onas.html)
  24. Krok 24: O nas: blok z trzema obrazami

    ok. 1 min
    Polecenie z arkusza

    Blok zawierający trzy obrazy: gra10.jpg, gra5.jpg oraz gra1.jpg.

    Ten sam blok gallery, kolejność z arkusza. Arkusz nie podaje tekstu alternatywnego, ale każdy obraz powinien go mieć.

    onas.html HTML zmienione: 5 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>O nas | PoGRAJmy!</title>
        <link rel="stylesheet" href="styl_gier.css">
        <script src="skrypty.js" defer></script>
    </head>
    <body>
        <header id="header1">
            <h2><a href="index.html">PoGRAJmy!</a></h2>
        </header>
        <header id="header2">
            <nav>
                <ul>
                    <li><a href="index.html">Strona główna</a></li>
                    <li><a href="onas.html">O nas</a></li>
                </ul>
            </nav>
        </header>
        <main>
            <h1>Twoje centrum rozrywki</h1>
            <div class="gallery">
                <img src="gra10.jpg" alt="Grafika z gry">
                <img src="gra5.jpg" alt="Grafika z gry">
                <img src="gra1.jpg" alt="Grafika z gry">
            </div>
        </main>
        <footer>
            <p>Autor: <strong>Bartosz Bryniarski</strong></p>
            <p id="counter"></p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (onas.html)
  25. Krok 25: O nas: trzy akapity z pliku tekstowego

    ok. 2 min
    Polecenie z arkusza

    Trzy paragrafy z treścią skopiowaną z pliku teksty_marketingowe.txt.

    Każdy akapit pliku do osobnego <p>. Gwiazdki i podkreślenia na razie zostają - zamieni je następny krok.

    onas.html HTML zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>O nas | PoGRAJmy!</title>
        <link rel="stylesheet" href="styl_gier.css">
        <script src="skrypty.js" defer></script>
    </head>
    <body>
        <header id="header1">
            <h2><a href="index.html">PoGRAJmy!</a></h2>
        </header>
        <header id="header2">
            <nav>
                <ul>
                    <li><a href="index.html">Strona główna</a></li>
                    <li><a href="onas.html">O nas</a></li>
                </ul>
            </nav>
        </header>
        <main>
            <h1>Twoje centrum rozrywki</h1>
            <div class="gallery">
                <img src="gra10.jpg" alt="Grafika z gry">
                <img src="gra5.jpg" alt="Grafika z gry">
                <img src="gra1.jpg" alt="Grafika z gry">
            </div>
            <p>Zapraszamy do naszej wypożyczalni *gier konsolowych i komputerowych*, gdzie każdy znajdzie coś dla siebie! Oferujemy szeroką gamę tytułów, od najnowszych hitów po klasyczne produkcje, które wciąż cieszą się niesłabnącą popularnością. Dzięki nam możesz cieszyć się ulubionymi grami bez konieczności ich zakupu, co pozwala na oszczędność pieniędzy i przestrzeni. Nasza wypożyczalnia to idealne miejsce dla każdego miłośnika gier, niezależnie od wieku i preferencji.</p>
            <p>Nasza oferta jest dostosowana do potrzeb wszystkich graczy. Posiadamy _gry na różne platformy_, w tym PlayStation, Xbox, Nintendo oraz PC. Regularnie aktualizujemy nasz katalog, abyś zawsze miał dostęp do najnowszych premier. Niezależnie od tego, czy jesteś fanem dynamicznych strzelanek, epickich RPG, czy relaksujących gier strategicznych, u nas znajdziesz coś, co spełni Twoje oczekiwania.</p>
            <p>Wypożyczanie gier w naszej wypożyczalni jest proste i wygodne. Możesz dokonać *rezerwacji online* lub odwiedzić nas osobiście, gdzie nasi pracownicy chętnie doradzą i pomogą w wyborze odpowiednich tytułów. Gwarantujemy _atrakcyjne ceny i elastyczne warunki wypożyczenia_, dostosowane do Twoich potrzeb. Dołącz do grona naszych zadowolonych klientów i odkryj, jak wiele radości może przynieść świat gier!</p>
        </main>
        <footer>
            <p>Autor: <strong>Bartosz Bryniarski</strong></p>
            <p id="counter"></p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (onas.html)
  26. Krok 26: O nas: gwiazdki na strong, podkreślenia na em

    Kryteria:

    R.2.10 Na podstronie w bloku głównym znajdują się: trzy znaczniki <p> oraz przynajmniej jeden <strong> i jeden <em>

    ok. 3 min
    Polecenie z arkusza

    W skopiowanej treści fragmenty między gwiazdkami należy zapisać za pomocą znaczników semantycznych oznaczających tekst ważny, formatowany domyślnie jako pogrubiony. Fragmenty między znakami podkreślenia zapisać za pomocą znaczników semantycznych oznaczających tekst uwypuklony, formatowany domyślnie jako pochylony. Znaki gwiazdki i podkreślenia należy usunąć (ilustracja 4).

    Gwiazdki i podkreślenia to zapis Markdown: *…* → <strong>, _…_ → <em>, same znaki usuń. W edytorze z wyszukiwaniem wyrażeń regularnych da się to zrobić jednym poleceniem zamiany: wzorzec \*(.+?)\* na <strong>$1</strong> (R.2.10).

    Typowe błędy

    <b> i <i> wyglądają tak samo, ale nie są znacznikami semantycznymi z arkusza.

    onas.html HTML zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>O nas | PoGRAJmy!</title>
        <link rel="stylesheet" href="styl_gier.css">
        <script src="skrypty.js" defer></script>
    </head>
    <body>
        <header id="header1">
            <h2><a href="index.html">PoGRAJmy!</a></h2>
        </header>
        <header id="header2">
            <nav>
                <ul>
                    <li><a href="index.html">Strona główna</a></li>
                    <li><a href="onas.html">O nas</a></li>
                </ul>
            </nav>
        </header>
        <main>
            <h1>Twoje centrum rozrywki</h1>
            <div class="gallery">
                <img src="gra10.jpg" alt="Grafika z gry">
                <img src="gra5.jpg" alt="Grafika z gry">
                <img src="gra1.jpg" alt="Grafika z gry">
            </div>
            <p>Zapraszamy do naszej wypożyczalni <strong>gier konsolowych i komputerowych</strong>, gdzie każdy znajdzie coś dla siebie! Oferujemy szeroką gamę tytułów, od najnowszych hitów po klasyczne produkcje, które wciąż cieszą się niesłabnącą popularnością. Dzięki nam możesz cieszyć się ulubionymi grami bez konieczności ich zakupu, co pozwala na oszczędność pieniędzy i przestrzeni. Nasza wypożyczalnia to idealne miejsce dla każdego miłośnika gier, niezależnie od wieku i preferencji.</p>
            <p>Nasza oferta jest dostosowana do potrzeb wszystkich graczy. Posiadamy <em>gry na różne platformy</em>, w tym PlayStation, Xbox, Nintendo oraz PC. Regularnie aktualizujemy nasz katalog, abyś zawsze miał dostęp do najnowszych premier. Niezależnie od tego, czy jesteś fanem dynamicznych strzelanek, epickich RPG, czy relaksujących gier strategicznych, u nas znajdziesz coś, co spełni Twoje oczekiwania.</p>
            <p>Wypożyczanie gier w naszej wypożyczalni jest proste i wygodne. Możesz dokonać <strong>rezerwacji online</strong> lub odwiedzić nas osobiście, gdzie nasi pracownicy chętnie doradzą i pomogą w wyborze odpowiednich tytułów. Gwarantujemy <em>atrakcyjne ceny i elastyczne warunki wypożyczenia</em>, dostosowane do Twoich potrzeb. Dołącz do grona naszych zadowolonych klientów i odkryj, jak wiele radości może przynieść świat gier!</p>
        </main>
        <footer>
            <p>Autor: <strong>Bartosz Bryniarski</strong></p>
            <p id="counter"></p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (onas.html)
  27. Etap 3: Styl CSS

    Kroki 27-38 · po tym etapie masz 29 z 35 kryteriów (pkt)

    Krok 27: Zmienne z kolorami i krój czcionki

    Kryteria:

    R.4.1 domyślne formatowanie selektorów (*): krój czcionki "Segoe UI" - jako pierwszy i Tahoma

    ok. 2 min
    Polecenie z arkusza

    Domyślne formatowanie wszystkich selektorów: krój czcionki „Segoe UI”, a w przypadku jej braku „Tahoma”.

    Kolory z arkusza w zmiennych CSS (var(--link)) - nazwa mówi, do czego kolor służy, a nie jaki ma kod. Potem * z krojami w kolejności z arkusza (R.4.1).

    styl_gier.css CSS nowy plik
    :root {
        --link: #0077A2;
        --accent: #E30613;
    }
    
    * {
        font-family: "Segoe UI", Tahoma;
    }
    Podgląd strony po tym kroku (index.html)
  28. Krok 28: Nagłówek 1: szerokość

    ok. 1 min
    Polecenie z arkusza

    Dla bloku nagłówkowego 1: szerokość 40%.

    Selektor #header1.

    styl_gier.css CSS zmienione: 4 linie
    :root {
        --link: #0077A2;
        --accent: #E30613;
    }
    
    * {
        font-family: "Segoe UI", Tahoma;
    }
    
    #header1 {
        width: 40%;
    }
    Podgląd strony po tym kroku (index.html)
  29. Krok 29: Nagłówek 2: szerokość i wyrównanie

    Kryteria:

    R.4.9 blok nagłówkowy 2 - wyrównanie zawartości lub tekstu do prawej strony

    ok. 1 min
    Polecenie z arkusza

    Dla bloku nagłówkowego 2: szerokość 60%, wyrównanie zawartości bloku do prawej strony.

    text-align: right dosuwa menu do prawej (R.4.9).

    styl_gier.css CSS zmienione: 5 linii
    :root {
        --link: #0077A2;
        --accent: #E30613;
    }
    
    * {
        font-family: "Segoe UI", Tahoma;
    }
    
    #header1 {
        width: 40%;
    }
    
    #header2 {
        width: 60%;
        text-align: right;
    }
    Podgląd strony po tym kroku (index.html)
  30. Krok 30: Układ bloków zgodny z ilustracją 3

    Kryteria:

    R.3.1 Układ bloków po uruchomieniu przynajmniej jednej strony w przeglądarce jest zgodny z ilustracją 3 w arkuszu egzaminacyjnym (prawidłowo zastosowane właściwości CSS decydujące o układzie bloków na stronie, np. float i clear albo display flex, albo grid, albo position; żaden blok nie zachodzi na inne bloki - sprawdzić w inspektorze)

    ok. 3 min
    Polecenie z arkusza

    Podział zrealizowany za pomocą semantycznych znaczników języka HTML5 tak, aby po uruchomieniu w przeglądarce układ bloków był zgodny z ilustracją 3.

    Ciało strony jako kontener flex z zawijaniem (flex-wrap: wrap): bloki stają w wierszu, dopóki mieszczą się szerokością. Nagłówki 40% + 60% wypełniają pierwszy wiersz, a blok główny i stopka mają po 100%, więc każdy przechodzi do własnego wiersza - bez float i bez clear. align-items: center wyrównuje logo i menu do wspólnej osi w pionie, choć <h2> i lista mają różne marginesy.

    Szerokości zostają w width, jak w arkuszu - klucz R.4.2 sprawdza szerokość bloków nagłówkowych (R.3.1).

    Typowe błędy

    Bez flex-wrap: wrap flex ściska wszystkie cztery bloki w jednym wierszu - stopka stoi obok bloku głównego.

    styl_gier.css CSS zmienione: 11 linii
    :root {
        --link: #0077A2;
        --accent: #E30613;
    }
    
    * {
        font-family: "Segoe UI", Tahoma;
    }
    
    #header1 {
        width: 40%;
    }
    
    #header2 {
        width: 60%;
        text-align: right;
    }
    
    body {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
    }
    
    main,
    footer {
        width: 100%;
    }
    Podgląd strony po tym kroku (index.html)
  31. Krok 31: Lista bez punktorów

    Kryteria:

    R.4.6 lista punktowana - brak punktora (punktory niewidoczne na stronie)

    ok. 1 min
    Polecenie z arkusza

    Dla listy punktowanej: brak punktora.

    list-style: none (R.4.6).

    styl_gier.css CSS zmienione: 4 linie
    :root {
        --link: #0077A2;
        --accent: #E30613;
    }
    
    * {
        font-family: "Segoe UI", Tahoma;
    }
    
    #header1 {
        width: 40%;
    }
    
    #header2 {
        width: 60%;
        text-align: right;
    }
    
    body {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
    }
    
    main,
    footer {
        width: 100%;
    }
    
    ul {
        list-style: none;
    }
    Podgląd strony po tym kroku (index.html)
  32. Krok 32: Elementy listy w jednej linii

    Kryteria:

    R.4.7 element listy - wyświetlanie jako element liniowy (np. display: inline; lub inline-block )

    ok. 1 min
    Polecenie z arkusza

    Dla elementu listy: wyświetlanie jako element liniowy.

    display: inline - tu klucz (R.4.7) pyta wprost o wyświetlanie liniowe (inline albo inline-block), więc menu nie jest kontenerem flex, choć mogłoby.

    styl_gier.css CSS zmienione: 4 linie
    :root {
        --link: #0077A2;
        --accent: #E30613;
    }
    
    * {
        font-family: "Segoe UI", Tahoma;
    }
    
    #header1 {
        width: 40%;
    }
    
    #header2 {
        width: 60%;
        text-align: right;
    }
    
    body {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
    }
    
    main,
    footer {
        width: 100%;
    }
    
    ul {
        list-style: none;
    }
    
    li {
        display: inline;
    }
    Podgląd strony po tym kroku (index.html)
  33. Krok 33: Odnośniki: kolor bez podkreślenia

    Kryteria:

    R.4.5 styl odnośnika: kolor czcionki: #0077A2, brak podkreślenia

    ok. 1 min
    Polecenie z arkusza

    Dla odnośnika: brak podkreślenia, kolor czcionki #0077A2.

    Selektor a, kolor ze zmiennej (R.4.5).

    styl_gier.css CSS zmienione: 5 linii
    :root {
        --link: #0077A2;
        --accent: #E30613;
    }
    
    * {
        font-family: "Segoe UI", Tahoma;
    }
    
    #header1 {
        width: 40%;
    }
    
    #header2 {
        width: 60%;
        text-align: right;
    }
    
    body {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
    }
    
    main,
    footer {
        width: 100%;
    }
    
    ul {
        list-style: none;
    }
    
    li {
        display: inline;
    }
    
    a {
        text-decoration: none;
        color: var(--link);
    }
    Podgląd strony po tym kroku (index.html)
  34. Krok 34: Odnośniki w menu: marginesy wewnętrzne

    Kryteria:

    R.4.3 marginesy wewnętrzne (padding) : jedynie odnośnik w elemencie listy - 1em

    ok. 1 min
    Polecenie z arkusza

    Jedynie dla odnośnika znajdującego się w elemencie listy: marginesy wewnętrzne 1 em.

    Selektor potomka li a - logo w <h2> zostaje bez marginesów („jedynie”, R.4.3).

    Typowe błędy

    padding w regule a dotyka też logo.

    styl_gier.css CSS zmienione: 4 linie
    :root {
        --link: #0077A2;
        --accent: #E30613;
    }
    
    * {
        font-family: "Segoe UI", Tahoma;
    }
    
    #header1 {
        width: 40%;
    }
    
    #header2 {
        width: 60%;
        text-align: right;
    }
    
    body {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
    }
    
    main,
    footer {
        width: 100%;
    }
    
    ul {
        list-style: none;
    }
    
    li {
        display: inline;
    }
    
    a {
        text-decoration: none;
        color: var(--link);
    }
    
    li a {
        padding: 1em;
    }
    Podgląd strony po tym kroku (index.html)
  35. Krok 35: Nagłówek pierwszego stopnia na środku

    Kryteria:

    R.4.8 selektor h1 - wyrównanie tekstu do środka

    ok. 1 min
    Polecenie z arkusza

    Dla selektora nagłówka pierwszego stopnia: wyrównanie tekstu do środka.

    Selektor znacznika h1 (R.4.8).

    styl_gier.css CSS zmienione: 4 linie
    :root {
        --link: #0077A2;
        --accent: #E30613;
    }
    
    * {
        font-family: "Segoe UI", Tahoma;
    }
    
    #header1 {
        width: 40%;
    }
    
    #header2 {
        width: 60%;
        text-align: right;
    }
    
    body {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
    }
    
    main,
    footer {
        width: 100%;
    }
    
    ul {
        list-style: none;
    }
    
    li {
        display: inline;
    }
    
    a {
        text-decoration: none;
        color: var(--link);
    }
    
    li a {
        padding: 1em;
    }
    
    h1 {
        text-align: center;
    }
    Podgląd strony po tym kroku (index.html)
  36. Krok 36: Obraz: szerokość i marginesy

    Kryteria: ,

    R.4.2 szerokość: blok nagłówkowy 1 - 40%, blok nagłówkowy 2 - 60%, selektor img - 20em

    R.4.4 marginesy zewnętrzne (margin): obraz - 1em

    ok. 1 min
    Polecenie z arkusza

    Dla selektora obrazu: szerokość 20 em, marginesy zewnętrzne 1 em.

    Miniatury po 20 em; wysokość przeliczy się z proporcji (R.4.2, R.4.4).

    styl_gier.css CSS zmienione: 5 linii
    :root {
        --link: #0077A2;
        --accent: #E30613;
    }
    
    * {
        font-family: "Segoe UI", Tahoma;
    }
    
    #header1 {
        width: 40%;
    }
    
    #header2 {
        width: 60%;
        text-align: right;
    }
    
    body {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
    }
    
    main,
    footer {
        width: 100%;
    }
    
    ul {
        list-style: none;
    }
    
    li {
        display: inline;
    }
    
    a {
        text-decoration: none;
        color: var(--link);
    }
    
    li a {
        padding: 1em;
    }
    
    h1 {
        text-align: center;
    }
    
    img {
        width: 20em;
        margin: 1em;
    }
    Podgląd strony po tym kroku (index.html)
  37. Krok 37: Galeria: obrazy obok siebie, wyśrodkowane

    ok. 2 min
    Polecenie z arkusza

    Obrazy są wyświetlane obok siebie zgodnie z ilustracją 2 i 4.

    Galeria to kontener flex z zawijaniem: miniatury stają obok siebie i przechodzą do nowego wiersza, gdy brakuje miejsca, a justify-content: center wyśrodkowuje każdy wiersz - ostatni z dwiema miniaturami stoi na środku, jak na ilustracji 2. W przeciwieństwie do text-align flex nie zostawia odstępów ze spacji między znacznikami <img>.

    styl_gier.css CSS zmienione: 6 linii
    :root {
        --link: #0077A2;
        --accent: #E30613;
    }
    
    * {
        font-family: "Segoe UI", Tahoma;
    }
    
    #header1 {
        width: 40%;
    }
    
    #header2 {
        width: 60%;
        text-align: right;
    }
    
    body {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
    }
    
    main,
    footer {
        width: 100%;
    }
    
    ul {
        list-style: none;
    }
    
    li {
        display: inline;
    }
    
    a {
        text-decoration: none;
        color: var(--link);
    }
    
    li a {
        padding: 1em;
    }
    
    h1 {
        text-align: center;
    }
    
    img {
        width: 20em;
        margin: 1em;
    }
    
    .gallery {
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
    }
    Podgląd strony po tym kroku (index.html)
  38. Krok 38: Obrys obrazu pod kursorem

    Kryteria:

    R.4.10 gdy kursor znajdzie się na obrazie dodawany jest obrys: outline: 3px dashed #E30613

    ok. 1 min
    Polecenie z arkusza

    Gdy kursor znajdzie się na obrazie: dodawany jest obrys (outline) o szerokości 3 px linią kreskową koloru #E30613.

    outline nie zajmuje miejsca, więc miniatury nie drgają po najechaniu (R.4.10).

    styl_gier.css CSS zmienione: 4 linie
    :root {
        --link: #0077A2;
        --accent: #E30613;
    }
    
    * {
        font-family: "Segoe UI", Tahoma;
    }
    
    #header1 {
        width: 40%;
    }
    
    #header2 {
        width: 60%;
        text-align: right;
    }
    
    body {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
    }
    
    main,
    footer {
        width: 100%;
    }
    
    ul {
        list-style: none;
    }
    
    li {
        display: inline;
    }
    
    a {
        text-decoration: none;
        color: var(--link);
    }
    
    li a {
        padding: 1em;
    }
    
    h1 {
        text-align: center;
    }
    
    img {
        width: 20em;
        margin: 1em;
    }
    
    .gallery {
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
    }
    
    img:hover {
        outline: 3px dashed var(--accent);
    }
    Podgląd strony po tym kroku (index.html)
  39. Etap 4: JavaScript

    Kroki 39-44 · po tym etapie masz 35 z 35 kryteriów (pkt)

    Krok 39: Plik skrypty.js, funkcja licznik i zdarzenie load

    Kryteria:

    R.5.3 Na przynajmniej jednej stronie w momencie załadowania witryny wywoływana jest funkcja licznik

    ok. 2 min
    Polecenie z arkusza

    Plik skrypty.js powinien zawierać funkcję licznik napisaną w języku JavaScript. Funkcja jest wywoływana w momencie załadowania się stron index.html oraz onas.html.

    W skrypty.js stała STORAGE_KEY z nazwą klucza w pamięci (jedno miejsce, jeśli kiedyś trzeba ją zmienić), pusta funkcja licznik (nazwa z arkusza) i window.addEventListener('load', licznik) - funkcja ruszy po wczytaniu strony. Funkcję przekazuje się bez nawiasów: z nawiasami wykonałaby się od razu.

    Obie strony podpinają ten sam plik, więc nie trzeba dopisywać onload w każdym HTML-u - trzecia podstrona dostanie licznik sama (R.5.3).

    Typowe błędy

    addEventListener('load', licznik()) z nawiasami wywołuje funkcję od razu, przy wczytaniu skryptu, a do zdarzenia podpina jej wynik (undefined) - przy skrypcie w <head> bez defer akapitu jeszcze nie ma i skrypt kończy się błędem.

    skrypty.js JavaScript nowy plik
    const STORAGE_KEY = 'licznik';
    
    function licznik() {
    }
    
    window.addEventListener('load', licznik);
    Podgląd strony po tym kroku (index.html)
  40. Krok 40: Odczyt licznika w bloku try

    Kryteria: ,

    R.5.1 Skrypt w języku JavaScript zawiera przynajmniej jedną poprawną składniowo instrukcję wynikającą z treści zadania. Skrypt zapisany w pliku skrypty.js

    R.5.2 Zastosowana przynajmniej jedna zmienna lub funkcja oraz nazewnictwo jest w języku polskim lub angielskim i odzwierciedla cel zastosowania

    ok. 3 min
    Polecenie z arkusza

    Wykorzystuje obiekt localStorage do przechowania licznika wyświetleń strony.

    localStorage.getItem (tabela 1) zwraca zapisany napis albo null przy pierwszym wejściu. Odczyt stoi w bloku try … catch: w trybie prywatnym z blokadą, przy wyłączonych danych witryn i w ramce tego podglądu samo sięgnięcie po localStorage rzuca wyjątek. Bez try skrypt by się przerwał i akapit zostałby pusty; z nim zmienna visits zostaje równa 1. Nazwy zmiennych po angielsku mówią, co przechowują (R.5.1, R.5.2).

    skrypty.js JavaScript zmienione: 6 linii
    const STORAGE_KEY = 'licznik';
    
    function licznik() {
        let visits = 1;
        try {
            const saved = localStorage.getItem(STORAGE_KEY);
        } catch (error) {
            // pamięć niedostępna (np. tryb prywatny z blokadą) - zostaje pierwsze wejście
        }
    }
    
    window.addEventListener('load', licznik);
    Podgląd strony po tym kroku (index.html)
  41. Krok 41: Zwiększenie licznika o 1

    Kryteria:

    R.5.5 Przy pierwszym uruchomieniu witryny licznik odwiedzin wyświetla wartość 1

    ok. 2 min
    Polecenie z arkusza

    Po każdym odwiedzeniu strony zwiększa liczbę jej wyświetleń o 1.

    localStorage przechowuje napisy, a "5" + 1 to "51". Number(saved) zamienia napis na liczbę: null daje 0, więc pierwsze wejście to 1 (R.5.5). || 0 ratuje sytuację, gdy w pamięci leży coś, co nie jest liczbą: Number("abc") to NaN, a NaN || 0 to 0.

    Typowe błędy

    saved + 1 bez Number skleja napisy: 1, 11, 111.

    skrypty.js JavaScript zmienione: 1 linia
    const STORAGE_KEY = 'licznik';
    
    function licznik() {
        let visits = 1;
        try {
            const saved = localStorage.getItem(STORAGE_KEY);
            visits = (Number(saved) || 0) + 1;
        } catch (error) {
            // pamięć niedostępna (np. tryb prywatny z blokadą) - zostaje pierwsze wejście
        }
    }
    
    window.addEventListener('load', licznik);
    Podgląd strony po tym kroku (index.html)
  42. Krok 42: Zapis nowej wartości

    Kryteria:

    R.5.6 Każde kolejne uruchomienie witryny zwiększa licznik odwiedzin o 1, co jest wyświetlane w witrynie

    ok. 1 min
    Polecenie z arkusza

    Wykorzystuje obiekt localStorage do przechowania licznika wyświetleń strony.

    localStorage.setItem(STORAGE_KEY, visits) nadpisuje wartość pod tym samym kluczem - przy następnym wejściu odczyt da o 1 więcej (R.5.6). Podgląd w przeglądarce: narzędzia deweloperskie → Aplikacja → Pamięć lokalna.

    skrypty.js JavaScript zmienione: 1 linia
    const STORAGE_KEY = 'licznik';
    
    function licznik() {
        let visits = 1;
        try {
            const saved = localStorage.getItem(STORAGE_KEY);
            visits = (Number(saved) || 0) + 1;
            localStorage.setItem(STORAGE_KEY, visits);
        } catch (error) {
            // pamięć niedostępna (np. tryb prywatny z blokadą) - zostaje pierwsze wejście
        }
    }
    
    window.addEventListener('load', licznik);
    Podgląd strony po tym kroku (index.html)
  43. Krok 43: Napis z liczbą wejść w stopce

    Kryteria:

    R.5.4 W skrypcie modyfikowana jest zawartość paragrafu w stopce

    ok. 2 min
    Polecenie z arkusza

    W paragrafie znajdującym się w stopce witryny wyświetla napis „Liczba wejść na stronę: X”, gdzie X jest liczbą wyświetleń strony.

    Poza blokiem try, więc wykona się zawsze: querySelector('#counter') znajduje akapit w stopce, a textContent wpisuje zwykły tekst złożony szablonem tekstowym `Liczba wejść na stronę: ${visits}` (R.5.4). Podgląd pokazuje „Liczba wejść na stronę: 1” - ramka podglądu nie ma dostępu do pamięci, więc zadziałał catch. W przeglądarce odśwież stronę albo przejdź na „O nas”: licznik rośnie, bo obie strony używają tego samego klucza.

    skrypty.js JavaScript zmienione: 1 linia
    const STORAGE_KEY = 'licznik';
    
    function licznik() {
        let visits = 1;
        try {
            const saved = localStorage.getItem(STORAGE_KEY);
            visits = (Number(saved) || 0) + 1;
            localStorage.setItem(STORAGE_KEY, visits);
        } catch (error) {
            // pamięć niedostępna (np. tryb prywatny z blokadą) - zostaje pierwsze wejście
        }
        document.querySelector('#counter').textContent = `Liczba wejść na stronę: ${visits}`;
    }
    
    window.addEventListener('load', licznik);
    Podgląd strony po tym kroku (index.html)
  44. Krok 44: Licznik na stronie O nas

    ok. 1 min
    Polecenie z arkusza

    Funkcja jest wywoływana w momencie załadowania się stron index.html oraz onas.html.

    Druga strona ma ten sam <script src="skrypty.js" defer> i akapit counter - licznik działa i tu, bez żadnej zmiany w HTML. Strona jak na ilustracji 4.

    Podgląd strony po tym kroku (onas.html)
  45. Etap 5: Porównanie z wersją podstawową

    Krok 45 · po tym etapie masz 35 z 35 kryteriów (pkt)

    Krok 45: Co jest inaczej i którą wersję wybrać na egzaminie

    ok. 2 min

    Obie wersje dają komplet 35 punktów. Różnice:

    wersja podstawowawersja nowoczesna
    układfloat: left na nagłówkach + clear: bothbody jako flex z zawijaniem
    galeriatext-align: center na obrazach liniowych.gallery jako flex: zawijanie i wyśrodkowanie
    wywołanie<body onload="licznik()"> w każdym plikuaddEventListener('load', licznik) w skrypcie
    odczytwarunek == null i Number()(Number(saved) \|\| 0) + 1 w try … catch
    wpisinnerHTML i sklejanie +textContent i szablon tekstowy

    Klucz wymusza width przy nagłówkach (R.4.2 pyta o szerokość bloków) i liniowe elementy listy (R.4.7) - obie wersje je mają. Na egzaminie obie zajmują podobnie dużo czasu; onload z tabeli 2 arkusza łatwiej sprawdzić w kodzie wzrokiem, a try … catch chroni przed jedyną realną awarią tego skryptu - przeglądarką bez dostępu do pamięci. Licznik w localStorage liczy wejścia jednej przeglądarki, nie wszystkich gości - prawdziwy licznik odwiedzin wymaga serwera i bazy.

    Podgląd strony bez zmian - taki jak po kroku 44.

  46. Etap 6: Oddanie pracy

    Krok 46 · po tym etapie masz 35 z 35 kryteriów (pkt)

    Krok 46: Plik przeglądarka.txt i nagranie płyty

    ok. 5 min
    Polecenie z arkusza

    Po zakończeniu pracy utwórz plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowana była poprawność działania witryny. Umieść go w folderze z numerem zdającego. Nagraj płytę z rezultatami pracy.

    W folderze z numerem zdającego: index.html, onas.html, gra1.jpg … gra10.jpg, oryginalny gra10.png, kwerendy.txt, skrypty.js, styl_gier.css, import.png, kw1.jpg … kw4.jpg, przeglądarka.txt. Płytę sprawdź po nagraniu.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

    Podgląd strony bez zmian - taki jak po kroku 44.

Podgląd

To jedno z możliwych rozwiązań. Egzaminator ocenia spełnienie kryteriów z klucza odpowiedzi, a nie zgodność z tym kodem - inna, poprawna droga też daje punkty.

Autor rozwiązania: . Licencja CC BY-NC 4.0 - kopiowanie i przeróbki do celów niekomercyjnych, z podaniem autora i źródła (link do tej strony) (zasady wykorzystania). Treść arkusza i klucza oceniania pochodzi z CKE.