Przejdź do głównej treści
INF.03-01-25.01-SGStyczeń 2025 · 48 kroków · ok. 94 min · 40 kryteriów z klucza

Rozwiązanie krok po kroku: Witryna firmy szkoleniowej (Nowoczesny kod (grid, osobny skrypt))

To drugi sposób rozwiązania tego samego arkusza: baza obuwie z czterema zapytaniami, baner wycięty ze zdjęcia klawiatury, strony index.html z tabelą kursów i raty.html z kalkulatorem rat oraz style w style.css. Obie wersje spełniają wszystkie 40 kryteriów klucza - różni je sposób pisania kodu, nie wynik.

Czym ta wersja różni się od podstawowej:

  • kolory z arkusza w zmiennych CSS (--color-dark, --color-light) - każdy kolor jest wpisany raz,
  • tabela z częścią nagłówkową <thead> i treścią <tbody>, odnośniki menu reagują także na klawiaturę (:focus-visible) i nie przesuwają się, gdy pojawia się ramka,
  • kalkulator ułożony siatką CSS (display: grid) zamiast znaczników <br>, pola wyboru razem z etykietami w znaczniku <label>,
  • skrypt w osobnym pliku raty.js dołączonym z defer, podpięty przez addEventListener - w HTML nie ma onclick,
  • ceny kursów w obiekcie zamiast osobnych warunków, sprawdzenie liczby rat i zaznaczonych kursów od pierwszej linii oraz kwoty w polskim formacie (2666,67 zamiast 2666.6666666666665).

Kroki nadal idą zdanie po zdaniu za treścią arkusza. Baza i zdjęcie pochodzą z prawdziwego archiwum pliki10, zapytania są sprawdzone na MariaDB, a kalkulator w podglądzie działa naprawdę - skrypt jest też sprawdzony w prawdziwej przeglądarce Chrome (oba kursy, jeden kurs, żaden, puste i ujemne pole liczby rat).

Jak liczą się punkty. Klucz ma 40 kryteriów (R.1.1 - R.5.8), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 30 punktów. Przy każdym kroku jest napisane, które kryteria spełnia; egzaminator ocenia spełnienie kryteriów z klucza, nie zgodność z tym kodem.

  1. Etap 1: Baza danych

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

    Krok 1: Baza danych obuwie

    ok. 2 min
    Polecenie z arkusza

    Utwórz bazę danych o nazwie obuwie, z zestawem polskich znaków (np. utf8_unicode_ci).

    Archiwum pliki10.7z ma hasło KuRsyKompuTerow3& (z ampersandem na końcu); zawiera baza.sql i klawiatura.jpg. W phpMyAdmin: Nowa, nazwa obuwie i porównywanie z polskimi znakami - arkusz podaje przykład utf8_unicode_ci, a dziś częściej wybiera się utf8mb4_polish_ci (utf8mb4 mieści każdy znak Unicode, polish sortuje „ł” po „l”).

    Tabele z baza.sql mają zestaw znaków i porównywanie zapisane we własnej definicji (utf8_polish_ci), więc wybór dla bazy ich nie zmienia - dziedziczyłyby go dopiero tabele zakładane później bez własnego ustawienia.

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

    ok. 2 min
    Polecenie z arkusza

    Do utworzonej bazy zaimportuj tabele z pliku baza.sql z rozpakowanego archiwum.

    Zaznaczona baza obuwie, potem Import → baza.sql → Wykonaj. Powstają trzy tabele z ilustracji 1: kategorie, buty (model, kategoria, nazwa, cena) i produkt (kolor, materiał, wysokość buta). Relacje: buty.id_kat → kategorie.id_kat i produkt.model → buty.model.

    Typowe błędy

    Import bez zaznaczonej bazy obuwie kończy się błędem „Nie wybrano bazy danych” - plik nie zawiera polecenia USE.

  3. Krok 3: Zrzut ekranu import.jpg

    Kryteria:

    R.1.1 Wykonany import tabel do bazy danych obuwie , co jest udokumentowane w pliku import w formacie JPEG

    ok. 2 min
    Polecenie z arkusza

    Wykonaj zrzut ekranu po imporcie. Zapisz zrzut w formacie JPEG 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.

    Print Screen, wklejenie do edytora grafiki i zapis jako import.jpg - import w JPEG, a zrzuty zapytań w PNG. Na zrzucie widać komunikat o udanym imporcie i trzy tabele w drzewie bazy.

    Typowe błędy

    Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany (uwaga w kluczu przy R.1).

  4. Krok 4: Zapytanie 1: kolor i materiał wysokich butów

    Kryteria: ,

    R.1.2 Zapisany plik kwerendy.txt zawierający co najmniej jedno zapytanie SQL, wynikające z treści zadania

    R.1.3 Wykonane zapytanie 1 wybierające jedynie kolor i materiał produktów, których wysokość buta jest większa niż 10. W pliku z kwerendami lub na zrzucie istnieje zapis np. SELECT kolor, material FROM produkt WHERE wysokosc_buta > 10; oraz wynik działania udokumentowany zrzutem, na którym widoczne są dokładnie 2 wiersze dla koloru brązowego i szarego

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 1: wybierające jedynie kolor i materiał produktów, których wysokość buta jest większa niż 10.

    Każda klauzula w osobnej linii - przy dłuższych zapytaniach od razu widać, co jest wybierane, skąd i z jakim warunkiem:

    • SELECT kolor, material - „jedynie kolor i materiał”, dwie kolumny zamiast *,
    • FROM produkt - tabela z tymi polami,
    • WHERE wysokosc_buta > 10 - „większa niż 10”, ostra nierówność.

    Wynik: dwa wiersze - brązowy i szary, jak w kluczu. Zapytanie trafia do kwerendy.txt, zrzut do kw1.png.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT kolor, material
    FROM produkt
    WHERE wysokosc_buta > 10;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: buty z nazwą kategorii

    Kryteria:

    R.1.4 Wykonane zapytanie 2 wybierające jedynie nazwę i cenę buta oraz odpowiadającą im nazwę kategorii. W pliku z kwerendami lub na zrzucie istnieje zapis np. SELECT nazwa, cena, nazwa_kat FROM buty JOIN kategorie USING(id_kat); (możliwe też porównanie kluczy po ON lub WHERE ) oraz wynik działania udokumentowany zrzutem, na którym widoczne są dokładnie 4 rekordy dla nazw kategorii Półbuty, Trzewiki, Trampki, Obuwie sportowe

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie nazwę i cenę buta oraz odpowiadającą im nazwę kategorii. Należy posłużyć się relacją.

    Tabele dostają krótkie aliasy: buty AS b, kategorie AS k. Każda kolumna ma przed sobą alias tabeli, więc od razu widać, skąd pochodzi, a dopisanie później kolumny o tej samej nazwie w drugiej tabeli nie zepsuje zapytania.

    • SELECT b.nazwa, b.cena, k.nazwa_kat - nazwa i cena buta, nazwa kategorii,
    • JOIN kategorie AS k ON k.id_kat = b.id_kat - warunek relacji zapisany wprost; klucz uznaje też USING(id_kat).

    Wynik: cztery wiersze dla kategorii Półbuty, Trzewiki, Trampki i Obuwie sportowe. Zrzut: kw2.png.

    Typowe błędy

    FROM buty, kategorie bez warunku złączenia daje iloczyn kartezjański: 16 wierszy zamiast 4.

    kwerendy.txt Tekst zmienione: 5 linii
    -- Zapytanie 1
    SELECT kolor, material
    FROM produkt
    WHERE wysokosc_buta > 10;
    
    -- Zapytanie 2
    SELECT b.nazwa, b.cena, k.nazwa_kat
    FROM buty AS b
    JOIN kategorie AS k ON k.id_kat = b.id_kat;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: konto Marek

    Kryteria:

    R.1.5 Wykonane zapytanie 3 tworzące konto użytkownika Marek na localhost z hasłem M@reK W pliku z kwerendami lub na zrzucie istnieje zapis np. CREATE USER 'Marek'@'localhost' IDENTIFIED BY 'M@reK'; oraz wynik działania udokumentowany zrzutem, na którym jest widoczny komunikat o poprawnie wykonanym zapytaniu, dopuszczalny jest błąd informujący o niewybraniu bazy

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 3: tworzące konto użytkownika Marek na localhost z hasłem M@reK.

    Konto to para nazwa i host: 'Marek'@'localhost' może łączyć się tylko z tego samego komputera. Hasło po IDENTIFIED BY, z zachowaniem wielkości liter. Wynik to komunikat o poprawnym wykonaniu; klucz dopuszcza też błąd o niewybranej bazie. Zrzut: kw3.png.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT kolor, material
    FROM produkt
    WHERE wysokosc_buta > 10;
    
    -- Zapytanie 2
    SELECT b.nazwa, b.cena, k.nazwa_kat
    FROM buty AS b
    JOIN kategorie AS k ON k.id_kat = b.id_kat;
    
    -- Zapytanie 3
    CREATE USER 'Marek'@'localhost' IDENTIFIED BY 'M@reK';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: przeglądanie i aktualizacja tabeli produkt

    Kryteria:

    R.1.6 Wykonane zapytanie 4 nadające dla konta Marek prawa jedynie do przeglądania i aktualizacji danych jedynie w bazie danych obuwie, w tabeli produkt. W pliku z kwerendami lub na zrzucie istnieje zapis np. GRANT SELECT, UPDATE ON obuwie.produkt TO 'Marek'@'localhost'; oraz wynik działania udokumentowany zrzutem, na którym jest widoczny komunikat o poprawnie wykonanym zapytaniu

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: nadające kontu Marek prawa jedynie do przeglądania i aktualizacji danych jedynie w bazie danych obuwie, w tabeli produkt.

    Zasada najmniejszych uprawnień: konto dostaje dokładnie to, czego potrzebuje. SELECT (przeglądanie) i UPDATE (aktualizacja), tylko na obuwie.produkt, dla tego samego konta 'Marek'@'localhost'. Zrzut z komunikatem: kw4.png.

    Typowe błędy

    ON obuwie.* daje prawa do wszystkich tabel bazy, a GRANT ALL także do usuwania - arkusz mówi „jedynie” dwa razy.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT kolor, material
    FROM produkt
    WHERE wysokosc_buta > 10;
    
    -- Zapytanie 2
    SELECT b.nazwa, b.cena, k.nazwa_kat
    FROM buty AS b
    JOIN kategorie AS k ON k.id_kat = b.id_kat;
    
    -- Zapytanie 3
    CREATE USER 'Marek'@'localhost' IDENTIFIED BY 'M@reK';
    
    -- Zapytanie 4
    GRANT SELECT, UPDATE ON obuwie.produkt TO 'Marek'@'localhost';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strony HTML

    Kroki 8-29 · po tym etapie masz 21 z 40 kryteriów (pkt)

    Krok 8: Kadr klawiatura.jpg: 1000 × 100 px

    Kryteria:

    R.2.1 Grafika baner.png ma szerokość 1000 px i wysokość 100 px, jest skadrowana tak, że po lewej stronie klawiatury nie widać cyfry 8, a po prawej stronie widać jedynie klawisze Insert i Delete

    ok. 4 min
    Polecenie z arkusza

    Na potrzeby witryny internetowej należy przygotować grafikę baner.png utworzoną na podstawie pliku klawiatura.jpg, który należy wykadrować do szerokości 1000 px i wysokości 100 px, zgodnie z kadrem przedstawionym na ilustracji 2.

    Zdjęcie ma 1500 × 300 px. W GIMP-ie Zaznaczenie prostokątne z opcją Stały: Rozmiar 1000 × 100 - zaznaczenie ma wtedy zawsze właściwy rozmiar i przesuwa się je tylko na miejsce z ilustracji 2 (około 37 px od lewej i 51 px od góry). Potem Obraz → Przytnij do zaznaczenia. Klucz sprawdza kadr po klawiszach: z lewej nie widać cyfry 8, z prawej widać tylko Insert i Delete (R.2.1).

    Typowe błędy

    Skalowanie zamiast kadrowania daje 1000 × 100, ale ze ściśniętą całą klawiaturą - kryterium R.2.1 nie jest spełnione.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 8
  9. Krok 9: Napis „Kursy komputerowe” i zapis baner.png

    Kryteria:

    R.2.2 W grafice jest widoczny napis "Kursy komputerowe" zapisany czcionką bezszeryfową, pochyloną, wypełnioną kolorem białym

    ok. 4 min
    Polecenie z arkusza

    Na środku umieszczony napis "Kursy komputerowe" czcionką Arial pochyloną i pogrubioną, o rozmiarze 60, wypełnioną kolorem białym.

    Narzędzie Tekst: Arial Bold Italic, rozmiar 60 px, kolor ffffff. Warstwę tekstu ustawia na środku narzędzie Wyrównanie (względem obrazu, środek w poziomie i w pionie). Plik → Eksportuj jako baner.png (R.2.2).

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

    Kryteria:

    R.2.3 Witryna internetowa zapisana w plikach index.html i raty.html oraz zapisany jawnie standard kodowania polskich znaków, deklaracja HTML5 <!DOCTYPE HTML>, zadeklarowany język witryny: polski np. <html lang="pl"> oraz nadany tytuł strony "Kursy komputerowe". Strona zawiera sekcje head i body

    ok. 2 min
    Polecenie z arkusza

    Cechy witryny: Składa się z podstron o nazwach index.html, raty.html. Cechy wspólne dla stron: Zapisane w języku HTML5.

    Najpierw powstaje cała strona index.html, a raty.html będzie jej kopią z innym blokiem głównym. <!DOCTYPE html> włącza w przeglądarce tryb standardów HTML5.

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

    Kryteria:

    R.2.3 Witryna internetowa zapisana w plikach index.html i raty.html oraz zapisany jawnie standard kodowania polskich znaków, deklaracja HTML5 <!DOCTYPE HTML>, zadeklarowany język witryny: polski np. <html lang="pl"> oraz nadany tytuł strony "Kursy komputerowe". Strona zawiera sekcje head i body

    ok. 1 min
    Polecenie z arkusza

    Zadeklarowany polski język zawartości witryny.

    lang="pl" w <html>: czytnik ekranu czyta stronę polską wymową, a przeglądarka nie proponuje tłumaczenia.

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

    Kryteria:

    R.2.3 Witryna internetowa zapisana w plikach index.html i raty.html oraz zapisany jawnie standard kodowania polskich znaków, deklaracja HTML5 <!DOCTYPE HTML>, zadeklarowany język witryny: polski np. <html lang="pl"> oraz nadany tytuł strony "Kursy komputerowe". Strona zawiera sekcje head i body

    ok. 1 min
    Polecenie z arkusza

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

    <meta charset="UTF-8"> jako pierwszy element <head> - przeglądarka musi znać kodowanie, zanim przeczyta tytuł z polskimi literami.

    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)
  13. Krok 13: Tytuł strony i viewport

    Kryteria:

    R.2.3 Witryna internetowa zapisana w plikach index.html i raty.html oraz zapisany jawnie standard kodowania polskich znaków, deklaracja HTML5 <!DOCTYPE HTML>, zadeklarowany język witryny: polski np. <html lang="pl"> oraz nadany tytuł strony "Kursy komputerowe". Strona zawiera sekcje head i body

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony widoczny na karcie przeglądarki: „Kursy komputerowe”.

    <title> to napis na karcie. <meta name="viewport"> każe telefonowi pokazać stronę w jego prawdziwej szerokości zamiast pomniejszać ją jak ekran komputera - arkusz tego nie wymaga, ale bez tej linii żadna strona nie wygląda dobrze na telefonie.

    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>Kursy komputerowe</title>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  14. Krok 14: Podpięcie arkusza stylów

    Kryteria:

    R.3.6 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie style.css formatowanie CSS pochodzi jedynie z tego arkusza. Uwaga: kryterium to nie jest spełnione również, gdy zdający źle przypisał co najmniej jeden selektor do bloku (np. kropka zamiast #)

    ok. 1 min
    Polecenie z arkusza

    Arkusz stylów w pliku o nazwie style.css prawidłowo połączony z kodem strony.

    <link> jest znacznikiem pustym - w HTML5 bez ukośnika />. Nazwa w tym arkuszu: style.css, z „e” na końcu.

    Typowe błędy

    styl.css zamiast style.css odcina wszystkie style - kryterium R.3.6, a rezultat R.4 jest wtedy oceniany tylko z kodu.

    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>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  15. Krok 15: Bloki: nagłówek, menu, blok główny, stopka

    Kryteria:

    R.2.4 Zdefiniowany układ strony dzielący ją na bloki: nagłówkowy, menu, główny i stopki przy pomocy semantycznych znaczników sekcji języka HTML5 zgodnie z ich znaczeniem, w tym do części nagłówkowej - header, do stopki - footer. Dopuszcza się dodatkowe użycie bloków div lub section

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: nagłówkowy, poniżej menu, poniżej główny, na dole stopka. Podział zrealizowany za pomocą semantycznych znaczników sekcji języka HTML5 tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z ilustracją 3.

    <header>, <nav>, <main> i <footer> - każdy znacznik mówi, czym jest blok (R.2.4). Bloki stoją jeden pod drugim w kolejności z ilustracji 3, a to jest zwykły układ dokumentu: przeglądarka sama stawia elementy blokowe pod sobą, więc na tej stronie ani siatka, ani float nie są potrzebne - siatka przyda się dopiero przy kalkulatorze.

    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>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
        </header>
        <nav>
        </nav>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  16. Krok 16: Nagłówek: baner

    Kryteria:

    R.2.6 W bloku nagłówkowym umieszczony obraz z pliku baner.png z tekstem alternatywnym "kursy komputerowe"

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku nagłówkowego: obraz baner.png z tekstem alternatywnym „kursy komputerowe”.

    <img> z tekstem alternatywnym z arkusza (R.2.6). Tekst w alt powtarza napis z banera - czytnik ekranu przeczyta go zamiast obrazu.

    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>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <img src="baner.png" alt="kursy komputerowe">
        </header>
        <nav>
        </nav>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  17. Krok 17: Menu: trzy odnośniki

    Kryteria:

    R.3.2 Wybranie odnośnika "Strona główna" otwiera stronę index.html, "Koszt rat" otwiera raty.html , „Nasz partner” otwiera "https://moje-szkolenia.pl/"

    ok. 2 min
    Polecenie z arkusza

    Zawartość menu: Odnośnik o treści „Strona główna” prowadzący do strony index.html. Odnośnik o treści „Koszt rat” prowadzący do strony raty.html. Odnośnik o treści „Nasz partner” prowadzący do strony https://moje-szkolenia.pl/.

    Do własnych podstron prowadzą adresy względne, do serwisu partnera pełny adres z https:// (R.3.2). Atrybut aria-current="page" przy odnośniku do bieżącej strony mówi czytnikowi ekranu „jesteś tutaj”; na raty.html przejdzie na „Koszt rat”.

    Typowe błędy

    Adres partnera bez https:// przeglądarka traktuje jak plik w bieżącym folderze - odnośnik prowadzi donikąd.

    index.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>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <img src="baner.png" alt="kursy komputerowe">
        </header>
        <nav>
            <a href="index.html" aria-current="page">Strona główna</a>
            <a href="raty.html">Koszt rat</a>
            <a href="https://moje-szkolenia.pl/">Nasz partner</a>
        </nav>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  18. Krok 18: Stopka

    Kryteria:

    R.2.5 W bloku głównym umieszczony przynajmniej jeden <h3>: "Kursy komputerowe - programowanie" lub "Adres do korespondencji" (główna), lub "Oblicz miesięczną ratę" (raty); w stopce umieszczony paragraf z numerem zdającego

    ok. 1 min
    Polecenie z arkusza

    Zawartość stopki: paragraf o treści „Autor strony: ”, dalej wstawiony numer zdającego.

    Akapit <p> w <footer>. Na egzaminie po dwukropku wpisuje się 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>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <img src="baner.png" alt="kursy komputerowe">
        </header>
        <nav>
            <a href="index.html" aria-current="page">Strona główna</a>
            <a href="raty.html">Koszt rat</a>
            <a href="https://moje-szkolenia.pl/">Nasz partner</a>
        </nav>
        <main>
        </main>
        <footer>
            <p>Autor strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  19. Krok 19: Blok główny: nagłówek trzeciego stopnia

    Kryteria:

    R.2.5 W bloku głównym umieszczony przynajmniej jeden <h3>: "Kursy komputerowe - programowanie" lub "Adres do korespondencji" (główna), lub "Oblicz miesięczną ratę" (raty); w stopce umieszczony paragraf z numerem zdającego

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku głównego strony index.html: Nagłówek trzeciego stopnia o treści „Kursy komputerowe - programowanie”.

    Trzeci stopień to <h3>.

    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>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <img src="baner.png" alt="kursy komputerowe">
        </header>
        <nav>
            <a href="index.html" aria-current="page">Strona główna</a>
            <a href="raty.html">Koszt rat</a>
            <a href="https://moje-szkolenia.pl/">Nasz partner</a>
        </nav>
        <main>
            <h3>Kursy komputerowe - programowanie</h3>
        </main>
        <footer>
            <p>Autor strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  20. Krok 20: Tabela kursów: część nagłówkowa i treść

    Kryteria:

    R.2.7 Na stronie głównej w bloku głównym umieszczona tabela o 3 kolumnach i 3 wierszach, pierwszy wiersz zawiera komórki nagłówkowe, zastosowane znaczniki <table>, <tr>, <td>, <th>

    ok. 3 min
    Polecenie z arkusza

    Tabela składająca się z 3 kolumn i 3 wierszy przedstawiona na ilustracji 4, pierwszy wiersz zawiera komórki nagłówkowe.

    Te same trzy wiersze co w wersji podstawowej, ale podzielone na części: <thead> z wierszem komórek nagłówkowych i <tbody> z danymi. Przy wydruku długiej tabeli przeglądarka powtarza <thead> na każdej stronie, a CSS i skrypty mogą osobno wskazać nagłówek i dane. Atrybut scope="col" mówi czytnikowi ekranu, że „Cena” opisuje kolumnę - przy każdej liczbie przeczyta, czego dotyczy. Wygląd się nie zmienia, klucz liczy wiersze <tr> i znaczniki <th>/<td> (R.2.7).

    index.html HTML zmienione: 21 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <img src="baner.png" alt="kursy komputerowe">
        </header>
        <nav>
            <a href="index.html" aria-current="page">Strona główna</a>
            <a href="raty.html">Koszt rat</a>
            <a href="https://moje-szkolenia.pl/">Nasz partner</a>
        </nav>
        <main>
            <h3>Kursy komputerowe - programowanie</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Nazwa</th>
                        <th scope="col">Liczba godzin</th>
                        <th scope="col">Cena</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>Kurs React.js</td>
                        <td>220</td>
                        <td>5000</td>
                    </tr>
                    <tr>
                        <td>Kurs JavaScript</td>
                        <td>150</td>
                        <td>3000</td>
                    </tr>
                </tbody>
            </table>
        </main>
        <footer>
            <p>Autor strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  21. Krok 21: Nagłówek „Adres do korespondencji”

    Kryteria:

    R.2.5 W bloku głównym umieszczony przynajmniej jeden <h3>: "Kursy komputerowe - programowanie" lub "Adres do korespondencji" (główna), lub "Oblicz miesięczną ratę" (raty); w stopce umieszczony paragraf z numerem zdającego

    ok. 1 min
    Polecenie z arkusza

    Nagłówek trzeciego stopnia o treści „Adres do korespondencji”.

    Drugi <h3> w bloku głównym.

    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>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <img src="baner.png" alt="kursy komputerowe">
        </header>
        <nav>
            <a href="index.html" aria-current="page">Strona główna</a>
            <a href="raty.html">Koszt rat</a>
            <a href="https://moje-szkolenia.pl/">Nasz partner</a>
        </nav>
        <main>
            <h3>Kursy komputerowe - programowanie</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Nazwa</th>
                        <th scope="col">Liczba godzin</th>
                        <th scope="col">Cena</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>Kurs React.js</td>
                        <td>220</td>
                        <td>5000</td>
                    </tr>
                    <tr>
                        <td>Kurs JavaScript</td>
                        <td>150</td>
                        <td>3000</td>
                    </tr>
                </tbody>
            </table>
            <h3>Adres do korespondencji</h3>
        </main>
        <footer>
            <p>Autor strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  22. Krok 22: Lista z adresem i odnośnikiem pocztowym

    Kryteria: ,

    R.2.8 Na stronie głównej w bloku głównym umieszczona jedna lista punktowana z trzema elementami, zastosowane znaczniki <ul> i <li>

    R.3.3 Na stronie umieszczony odnośnik pocztowy „skontaktuj się” połączony z adresem mailto:[email protected]

    ok. 2 min
    Polecenie z arkusza

    Lista punktowana (nieuporządkowana) wypełniona zawartością: „Adres: Katowice, ul. Mariacka 5”, „Telefon: 32 888 88 88” oraz odnośnik pocztowy o treści „skontaktuj się” prowadzący do adresu [email protected].

    <ul> z trzema <li> (R.2.8). Odnośnik pocztowy ma w href przedrostek mailto: (R.3.3). W prawdziwym serwisie numer telefonu dostałby też odnośnik tel: (kliknięcie na telefonie wybiera numer), ale arkusz tego nie przewiduje - punkt ma zostać zwykłym tekstem.

    Typowe błędy

    href="[email protected]" bez mailto: przeglądarka traktuje jak nazwę pliku.

    index.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>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <img src="baner.png" alt="kursy komputerowe">
        </header>
        <nav>
            <a href="index.html" aria-current="page">Strona główna</a>
            <a href="raty.html">Koszt rat</a>
            <a href="https://moje-szkolenia.pl/">Nasz partner</a>
        </nav>
        <main>
            <h3>Kursy komputerowe - programowanie</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Nazwa</th>
                        <th scope="col">Liczba godzin</th>
                        <th scope="col">Cena</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>Kurs React.js</td>
                        <td>220</td>
                        <td>5000</td>
                    </tr>
                    <tr>
                        <td>Kurs JavaScript</td>
                        <td>150</td>
                        <td>3000</td>
                    </tr>
                </tbody>
            </table>
            <h3>Adres do korespondencji</h3>
            <ul>
                <li>Adres: Katowice, ul. Mariacka 5</li>
                <li>Telefon: 32 888 88 88</li>
                <li><a href="mailto:[email protected]">skontaktuj się</a></li>
            </ul>
        </main>
        <footer>
            <p>Autor strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  23. Krok 23: Strona raty.html

    Kryteria: ,

    R.2.3 Witryna internetowa zapisana w plikach index.html i raty.html oraz zapisany jawnie standard kodowania polskich znaków, deklaracja HTML5 <!DOCTYPE HTML>, zadeklarowany język witryny: polski np. <html lang="pl"> oraz nadany tytuł strony "Kursy komputerowe". Strona zawiera sekcje head i body

    R.2.5 W bloku głównym umieszczony przynajmniej jeden <h3>: "Kursy komputerowe - programowanie" lub "Adres do korespondencji" (główna), lub "Oblicz miesięczną ratę" (raty); w stopce umieszczony paragraf z numerem zdającego

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku głównego strony raty.html: Nagłówek trzeciego stopnia o treści „Oblicz miesięczną ratę”.

    Kopia index.html jako raty.html: nagłówek, menu i stopka zostają, w <main> tylko nowy <h3>. Atrybut aria-current przechodzi na odnośnik „Koszt rat”.

    raty.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>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <img src="baner.png" alt="kursy komputerowe">
        </header>
        <nav>
            <a href="index.html">Strona główna</a>
            <a href="raty.html" aria-current="page">Koszt rat</a>
            <a href="https://moje-szkolenia.pl/">Nasz partner</a>
        </nav>
        <main>
            <h3>Oblicz miesięczną ratę</h3>
        </main>
        <footer>
            <p>Autor strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (raty.html)
  24. Krok 24: Pole wyboru „Kurs React.js” w etykiecie

    Kryteria: ,

    R.2.9 Na stronie z ratami w bloku głównym umieszczone dwa pola wyboru (checkbox), pole edycyjne i przycisk, przynajmniej z jednym polem powiązana etykieta <label>

    R.3.5 Na stronie z ratami klasa kontrolki jest przypisana do przynajmniej jednej kontrolki

    ok. 2 min
    Polecenie z arkusza

    Pole wyboru z etykietą „Kurs React.js”.

    Kontrolki stoją w bloku div.calculator - za chwilę ułoży je siatka CSS. Pole wyboru siedzi wewnątrz <label>: takie zagnieżdżenie samo wiąże etykietę z polem, bez pary for/id, i cały napis jest klikalny (R.2.9). Identyfikator react przyda się skryptowi, a klasa kontrolki jest od razu, bo arkusz przypisuje ją wszystkim kontrolkom strony (R.3.5).

    raty.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>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <img src="baner.png" alt="kursy komputerowe">
        </header>
        <nav>
            <a href="index.html">Strona główna</a>
            <a href="raty.html" aria-current="page">Koszt rat</a>
            <a href="https://moje-szkolenia.pl/">Nasz partner</a>
        </nav>
        <main>
            <h3>Oblicz miesięczną ratę</h3>
            <div class="calculator">
                <label><input type="checkbox" id="react" class="kontrolki"> Kurs React.js</label>
            </div>
        </main>
        <footer>
            <p>Autor strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (raty.html)
  25. Krok 25: Pole wyboru „Kurs JavaScript”

    Kryteria: ,

    R.2.9 Na stronie z ratami w bloku głównym umieszczone dwa pola wyboru (checkbox), pole edycyjne i przycisk, przynajmniej z jednym polem powiązana etykieta <label>

    R.3.5 Na stronie z ratami klasa kontrolki jest przypisana do przynajmniej jednej kontrolki

    ok. 1 min
    Polecenie z arkusza

    Pole wyboru z etykietą „Kurs JavaScript”.

    Drugie pole wyboru z własnym identyfikatorem javascript. Bez <br> oba stoją na razie w jednej linii - etykiety są elementami liniowymi.

    raty.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>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <img src="baner.png" alt="kursy komputerowe">
        </header>
        <nav>
            <a href="index.html">Strona główna</a>
            <a href="raty.html" aria-current="page">Koszt rat</a>
            <a href="https://moje-szkolenia.pl/">Nasz partner</a>
        </nav>
        <main>
            <h3>Oblicz miesięczną ratę</h3>
            <div class="calculator">
                <label><input type="checkbox" id="react" class="kontrolki"> Kurs React.js</label>
                <label><input type="checkbox" id="javascript" class="kontrolki"> Kurs JavaScript</label>
            </div>
        </main>
        <footer>
            <p>Autor strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (raty.html)
  26. Krok 26: Pole liczby rat

    Kryteria: , ,

    R.2.9 Na stronie z ratami w bloku głównym umieszczone dwa pola wyboru (checkbox), pole edycyjne i przycisk, przynajmniej z jednym polem powiązana etykieta <label>

    R.3.4 Na stronie z ratami pole edycyjne jest typu number oraz jest zdefiniowane dla przycisku zdarzenie związane z jego wciśnięciem, które uruchamia funkcję skryptu (obsługa zdarzenia zdefiniowana w HTML np. onClick lub w skrypcie np.addEventListener zmienna.onClick = …)

    R.3.5 Na stronie z ratami klasa kontrolki jest przypisana do przynajmniej jednej kontrolki

    ok. 2 min
    Polecenie z arkusza

    Pole edycyjne typu numerycznego poprzedzone etykietą: „Liczba rat: ”.

    Tu etykieta stoi przed polem, więc wiąże je para for/id. Etykieta i pole są w jednym div, żeby siatka potraktowała je jak jeden wiersz. type="number" (R.3.4) z min="1" i step="1": strzałki nie zejdą poniżej jednej raty i nie dadzą ułamka. To tylko podpowiedź przeglądarki - wpisanej ręcznie liczby nie blokuje, dlatego skrypt sprawdzi ją jeszcze raz.

    raty.html HTML zmienione: 4 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <img src="baner.png" alt="kursy komputerowe">
        </header>
        <nav>
            <a href="index.html">Strona główna</a>
            <a href="raty.html" aria-current="page">Koszt rat</a>
            <a href="https://moje-szkolenia.pl/">Nasz partner</a>
        </nav>
        <main>
            <h3>Oblicz miesięczną ratę</h3>
            <div class="calculator">
                <label><input type="checkbox" id="react" class="kontrolki"> Kurs React.js</label>
                <label><input type="checkbox" id="javascript" class="kontrolki"> Kurs JavaScript</label>
                <div>
                    <label for="installments">Liczba rat: </label>
                    <input type="number" id="installments" class="kontrolki" min="1" step="1">
                </div>
            </div>
        </main>
        <footer>
            <p>Autor strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (raty.html)
  27. Krok 27: Lista rozwijana z miastami

    Kryteria: ,

    R.2.10 Na stronie z ratami w bloku głównym umieszczona jedna lista rozwijalna z 3 elementami, zastosowane znaczniki <select> i <option>

    R.3.5 Na stronie z ratami klasa kontrolki jest przypisana do przynajmniej jednej kontrolki

    ok. 2 min
    Polecenie z arkusza

    Lista rozwijana z danymi: „Warszawa”, „Katowice”, „Gdańsk”.

    <select> z trzema <option> (R.2.10). Arkusz nie daje liście etykiety, więc opis dla czytnika ekranu niesie atrybut aria-label - bez niego lista byłaby ogłaszana jako „pole wyboru, Warszawa”, bez informacji, czego dotyczy.

    raty.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>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <img src="baner.png" alt="kursy komputerowe">
        </header>
        <nav>
            <a href="index.html">Strona główna</a>
            <a href="raty.html" aria-current="page">Koszt rat</a>
            <a href="https://moje-szkolenia.pl/">Nasz partner</a>
        </nav>
        <main>
            <h3>Oblicz miesięczną ratę</h3>
            <div class="calculator">
                <label><input type="checkbox" id="react" class="kontrolki"> Kurs React.js</label>
                <label><input type="checkbox" id="javascript" class="kontrolki"> Kurs JavaScript</label>
                <div>
                    <label for="installments">Liczba rat: </label>
                    <input type="number" id="installments" class="kontrolki" min="1" step="1">
                </div>
                <select id="city" class="kontrolki" aria-label="Miasto kursu">
                    <option>Warszawa</option>
                    <option>Katowice</option>
                    <option>Gdańsk</option>
                </select>
            </div>
        </main>
        <footer>
            <p>Autor strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (raty.html)
  28. Krok 28: Przycisk „Oblicz”

    Kryteria: ,

    R.2.9 Na stronie z ratami w bloku głównym umieszczone dwa pola wyboru (checkbox), pole edycyjne i przycisk, przynajmniej z jednym polem powiązana etykieta <label>

    R.3.5 Na stronie z ratami klasa kontrolki jest przypisana do przynajmniej jednej kontrolki

    ok. 1 min
    Polecenie z arkusza

    Przycisk o treści „Oblicz”, którego wybranie uruchamia skrypt.

    <button type="button"> z identyfikatorem calculate - bez atrybutu onclick. Obsługę kliknięcia podepnie skrypt (klucz R.3.4 wymienia wprost addEventListener). Jawny type="button" mówi, że przycisk niczego nie wysyła - to zwykły przycisk uruchamiający skrypt.

    raty.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>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <img src="baner.png" alt="kursy komputerowe">
        </header>
        <nav>
            <a href="index.html">Strona główna</a>
            <a href="raty.html" aria-current="page">Koszt rat</a>
            <a href="https://moje-szkolenia.pl/">Nasz partner</a>
        </nav>
        <main>
            <h3>Oblicz miesięczną ratę</h3>
            <div class="calculator">
                <label><input type="checkbox" id="react" class="kontrolki"> Kurs React.js</label>
                <label><input type="checkbox" id="javascript" class="kontrolki"> Kurs JavaScript</label>
                <div>
                    <label for="installments">Liczba rat: </label>
                    <input type="number" id="installments" class="kontrolki" min="1" step="1">
                </div>
                <select id="city" class="kontrolki" aria-label="Miasto kursu">
                    <option>Warszawa</option>
                    <option>Katowice</option>
                    <option>Gdańsk</option>
                </select>
                <button type="button" id="calculate" class="kontrolki">Oblicz</button>
            </div>
        </main>
        <footer>
            <p>Autor strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (raty.html)
  29. Krok 29: Pusty akapit na wynik

    ok. 1 min
    Polecenie z arkusza

    Rozmieszczenie kontrolek zgodnie z ilustracją 5. Pusty paragraf do wyświetla wyniku działania skryptu.

    Pusty <p id="result"> pod kalkulatorem. aria-live="polite" sprawia, że czytnik ekranu przeczyta nowy wynik sam, gdy skrypt go wpisze. Rozmieszczenie z ilustracji 5 (każda kontrolka w osobnym wierszu) zrobi CSS - na razie pola stoją obok siebie.

    raty.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>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <img src="baner.png" alt="kursy komputerowe">
        </header>
        <nav>
            <a href="index.html">Strona główna</a>
            <a href="raty.html" aria-current="page">Koszt rat</a>
            <a href="https://moje-szkolenia.pl/">Nasz partner</a>
        </nav>
        <main>
            <h3>Oblicz miesięczną ratę</h3>
            <div class="calculator">
                <label><input type="checkbox" id="react" class="kontrolki"> Kurs React.js</label>
                <label><input type="checkbox" id="javascript" class="kontrolki"> Kurs JavaScript</label>
                <div>
                    <label for="installments">Liczba rat: </label>
                    <input type="number" id="installments" class="kontrolki" min="1" step="1">
                </div>
                <select id="city" class="kontrolki" aria-label="Miasto kursu">
                    <option>Warszawa</option>
                    <option>Katowice</option>
                    <option>Gdańsk</option>
                </select>
                <button type="button" id="calculate" class="kontrolki">Oblicz</button>
            </div>
            <p id="result" aria-live="polite"></p>
        </main>
        <footer>
            <p>Autor strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (raty.html)
  30. Etap 3: Styl CSS

    Kroki 30-40 · po tym etapie masz 32 z 40 kryteriów (pkt)

    Krok 30: Zmienne z kolorami i krój czcionki

    Kryteria:

    R.4.1 Ustawiony styl domyślny dla wszystkich selektorów (*): krój czcionki Helvetica

    ok. 2 min
    Polecenie z arkusza

    Domyślnie, dla wszystkich selektorów: krój czcionki Helvetica.

    Na początku style.css blok :root z dwiema zmiennymi CSS: ciemny #625B5B i jasny #EAEAEA. Arkusz używa tych kolorów na zmianę w tle, tekście i ramkach - każdy wpisany jest raz, a w regułach stoi var(--color-dark). Zmiana odcienia to potem jedna linia. Selektor * ustawia krój Helvetica wszystkim elementom (R.4.1).

    style.css CSS nowy plik
    :root {
        --color-dark: #625B5B;
        --color-light: #EAEAEA;
    }
    * {
        font-family: Helvetica;
    }
    Podgląd strony po tym kroku (index.html)
  31. Krok 31: Tło strony

    Kryteria:

    R.4.2 Ustawiony kolor tła #EAEAEA dla selektora body oraz #625B5B dla bloków menu i stopki

    ok. 1 min
    Polecenie z arkusza

    Dla selektora ciała strony: kolor tła #EAEAEA.

    Selektor znacznika body, jak każe uwaga arkusza (R.4.2). W narzędziach przeglądarki obliczona wartość to rgb(234, 234, 234) - to samo, co #EAEAEA.

    style.css CSS zmienione: 3 linie
    :root {
        --color-dark: #625B5B;
        --color-light: #EAEAEA;
    }
    * {
        font-family: Helvetica;
    }
    body {
        background-color: var(--color-light);
    }
    Podgląd strony po tym kroku (index.html)
  32. Krok 32: Menu i stopka

    Kryteria: , , ,

    R.4.2 Ustawiony kolor tła #EAEAEA dla selektora body oraz #625B5B dla bloków menu i stopki

    R.4.3 Ustawiony biały kolor czcionki dla bloków menu i stopki

    R.4.6 Ustawione marginesy wewnętrzne (padding) 20px dla bloków menu i stopki oraz margines zewnętrzny lewy (margin-left) 40px dla listy punktowanej oraz tabeli

    R.4.7 Ustawione wyrównanie tekstu do środka dla bloków menu, stopki i tabeli oraz obramowanie tabeli: 1px dashed #625B5B

    ok. 2 min
    Polecenie z arkusza

    Wspólne dla bloków menu i stopki: kolor tła #625B5B, biały kolor czcionki, marginesy wewnętrzne 20 px, wyrównanie tekstu do środka.

    Jedna reguła dla dwóch selektorów nav, footer (R.4.2, R.4.3, R.4.6, R.4.7).

    style.css CSS zmienione: 6 linii
    :root {
        --color-dark: #625B5B;
        --color-light: #EAEAEA;
    }
    * {
        font-family: Helvetica;
    }
    body {
        background-color: var(--color-light);
    }
    nav, footer {
        background-color: var(--color-dark);
        color: white;
        padding: 20px;
        text-align: center;
    }
    Podgląd strony po tym kroku (index.html)
  33. Krok 33: Obraz: pełna szerokość

    Kryteria:

    R.4.4 Ustawiona szerokość 100% dla selektora img oraz 60% dla selektora table

    ok. 1 min
    Polecenie z arkusza

    Dla selektora obrazu: szerokość 100%.

    Baner wypełnia szerokość okna, a wysokość przeglądarka liczy z proporcji (R.4.4).

    style.css CSS zmienione: 3 linie
    :root {
        --color-dark: #625B5B;
        --color-light: #EAEAEA;
    }
    * {
        font-family: Helvetica;
    }
    body {
        background-color: var(--color-light);
    }
    nav, footer {
        background-color: var(--color-dark);
        color: white;
        padding: 20px;
        text-align: center;
    }
    img {
        width: 100%;
    }
    Podgląd strony po tym kroku (index.html)
  34. Krok 34: Lista: margines i punktor okrąg

    Kryteria: ,

    R.4.5 Ustawiony typ punktora circle dla selektora ul

    R.4.6 Ustawione marginesy wewnętrzne (padding) 20px dla bloków menu i stopki oraz margines zewnętrzny lewy (margin-left) 40px dla listy punktowanej oraz tabeli

    ok. 1 min
    Polecenie z arkusza

    Dla selektora listy punktowanej: margines zewnętrzny lewy 40 px, typ punktora okrąg.

    Punktor „okrąg” to circle (R.4.5, R.4.6).

    style.css CSS zmienione: 4 linie
    :root {
        --color-dark: #625B5B;
        --color-light: #EAEAEA;
    }
    * {
        font-family: Helvetica;
    }
    body {
        background-color: var(--color-light);
    }
    nav, footer {
        background-color: var(--color-dark);
        color: white;
        padding: 20px;
        text-align: center;
    }
    img {
        width: 100%;
    }
    ul {
        margin-left: 40px;
        list-style-type: circle;
    }
    Podgląd strony po tym kroku (index.html)
  35. Krok 35: Odnośniki w menu

    Kryteria:

    R.4.9 Dla odsyłaczy jedynie w bloku menu: czcionka pogrubiona, kolor tła #EAEAEA, kolor czcionki #625B5B, marginesy wewnętrzne 10px, marginesy zewnętrzne 50px, zaokrąglenie rogów 20px

    ok. 2 min
    Polecenie z arkusza

    Dla odsyłaczy jedynie w bloku menu: czcionka pogrubiona, kolor tła #EAEAEA, kolor czcionki #625B5B, marginesy wewnętrzne 10 px, marginesy zewnętrzne 50 px, zaokrąglenie rogów 20 px.

    Selektor potomka nav a - odnośnik pocztowy w bloku głównym zostaje zwykły (R.4.9). Jedna linia ponad arkusz: border: 1px solid transparent. Pod kursorem pojawi się ramka 1 px, a gdyby jej wcześniej nie było, przycisk urósłby o 2 px i odnośniki w menu przeskoczyłyby w bok. Przezroczysta ramka tej samej grubości rezerwuje na nią miejsce.

    Typowe błędy

    Sam selektor a zmienia też odnośnik „skontaktuj się” - arkusz mówi „jedynie w bloku menu”.

    style.css CSS zmienione: 9 linii
    :root {
        --color-dark: #625B5B;
        --color-light: #EAEAEA;
    }
    * {
        font-family: Helvetica;
    }
    body {
        background-color: var(--color-light);
    }
    nav, footer {
        background-color: var(--color-dark);
        color: white;
        padding: 20px;
        text-align: center;
    }
    img {
        width: 100%;
    }
    ul {
        margin-left: 40px;
        list-style-type: circle;
    }
    nav a {
        font-weight: bold;
        background-color: var(--color-light);
        color: var(--color-dark);
        padding: 10px;
        margin: 50px;
        border-radius: 20px;
        border: 1px solid transparent;
    }
    Podgląd strony po tym kroku (index.html)
  36. Krok 36: Odnośnik pod kursorem i z klawiatury

    Kryteria:

    R.4.10 Gdy kursor myszy znajdzie się na odsyłaczu w menu, jego kolor tła zmienia się na #625B5B, czcionki na #EAEAEA oraz pojawia się obramowanie 1px solid #EAEAEA

    ok. 2 min
    Polecenie z arkusza

    Gdy kursor myszy znajdzie się na odsyłaczu w menu jego kolor tła zmienia się na #625B5B, czcionki na #EAEAEA oraz pojawia się obramowanie linią ciągłą o szerokości 1 px i kolorze #EAEAEA.

    :hover odwraca kolory i zmienia kolor ramki na jasny - grubość i styl (1px solid) są już w regule nav a, więc pod kursorem ramka 1px solid #EAEAEA jest widoczna (R.4.10). Ten sam wygląd dostaje :focus-visible: odnośnik wybrany klawiszem Tab wygląda jak wskazany myszą. Najedź na menu w podglądzie albo przejdź po nim Tabem.

    style.css CSS zmienione: 6 linii
    :root {
        --color-dark: #625B5B;
        --color-light: #EAEAEA;
    }
    * {
        font-family: Helvetica;
    }
    body {
        background-color: var(--color-light);
    }
    nav, footer {
        background-color: var(--color-dark);
        color: white;
        padding: 20px;
        text-align: center;
    }
    img {
        width: 100%;
    }
    ul {
        margin-left: 40px;
        list-style-type: circle;
    }
    nav a {
        font-weight: bold;
        background-color: var(--color-light);
        color: var(--color-dark);
        padding: 10px;
        margin: 50px;
        border-radius: 20px;
        border: 1px solid transparent;
    }
    nav a:hover,
    nav a:focus-visible {
        background-color: var(--color-dark);
        color: var(--color-light);
        border-color: var(--color-light);
    }
    Podgląd strony po tym kroku (index.html)
  37. Krok 37: Tabela: ramka kreskowa, szerokość, margines

    Kryteria: , ,

    R.4.4 Ustawiona szerokość 100% dla selektora img oraz 60% dla selektora table

    R.4.6 Ustawione marginesy wewnętrzne (padding) 20px dla bloków menu i stopki oraz margines zewnętrzny lewy (margin-left) 40px dla listy punktowanej oraz tabeli

    R.4.7 Ustawione wyrównanie tekstu do środka dla bloków menu, stopki i tabeli oraz obramowanie tabeli: 1px dashed #625B5B

    ok. 2 min
    Polecenie z arkusza

    Dla selektora tabeli: obramowanie linią kreskową o grubości 1 px i kolorze #625B5B, szerokość 60%, margines zewnętrzny lewy 40 px, wyrównanie tekstu do środka.

    Linia kreskowa to dashed. Ramka obejmuje samą tabelę, bez linii między komórkami - jak na ilustracji 4 (R.4.4, R.4.6, R.4.7).

    style.css CSS zmienione: 6 linii
    :root {
        --color-dark: #625B5B;
        --color-light: #EAEAEA;
    }
    * {
        font-family: Helvetica;
    }
    body {
        background-color: var(--color-light);
    }
    nav, footer {
        background-color: var(--color-dark);
        color: white;
        padding: 20px;
        text-align: center;
    }
    img {
        width: 100%;
    }
    ul {
        margin-left: 40px;
        list-style-type: circle;
    }
    nav a {
        font-weight: bold;
        background-color: var(--color-light);
        color: var(--color-dark);
        padding: 10px;
        margin: 50px;
        border-radius: 20px;
        border: 1px solid transparent;
    }
    nav a:hover,
    nav a:focus-visible {
        background-color: var(--color-dark);
        color: var(--color-light);
        border-color: var(--color-light);
    }
    table {
        border: 1px dashed var(--color-dark);
        width: 60%;
        margin-left: 40px;
        text-align: center;
    }
    Podgląd strony po tym kroku (index.html)
  38. Krok 38: Klasa kontrolki

    Kryteria:

    R.4.8 Zdefiniowana klasa kontrolki o cechach: marginesy zewnętrzne 5px

    ok. 1 min
    Polecenie z arkusza

    Dla klasy o nazwie kontrolki: marginesy zewnętrzne 5 px. Klasa jest przypisana do wszystkich kontrolek na stronie raty.html (pól wyboru, pola edycyjnego, listy rozwijalnej i przycisku).

    Selektor klasy z kropką: .kontrolki (R.4.8). Nazwa po polsku, bo narzuca ją arkusz.

    style.css CSS zmienione: 3 linie
    :root {
        --color-dark: #625B5B;
        --color-light: #EAEAEA;
    }
    * {
        font-family: Helvetica;
    }
    body {
        background-color: var(--color-light);
    }
    nav, footer {
        background-color: var(--color-dark);
        color: white;
        padding: 20px;
        text-align: center;
    }
    img {
        width: 100%;
    }
    ul {
        margin-left: 40px;
        list-style-type: circle;
    }
    nav a {
        font-weight: bold;
        background-color: var(--color-light);
        color: var(--color-dark);
        padding: 10px;
        margin: 50px;
        border-radius: 20px;
        border: 1px solid transparent;
    }
    nav a:hover,
    nav a:focus-visible {
        background-color: var(--color-dark);
        color: var(--color-light);
        border-color: var(--color-light);
    }
    table {
        border: 1px dashed var(--color-dark);
        width: 60%;
        margin-left: 40px;
        text-align: center;
    }
    .kontrolki {
        margin: 5px;
    }
    Podgląd strony po tym kroku (raty.html)
  39. Krok 39: Kalkulator na siatce: każda kontrolka w osobnym wierszu

    ok. 2 min
    Polecenie z arkusza

    Rozmieszczenie kontrolek zgodnie z ilustracją 5.

    display: grid na bloku .calculator robi z każdego dziecka osobny wiersz siatki - dwa pola wyboru, wiersz z liczbą rat, lista i przycisk stają jedno pod drugim, jak na ilustracji 5. justify-items: start dosuwa je do lewej i nie rozciąga na całą szerokość (domyślnie element siatki zajmuje całą szerokość kolumny - przycisk byłby szeroki na pół ekranu).

    W wersji podstawowej ten sam układ robią znaczniki <br>. Różnica: tu HTML opisuje tylko treść, a o układzie decyduje CSS - na przykład dwie kolumny na szerokim ekranie to jedna linia grid-template-columns, bez zmian w HTML.

    style.css CSS zmienione: 4 linie
    :root {
        --color-dark: #625B5B;
        --color-light: #EAEAEA;
    }
    * {
        font-family: Helvetica;
    }
    body {
        background-color: var(--color-light);
    }
    nav, footer {
        background-color: var(--color-dark);
        color: white;
        padding: 20px;
        text-align: center;
    }
    img {
        width: 100%;
    }
    ul {
        margin-left: 40px;
        list-style-type: circle;
    }
    nav a {
        font-weight: bold;
        background-color: var(--color-light);
        color: var(--color-dark);
        padding: 10px;
        margin: 50px;
        border-radius: 20px;
        border: 1px solid transparent;
    }
    nav a:hover,
    nav a:focus-visible {
        background-color: var(--color-dark);
        color: var(--color-light);
        border-color: var(--color-light);
    }
    table {
        border: 1px dashed var(--color-dark);
        width: 60%;
        margin-left: 40px;
        text-align: center;
    }
    .kontrolki {
        margin: 5px;
    }
    .calculator {
        display: grid;
        justify-items: start;
    }
    Podgląd strony po tym kroku (raty.html)
  40. Krok 40: Układ bloków zgodny z ilustracją 3

    Kryteria:

    R.3.1 Układ bloków po uruchomieniu w przeglądarce jest zgodny z ilustracją 3 w arkuszu egzaminacyjnym

    ok. 2 min
    Polecenie z arkusza

    Uwaga: styl CSS ciała strony, obrazu, listy i tabeli należy zdefiniować wyłącznie przy pomocy selektora tych znaczników. Jest to uwarunkowane projektem późniejszej rozbudowy witryny.

    Na index.html bloki stoją jeden pod drugim, jak na ilustracji 3 (R.3.1). Style body, img, ul i table są zapisane selektorami znaczników, bez klas i identyfikatorów - klucz uznaje R.4.2, R.4.4 i R.4.5 tylko w tej postaci. Zmienne CSS tego nie zmieniają: o selektorze decyduje lewa strona reguły, a var(...) stoi po prawej.

    Typowe błędy

    Styl tabeli zapisany jako klasa .tabela wygląda tak samo, ale klucz go nie uznaje (uwaga przy R.4).

    Podgląd strony po tym kroku (index.html)
  41. Etap 4: Skrypt JavaScript

    Kroki 41-45 · po tym etapie masz 40 z 40 kryteriów (pkt)

    Krok 41: Plik raty.js z defer i obsługa kliknięcia

    Kryteria: ,

    R.3.4 Na stronie z ratami pole edycyjne jest typu number oraz jest zdefiniowane dla przycisku zdarzenie związane z jego wciśnięciem, które uruchamia funkcję skryptu (obsługa zdarzenia zdefiniowana w HTML np. onClick lub w skrypcie np.addEventListener zmienna.onClick = …)

    R.5.1 Skrypt jest napisany w języku JavaScript i zawiera on przynajmniej jedną poprawną składniowo instrukcję wynikającą z treści zadania

    ok. 3 min
    Polecenie z arkusza

    Wykonywany po stronie klienta, na stronie raty.html po kliknięciu przycisku „Oblicz”.

    Skrypt w osobnym pliku raty.js, dołączonym w <head> z atrybutem defer: przeglądarka pobiera go równolegle ze stroną i uruchamia dopiero, gdy cały HTML jest wczytany - querySelector na pewno znajdzie przycisk i pola.

    Na początku pliku:

    • obiekt PRICES z cenami z tabeli na ilustracji 4 - klucz to identyfikator pola wyboru, wartość to cena,
    • stałe const z odnośnikami do pola liczby rat, listy miast i akapitu wyniku - wyszukane raz, a nie przy każdym kliknięciu,
    • addEventListener('click', calculateInstallment) podpina funkcję pod przycisk (R.3.4) - nazwa funkcji bez nawiasów, bo przekazuje się samą funkcję, a nie wynik jej wywołania.

    Funkcja jest jeszcze pusta: kliknięcie „Oblicz” niczego nie robi (R.5.1).

    raty.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>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
        <script src="raty.js" defer></script>
    </head>
    <body>
        <header>
            <img src="baner.png" alt="kursy komputerowe">
        </header>
        <nav>
            <a href="index.html">Strona główna</a>
            <a href="raty.html" aria-current="page">Koszt rat</a>
            <a href="https://moje-szkolenia.pl/">Nasz partner</a>
        </nav>
        <main>
            <h3>Oblicz miesięczną ratę</h3>
            <div class="calculator">
                <label><input type="checkbox" id="react" class="kontrolki"> Kurs React.js</label>
                <label><input type="checkbox" id="javascript" class="kontrolki"> Kurs JavaScript</label>
                <div>
                    <label for="installments">Liczba rat: </label>
                    <input type="number" id="installments" class="kontrolki" min="1" step="1">
                </div>
                <select id="city" class="kontrolki" aria-label="Miasto kursu">
                    <option>Warszawa</option>
                    <option>Katowice</option>
                    <option>Gdańsk</option>
                </select>
                <button type="button" id="calculate" class="kontrolki">Oblicz</button>
            </div>
            <p id="result" aria-live="polite"></p>
        </main>
        <footer>
            <p>Autor strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    raty.js JavaScript nowy plik
    const PRICES = { react: 5000, javascript: 3000 };
    
    const installmentsInput = document.querySelector('#installments');
    const citySelect = document.querySelector('#city');
    const result = document.querySelector('#result');
    
    function calculateInstallment() {
    }
    
    document.querySelector('#calculate').addEventListener('click', calculateInstallment);
    Podgląd strony po tym kroku (raty.html)
  42. Krok 42: Kwota za zaznaczone kursy

    Kryteria: ,

    R.5.2 Skrypt pobiera dane z przynajmniej jednej kontrolki, np. funkcja document.getElementById z parametrem, który zdefiniowany jest w kontrolce jako id

    R.5.3 Skrypt ustala koszt wszystkich zaznaczonych w polu wyboru kursów np. poprzez sprawdzenie warunku zaznaczenia danego kursu (pole checked == true). Ceny: React.js - 5000, JavaScript 3000

    ok. 3 min
    Polecenie z arkusza

    Pobiera dane z kontrolek. Ustala całkowitą kwotę za wybrane kursy na podstawie cen z tabeli z ilustracji 4.

    Pętla for...of po Object.entries(PRICES) daje pary [identyfikator, cena]: ['react', 5000], potem ['javascript', 3000]. Dla każdej pary getElementById(id).checked sprawdza, czy pole jest zaznaczone (R.5.2), i jeśli tak - dolicza cenę do total (R.5.3).

    W wersji podstawowej są dwa osobne warunki if. Tu nowy kurs to jedna linia w obiekcie PRICES i jedno pole wyboru w HTML - funkcja się nie zmienia.

    raty.html HTML zmienione: 0 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
        <script src="raty.js" defer></script>
    </head>
    <body>
        <header>
            <img src="baner.png" alt="kursy komputerowe">
        </header>
        <nav>
            <a href="index.html">Strona główna</a>
            <a href="raty.html" aria-current="page">Koszt rat</a>
            <a href="https://moje-szkolenia.pl/">Nasz partner</a>
        </nav>
        <main>
            <h3>Oblicz miesięczną ratę</h3>
            <div class="calculator">
                <label><input type="checkbox" id="react" class="kontrolki"> Kurs React.js</label>
                <label><input type="checkbox" id="javascript" class="kontrolki"> Kurs JavaScript</label>
                <div>
                    <label for="installments">Liczba rat: </label>
                    <input type="number" id="installments" class="kontrolki" min="1" step="1">
                </div>
                <select id="city" class="kontrolki" aria-label="Miasto kursu">
                    <option>Warszawa</option>
                    <option>Katowice</option>
                    <option>Gdańsk</option>
                </select>
                <button type="button" id="calculate" class="kontrolki">Oblicz</button>
            </div>
            <p id="result" aria-live="polite"></p>
        </main>
        <footer>
            <p>Autor strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    raty.js JavaScript zmienione: 6 linii
    const PRICES = { react: 5000, javascript: 3000 };
    
    const installmentsInput = document.querySelector('#installments');
    const citySelect = document.querySelector('#city');
    const result = document.querySelector('#result');
    
    function calculateInstallment() {
        let total = 0;
        for (const [id, price] of Object.entries(PRICES)) {
            if (document.getElementById(id).checked) {
                total += price;
            }
        }
    }
    
    document.querySelector('#calculate').addEventListener('click', calculateInstallment);
    Podgląd strony po tym kroku (raty.html)
  43. Krok 43: Liczba rat i wysokość raty

    Kryteria:

    R.5.4 Skrypt pobiera wpisaną w pole edycyjne liczbę rat i oblicza koszt jednej raty dzieląc koszt kursów przez liczbę rat

    ok. 2 min
    Polecenie z arkusza

    Oblicza koszt jednej raty na podstawie kwoty całkowitej. Dla uproszczenia kwota całkowita jest dzielona przez podaną liczbę rat.

    valueAsNumber pola type="number" oddaje od razu liczbę (dla pustego pola - NaN, „nie liczba”), a nie tekst jak value. Wysokość raty to kwota całkowita podzielona przez liczbę rat: 8000 / 10 = 800 (R.5.4).

    raty.html HTML zmienione: 0 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
        <script src="raty.js" defer></script>
    </head>
    <body>
        <header>
            <img src="baner.png" alt="kursy komputerowe">
        </header>
        <nav>
            <a href="index.html">Strona główna</a>
            <a href="raty.html" aria-current="page">Koszt rat</a>
            <a href="https://moje-szkolenia.pl/">Nasz partner</a>
        </nav>
        <main>
            <h3>Oblicz miesięczną ratę</h3>
            <div class="calculator">
                <label><input type="checkbox" id="react" class="kontrolki"> Kurs React.js</label>
                <label><input type="checkbox" id="javascript" class="kontrolki"> Kurs JavaScript</label>
                <div>
                    <label for="installments">Liczba rat: </label>
                    <input type="number" id="installments" class="kontrolki" min="1" step="1">
                </div>
                <select id="city" class="kontrolki" aria-label="Miasto kursu">
                    <option>Warszawa</option>
                    <option>Katowice</option>
                    <option>Gdańsk</option>
                </select>
                <button type="button" id="calculate" class="kontrolki">Oblicz</button>
            </div>
            <p id="result" aria-live="polite"></p>
        </main>
        <footer>
            <p>Autor strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    raty.js JavaScript zmienione: 2 linie
    const PRICES = { react: 5000, javascript: 3000 };
    
    const installmentsInput = document.querySelector('#installments');
    const citySelect = document.querySelector('#city');
    const result = document.querySelector('#result');
    
    function calculateInstallment() {
        let total = 0;
        for (const [id, price] of Object.entries(PRICES)) {
            if (document.getElementById(id).checked) {
                total += price;
            }
        }
        const installments = installmentsInput.valueAsNumber;
        const rate = total / installments;
    }
    
    document.querySelector('#calculate').addEventListener('click', calculateInstallment);
    Podgląd strony po tym kroku (raty.html)
  44. Krok 44: Sprawdzenie danych przed liczeniem

    ok. 2 min
    Polecenie z arkusza

    Pobiera dane z kontrolek.

    Dwa warunki przed dzieleniem, każdy kończy funkcję komunikatem i return („wczesne wyjście”):

    • liczba rat musi być liczbą całkowitą większą od zera - Number.isInteger(NaN) to fałsz, więc puste pole też tu odpada. Bez tego puste pole dałoby „rat po Infinity zł”, a 0 lub -2 - ratę bez sensu,
    • trzeba zaznaczyć co najmniej jeden kurs - inaczej wynik brzmiałby „Koszt całkowity: 0 zł”.

    Komunikaty trafiają do akapitu przez textContent: wpisuje zwykły tekst, którego przeglądarka nie interpretuje jako HTML. Klucz tego nie sprawdza, ale to pierwsze, co zgłosiłby użytkownik kalkulatora.

    raty.html HTML zmienione: 0 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
        <script src="raty.js" defer></script>
    </head>
    <body>
        <header>
            <img src="baner.png" alt="kursy komputerowe">
        </header>
        <nav>
            <a href="index.html">Strona główna</a>
            <a href="raty.html" aria-current="page">Koszt rat</a>
            <a href="https://moje-szkolenia.pl/">Nasz partner</a>
        </nav>
        <main>
            <h3>Oblicz miesięczną ratę</h3>
            <div class="calculator">
                <label><input type="checkbox" id="react" class="kontrolki"> Kurs React.js</label>
                <label><input type="checkbox" id="javascript" class="kontrolki"> Kurs JavaScript</label>
                <div>
                    <label for="installments">Liczba rat: </label>
                    <input type="number" id="installments" class="kontrolki" min="1" step="1">
                </div>
                <select id="city" class="kontrolki" aria-label="Miasto kursu">
                    <option>Warszawa</option>
                    <option>Katowice</option>
                    <option>Gdańsk</option>
                </select>
                <button type="button" id="calculate" class="kontrolki">Oblicz</button>
            </div>
            <p id="result" aria-live="polite"></p>
        </main>
        <footer>
            <p>Autor strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    raty.js JavaScript zmienione: 8 linii
    const PRICES = { react: 5000, javascript: 3000 };
    
    const installmentsInput = document.querySelector('#installments');
    const citySelect = document.querySelector('#city');
    const result = document.querySelector('#result');
    
    function calculateInstallment() {
        let total = 0;
        for (const [id, price] of Object.entries(PRICES)) {
            if (document.getElementById(id).checked) {
                total += price;
            }
        }
        const installments = installmentsInput.valueAsNumber;
        if (!Number.isInteger(installments) || installments < 1) {
            result.textContent = 'Podaj liczbę rat - liczbę całkowitą większą od zera.';
            return;
        }
        if (total === 0) {
            result.textContent = 'Zaznacz co najmniej jeden kurs.';
            return;
        }
        const rate = total / installments;
    }
    
    document.querySelector('#calculate').addEventListener('click', calculateInstallment);
    Podgląd strony po tym kroku (raty.html)
  45. Krok 45: Zdanie z wynikiem pod przyciskiem

    Kryteria: , , ,

    R.5.5 Pod przyciskiem jest wyświetlany efekt działania skryptu, którego fragment dotyczący miasta zawiera nazwę miasta pobraną z listy rozwijalnej (wystarczy sprawdzić dwa razy dla różnych miast)

    R.5.6 Pod przyciskiem jest wyświetlany efekt działania skryptu: obliczony w skrypcie koszt całkowity

    R.5.7 Pod przyciskiem jest wyświetlany efekt działania skryptu: liczba rat oraz koszt jednej raty (sprawdzić dla dwóch różnych liczb )

    R.5.8 W skryptach zastosowana przynajmniej jedna zmienna lub funkcja oraz nazwy wszystkich funkcji i zmiennych są w języku polskim lub angielskim i odzwierciedlają cel zastosowania

    ok. 3 min
    Polecenie z arkusza

    Wyświetla pod przyciskiem w paragrafie treść: „Kurs odbędzie się w <miasto>. Koszt całkowity: <kwota> zł. Płacisz <liczba> rat po <rata> zł”, gdzie <miasto> oznacza wybór z listy rozwijalnej, <kwota> oznacza obliczoną kwotę całkowitą, <liczba> oznacza podaną liczbę rat, a <rata> oznacza wyliczoną ratę.

    • citySelect.value to tekst wybranej opcji, czyli nazwa miasta (R.5.5),
    • szablon tekstowy w odwrotnych apostrofach wstawia wartości w ${...} - zdanie czyta się jak gotowy tekst, bez plątaniny + i cudzysłowów,
    • Intl.NumberFormat('pl-PL') formatuje kwoty po polsku: przecinek dziesiętny i najwyżej dwa miejsca po przecinku. 8000 / 3 daje „2666,67 zł”, a nie „2666.6666666666665 zł” (R.5.6, R.5.7).

    Zaznacz w podglądzie oba kursy, wpisz 10, wybierz Katowice i kliknij „Oblicz”: „Kurs odbędzie się w Katowice. Koszt całkowity: 8000 zł. Płacisz 10 rat po 800 zł” - jak na ilustracji 5. Nazwy mówią, co przechowują: PRICES, total, installments, rate, city, calculateInstallment (R.5.8).

    raty.html HTML zmienione: 0 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Kursy komputerowe</title>
        <link rel="stylesheet" href="style.css">
        <script src="raty.js" defer></script>
    </head>
    <body>
        <header>
            <img src="baner.png" alt="kursy komputerowe">
        </header>
        <nav>
            <a href="index.html">Strona główna</a>
            <a href="raty.html" aria-current="page">Koszt rat</a>
            <a href="https://moje-szkolenia.pl/">Nasz partner</a>
        </nav>
        <main>
            <h3>Oblicz miesięczną ratę</h3>
            <div class="calculator">
                <label><input type="checkbox" id="react" class="kontrolki"> Kurs React.js</label>
                <label><input type="checkbox" id="javascript" class="kontrolki"> Kurs JavaScript</label>
                <div>
                    <label for="installments">Liczba rat: </label>
                    <input type="number" id="installments" class="kontrolki" min="1" step="1">
                </div>
                <select id="city" class="kontrolki" aria-label="Miasto kursu">
                    <option>Warszawa</option>
                    <option>Katowice</option>
                    <option>Gdańsk</option>
                </select>
                <button type="button" id="calculate" class="kontrolki">Oblicz</button>
            </div>
            <p id="result" aria-live="polite"></p>
        </main>
        <footer>
            <p>Autor strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    raty.js JavaScript zmienione: 3 linie
    const PRICES = { react: 5000, javascript: 3000 };
    
    const installmentsInput = document.querySelector('#installments');
    const citySelect = document.querySelector('#city');
    const result = document.querySelector('#result');
    const money = new Intl.NumberFormat('pl-PL', { maximumFractionDigits: 2 });
    
    function calculateInstallment() {
        let total = 0;
        for (const [id, price] of Object.entries(PRICES)) {
            if (document.getElementById(id).checked) {
                total += price;
            }
        }
        const installments = installmentsInput.valueAsNumber;
        if (!Number.isInteger(installments) || installments < 1) {
            result.textContent = 'Podaj liczbę rat - liczbę całkowitą większą od zera.';
            return;
        }
        if (total === 0) {
            result.textContent = 'Zaznacz co najmniej jeden kurs.';
            return;
        }
        const rate = total / installments;
        const city = citySelect.value;
        result.textContent = `Kurs odbędzie się w ${city}. Koszt całkowity: ${money.format(total)} zł. Płacisz ${installments} rat po ${money.format(rate)} zł`;
    }
    
    document.querySelector('#calculate').addEventListener('click', calculateInstallment);
    Podgląd strony po tym kroku (raty.html)
  46. Etap 5: Porównanie z wersją podstawową

    Kroki 46-47 · po tym etapie masz 40 z 40 kryteriów (pkt)

    Krok 46: Co jest inaczej i dlaczego

    ok. 3 min
    Polecenie z arkusza

    Ocenie podlegać będzie 5 rezultatów: operacje na bazie danych, zawartość witryny internetowej, działanie witryny internetowej, styl CSS witryny internetowej oraz skrypt.

    Obie wersje dają te same punkty. Różnice:

    wersja podstawowata wersja
    SQLJOIN ... USING(id_kat) w jednej liniialiasy tabel, JOIN ... ON, klauzule w osobnych liniach
    kolorywpisane w każdej regulezmienne w :root
    tabelasame <tr><thead>, <tbody>, scope="col"
    układ kalkulatora<br> w HTMLsiatka CSS na .calculator
    zdarzenieonclick w HTMLaddEventListener w raty.js z defer
    ceny kursówdwa warunki ifobiekt PRICES i pętla
    złe dane„rat po Infinity zł”komunikat i return
    kwoty2666.6666666666665Intl.NumberFormat: 2666,67
    menuramka pod kursorem przesuwa odnośnikiprzezroczysta ramka rezerwuje miejsce, :focus-visible

    Skrypt tej wersji jest sprawdzony w prawdziwym Chrome: oba kursy i 10 rat (800 zł, jak na ilustracji 5), 3 raty (2666,67 zł), jeden kurs, żaden kurs, puste i ujemne pole liczby rat.

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

  47. Krok 47: Którą wersję wybrać na egzaminie

    ok. 2 min
    Polecenie z arkusza

    Czas przeznaczony na wykonanie zadania wynosi 150 minut.

    • Wersja podstawowa, gdy liczy się czas: onclick, getElementById i innerHTML są w tabeli 1 arkusza, a cały skrypt to kilkanaście linii w jednym pliku.
    • Ta wersja, gdy addEventListener, szablony tekstowe i for...of pisze się z pamięci. Osobny plik raty.js trzeba nagrać na płytę razem z resztą - bez niego kalkulator przestaje działać, a punkty R.5 egzaminator sprawdzi już tylko w kodzie.

    Mieszanie też daje pełne punkty: zmienne CSS i siatka z tej wersji, skrypt z podstawowej.

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

  48. Etap 6: Oddanie pracy

    Krok 48 · po tym etapie masz 40 z 40 kryteriów (pkt)

    Krok 48: 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. Nagraj płytę z rezultatami pracy. W folderze z numerem zdającego powinny znajdować się pliki: baner.png, import.jpg, index.html, kw1.png, kw2.png, kw3.png, kw4.png, kwerendy.txt, raty.html, przeglądarka.txt, style.css, ewentualnie inne przygotowane pliki.

    W przeglądarka.txt nazwa przeglądarki, w której strony były sprawdzane. Strony nie wymagają serwera - otwierają się wprost z dysku.

    Do listy z arkusza dochodzi raty.js („ewentualnie inne przygotowane pliki”). Po nagraniu trzeba sprawdzić odczyt płyty i opisać ją numerem zdającego.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

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.