INF.03-03-26.01-SGStyczeń 2026 · 51 kroków · ok. 92 min · 38 kryteriów z klucza
Rozwiązanie krok po kroku: Witryna matematyczna pola figur (Nowoczesny kod (grid))
To drugi sposób rozwiązania tego samego arkusza: animacja GIF z pięciu kwadratów, strona index.html z dużą figurą, dwiema klikanymi miniaturami i kalkulatorem pola oraz podstrona kolo.html ze wzorem na pole koła. Obie wersje spełniają wszystkie 38 kryteriów klucza - różni je sposób pisania kodu, nie wynik.
Czym ta wersja różni się od podstawowej:
siatka CSS (display: grid) w bloku głównym: trzy kolumny 35% / 30% / 35% w jednej linii grid-template-columns, kolory z arkusza w zmiennych CSS,
HTML bez <br>: miniatury mają własny blok, a etykiety nad polami ustawia CSS,
skrypt w osobnym pliku skrypt.js dołączonym z defer - w HTML nie ma ani jednego onclick,
dane zamiast drabinki if: obiekt FIGURES opisuje każdą figurę (plik obrazu, nazwę, wzór na pole), a skrypt pamięta wybraną figurę w zmiennej, zamiast porównywać atrybut src,
miniatury obsługiwane także klawiaturą (Tab, Enter, spacja), wynik przez textContent i ogłaszany czytnikom ekranu (aria-live).
Kroki nadal idą zdanie po zdaniu za treścią arkusza. Oba skrypty są sprawdzone w prawdziwej przeglądarce na oryginalnych plikach BMP z archiwum pliki2 - kliknięciami, klawiaturą i złymi danymi.
Jak liczą się punkty. Klucz ma 38 kryteriów (R.1.1 - R.5.8), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 29 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.
Suwak i strzałki obok niego - albo ←→ na klawiaturze - przechodzą krok po kroku; wyjaśnienie, pliki i podgląd zmieniają się razem z krokiem.
Lista „Etap” przenosi od razu do wybranego etapu.
„Rozwiązuję samodzielnie” chowa rozwiązanie kroku - najpierw własna próba, potem odsłonięcie.
„Tryb prezentacji” pokazuje same kroki, bez menu strony - na rzutnik.
Etap 1: Animacja
Kroki 1-3 · po tym etapie masz 4 z 38 kryteriów (pkt)
Krok 1: Pięć klatek 200 × 200 px wyciętych z klatki.jpg
Kryteria: ,
R.1.1 Animacja kolo.gif ma wymiary 200 px na 200 px
R.1.2 W animacji zastosowany przynajmniej jeden kwadrat z grafiki klatki.jpg
ok. 5 min
Polecenie z arkusza
Każdą klatką animacji jest jeden kwadrat z grafiki klatki.jpg, razem to pięć klatek animacji. Wymiary każdej klatki: 200 px na 200 px
Archiwum pliki2.7z ma hasło *M@tem@tyk@6 (gwiazdka na początku, trzy małpy zamiast „a”). Obraz klatki.jpg ma 1122 × 220 px, a każdy z pięciu kwadratów - około 205 × 204 px, czyli trochę więcej niż klatka.
W GIMP-ie nowy obraz 200 × 200 px, a potem dla każdego kwadratu: zaznaczanie prostokątne z opcją Stały: Rozmiar 200 × 200, zaznaczenie w środku kwadratu, Kopiuj, w nowym obrazie Wklej jako → Nowa warstwa. Stały rozmiar zaznaczenia gwarantuje identyczne klatki - bez skalowania, które rozmyłoby napis. Kolejność warstw: ostatnia na liście to pierwsza klatka, więc kwadraty wkleja się od lewej do prawej.
Typowe błędy
Klatka większa niż 200 × 200 px (cały kwadrat z ramką albo przeskalowany cały obraz) daje animację o złych wymiarach - klucz sprawdza dokładnie 200 × 200.
Podgląd strony po tym kroku
Krok 2: Pętla i opóźnienie 1 s: zrzut parametry.jpg
Kryteria:
R.1.4 Ustawiono opóźnienie między klatkami na 1 sekundę, co jest udokumentowane zrzutem ekranu - plik parametry.jpg , na którym widoczny jest cały obszar ekranu z paskiem zadań
ok. 3 min
Polecenie z arkusza
Animacja jest powtarzana w nieskończoność, opóźnienie między klatkami 1 sekunda. Udokumentuj ustawienie parametrów animacji za pomocą zrzutu ekranu o nazwie parametry.jpg. Nie kadruj zrzutu. Powinien on obejmować cały ekran monitora, z widocznym paskiem zadań.
Plik → Wyeksportuj jako, nazwa kolo.gif. W oknie eksportu GIF:
Jako animację - bez tego GIMP spłaszczy warstwy do jednego obrazu,
Pętla - powtarzanie w nieskończoność,
opóźnienie 1000 ms - jednostką są milisekundy, więc 1 s to 1000,
Jedna klatka na warstwę (zastąp) i Użyj opóźnienia wprowadzonego powyżej dla wszystkich klatek - GIMP czyta też opóźnienie z nazw warstw (np. „Warstwa (100ms)”), a to pole każe zignorować nazwy.
Zanim klikniesz Eksportuj, zrób zrzut całego ekranu z tym oknem i zapisz go jako parametry.jpg (JPEG, nie PNG). Obraz w podglądzie kroku to odtworzenie tego okna z ustawieniami z arkusza.
Podgląd strony po tym kroku
Krok 3: Animacja kolo.gif
Kryteria:
R.1.3 Animacja składa się z pięciu klatek wyświetlanych jedna po drugiej, po ostatniej klatce jest wyświetlana pierwsza
ok. 1 min
Polecenie z arkusza
Animację zapisz jako kolo.gif
Eksportuj - powstaje kolo.gif: 5 klatek 200 × 200 px, każda po 1000 ms, po ostatniej znów pierwsza (R.1.3). Litery napisu „KOŁO” po kolei robią się czerwone, a koło miga na żółto i czerwono. Najprostszy test: przeciągnij plik do okna przeglądarki - animacja musi się zapętlać.
Podgląd strony po tym kroku
Etap 2: Strona HTML
Kroki 4-22 · po tym etapie masz 17 z 38 kryteriów (pkt)
Krok 4: Plik index.html w HTML5
ok. 2 min
Polecenie z arkusza
Składa się ze strony głównej index.html oraz podstrony kolo.html. Cechy wspólne dla obu stron: zapisane w języku HTML5
<!DOCTYPE html> i szkielet strony głównej. Podstrona kolo.html powstanie później jako kopia gotowej strony - obie mają ten sam nagłówek, menu i stopkę, więc nie ma sensu pisać ich dwa razy.
R.2.1 W plikach index.html lub kolo.html znajduje się deklaracja HTML5 <!DOCTYPE HTML> i deklaracja języka zawartości witryny: polski np. <html lang="pl">
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 wie, że nie musi proponować tłumaczenia. Z <!DOCTYPE html> to jedno kryterium (R.2.1).
R.2.2 W sekcji head znajduje się jawnie podany standard kodowania polskich znaków i tytuł strony "Pola figur"
ok. 1 min
Polecenie z arkusza
Tytuł strony widoczny na karcie przeglądarki: „Pola figur”
<title> to tekst karty (z kodowaniem - R.2.2). <meta name="viewport"> każe telefonowi pokazać stronę w jego prawdziwej szerokości, zamiast udawać ekran szeroki na ok. 980 px i pomniejszać wszystko. Arkusz tego nie wymaga.
R.3.2 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl.css formatowanie CSS pochodzi jedynie z tego arkusza
ok. 1 min
Polecenie z arkusza
Arkusz stylów w pliku o nazwie styl.css prawidłowo połączony z kodem strony
<link rel="stylesheet" href="styl.css"> - znacznik pusty, w HTML5 bez ukośnika />. Całe formatowanie pochodzi z tego pliku (R.3.2); w HTML nie ma żadnego atrybutu style.
R.2.3 W sekcji body zdefiniowany jest podział na bloki za pomocą semantycznych znaczników HTML5: header, main->nav+section+aside, footer (dopuszcza się stosowanie bloków pomocniczych)
ok. 2 min
Polecenie z arkusza
Podział strony na bloki zrealizowany za pomocą semantycznych znaczników bloków języka HTML5 tak, aby po uruchomieniu w przeglądarce układ bloków na stronie był zgodny z ilustracją 4. Zawartość bloku głównego: bloki nawigacyjny, sekcji i boczny
Klucz R.2.3 wymienia znaczniki: header, main z nav, section i aside w środku, footer. Kolejność w <main> to kolejność kolumn z ilustracji 4: menu, figura, kalkulator. Trzy bloki są jedynymi dziećmi <main>, więc siatka ustawiona na <main> rozłoży je w kolumny bez dodatkowych klas.
W tym arkuszu dwie ilustracje mają numer 4 (układ bloków i wynik dla trójkąta) - tutaj chodzi o układ.
R.2.5 W bloku nawigacyjnym umieszczona jedna lista punktowana z dwoma elementami, zastosowane znaczniki <ul> i <li>
ok. 2 min
Polecenie z arkusza
Lista punktowana (nieuporządkowana) z dwoma odsyłaczami o treści „Prostokąt i trójkąt”, prowadzący do strony index.html oraz „Okrąg i koło”, prowadzący do strony kolo.html
<ul> z dwoma <li>, w każdym odnośnik z adresem względnym - obie strony leżą w tym samym folderze (R.2.5). Atrybut aria-current="page" przy odnośniku do bieżącej strony mówi czytnikowi ekranu „jesteś tutaj”; na kolo.html przejdzie na drugi odnośnik. Ten sam atrybut przyda się, gdyby menu miało kiedyś wyróżniać bieżącą stronę w CSS ([aria-current]).
Zawartość bloku sekcji strony index.html: Obraz 1d.bmp z tekstem alternatywnym „Figura”
Duży trójkąt na start, z id="figure" - po nim skrypt znajdzie obraz i podmieni plik. Pliki BMP zostają w oryginalnym formacie, jak każe arkusz; przeglądarki wyświetlają BMP bez problemu.
R.2.6 Na stronie głównej w bloku sekcji umieszczone grafiki z tekstem alternatywnym: 1d.bmp , "Figura"; 1m.bmp , "Wybierz trójkąt"; 2m.bmp , "Wybierz prostokąt" (dopuszcza się dla obrazów 1m i 2m przycisk z obrazem)
R.3.6 Do grafik 1m.bmp i 2m.bmp przypisana jest klasa
ok. 2 min
Polecenie z arkusza
Poniżej obok siebie dwa obrazy: 1m.bmp z tekstem alternatywnym „Wybierz trójkąt” oraz 2m.bmp, z tekstem alternatywnym „Wybierz prostokąt”. Kliknięcie dowolnego z tych obrazów uruchamia skrypt 1. Do obu obrazów należy przypisać tę samą klasę
Miniatury stoją w bloku pomocniczym<div class="thumbnails"> - blok zawsze zaczyna się w nowej linii, więc są „poniżej” dużej figury bez znacznika <br>, który służy do łamania wierszy tekstu, a nie do układania obrazów. W bloku obrazy są elementami liniowymi i stają obok siebie.
Oba obrazy mają tę samą klasę choice (R.3.6) - na nią czeka styl cienia. Obsługę kliknięcia dopisze skrypt.
R.2.4 W bloku nagłówkowym umieszczony <h2>: "Pola figur płaskich", w nawigacyjnym <h3> "MENU", na stronie głównej <h3> "Pole prostokąta / pole trójkąta" oraz w stopce <p> z numerem zdającego
ok. 1 min
Polecenie z arkusza
Zawartość bloku bocznego strony index.html, rozkład elementów zgodny z ilustracją 2: Nagłówek trzeciego stopnia o treści: „Pole prostokąta / pole trójkąta”
Drugi <h3> na stronie. Na stronie są już wszystkie nagłówki i akapit z R.2.4: <h2> w nagłówku, dwa <h3> i <p> w stopce.
R.3.7 Przynajmniej jedna etykieta jest powiązana z polem edycyjnym
ok. 2 min
Polecenie z arkusza
Etykieta „Bok prostokąta / podstawa trójkąta:” oraz pole edycyjne powiązane z etykietą
<label for="side-a"> wskazuje id pola (R.3.7) - kliknięcie napisu ustawia kursor w polu, a czytnik ekranu przeczyta napis jako opis pola. Identyfikator side-a w stylu „z myślnikami”, typowym dla HTML i CSS.
Pole type="number" z step="any": domyślny krok pola liczbowego to 1, więc bez step="any" przeglądarka oznaczyłaby bok 2,5 jako błędny. min="0" podpowiada, że ujemne długości nie mają sensu. Między etykietą a polem nie ma <br> - etykietę nad polem postawi CSS.
Etykieta „Drugi bok prostokąta / wysokość trójkąta:” oraz pole edycyjne powiązane z etykietą
To samo dla drugiej wartości: for="side-b" i id="side-b". Każde id może wystąpić na stronie tylko raz - inaczej etykieta nie wiedziałaby, które pole opisuje.
R.2.7 Na stronie głównej umieszczone dwa pola edycyjne oraz przycisk Oblicz
ok. 1 min
Polecenie z arkusza
Przycisk „Oblicz”, którego wciśnięcie powoduje wywołanie skryptu 2
type="button" mówi wprost: ten przycisk niczego nie wysyła, zrobi tylko to, co każe mu skrypt. To ważne, gdyby kalkulator trafił kiedyś do <form> - przycisk bez typu wysłałby wtedy formularz i przeładował stronę. Na stronie są dwa pola i przycisk (R.2.7).
Paragraf przeznaczony na wynik. W stanie początkowym jest on pusty
<p id="result"> - pusty, pod przyciskiem. aria-live="polite" sprawia, że czytnik ekranu sam przeczyta nowy wynik, gdy skrypt go wpisze - bez tego osoba niewidoma nie wiedziałaby, że coś się zmieniło.
R.2.8 Na podstronie umieszczona animacja/grafika z kołem, z tekstem alternatywnym "koło"
R.3.3 Wybranie odnośnika "Prostokąt i trójkąt" otwiera stronę główną, "Okrąg i koło" otwiera podstronę
ok. 2 min
Polecenie z arkusza
Zawartość bloku sekcji strony kolo.html: Animacja kolo.gif z tekstem alternatywnym „koło”
Zapisz jakokolo.html - przychodzą razem wszystkie cechy wspólne: nagłówek strony, styl, menu i stopka. W sekcji zamiast figury i miniatur jest animacja z alt="koło", a aria-current="page" przechodzi na odnośnik „Okrąg i koło”. Teraz oba odnośniki działają: „Prostokąt i trójkąt” otwiera stronę główną, „Okrąg i koło” - podstronę (R.3.3).
R.2.9 Na podstronie umieszczony paragraf o treści: Pole koła: P = Π * r2
ok. 2 min
Polecenie z arkusza
Zawartość bloku bocznego strony kolo.html: Paragraf o treści „Pole koła: P = Π * r2”. Litera Pi (Π) powinna być zapisana za pomocą znaku specjalnego; oznaczenie potęgi powinno znajdować się w indeksie górnym.
Kalkulator w bloku bocznym zastępuje jeden akapit. Π to encja nazwana z tabeli 1 arkusza (to samo daje Π), a <sup> podnosi dwójkę do indeksu górnego: r<sup>2</sup>. <sup> jest tu na miejscu, bo potęga to część treści, a nie ozdoba - czytnik ekranu też ją rozpozna.
⚠️ Sprzeczność w arkuszu: polecenie i tabela 1 każą użyć wielkiej litery Π (Π), a ilustracja 3 pokazuje małą π (π), poprawną matematycznie we wzorze na pole koła. Klucz CKE przyjmuje Π - na egzaminie punkt daje wersja z klucza.
Typowe błędy
„r2” zwykłym tekstem albo π wklejone ze schowka nie spełnia wymagań: potęga ma być w <sup>, a Pi - znakiem specjalnym.
Kroki 23-36 · po tym etapie masz 28 z 38 kryteriów (pkt)
Krok 23: Zmienne CSS z kolorami arkusza
ok. 2 min
Polecenie z arkusza
Styl CSS zdefiniowany jest w całości w zewnętrznym pliku o nazwie styl.css.
Plik styl.css zaczyna się od zmiennych CSS w :root. Nazwy opisują rolę koloru, nie sam kolor: --color-side to tło obu bocznych kolumn - gdyby ktoś zmienił DodgerBlue na inny odcień, nazwa zmiennej nadal będzie prawdziwa. W regułach kolor pojawia się jako var(--color-side). Podgląd wraca na stronę główną.
R.4.1 styl domyślny dla wszystkich selektorów (*): krój czcionki Garamond, serif (dozwolona tylko taka kolejność)
ok. 1 min
Polecenie z arkusza
Domyślnie, dla wszystkich selektorów: krój czcionki Garamond, w przypadku braku serif
Selektor * (R.4.1) obejmuje też pola i przycisk, które domyślnie mają krój systemowy. Najpierw Garamond, na końcu rodzina zapasowa serif - klucz dopuszcza tylko taką kolejność.
R.4.3 kolor czcionki: blok nagłówkowy i stopka - biały
R.4.7 odstęp między literami: blok nagłówkowy i stopka - letter-spacing: 3px;
ok. 2 min
Polecenie z arkusza
Wspólne dla bloku nagłówkowego i stopki: kolor tła Navy, biały kolor czcionki, wyrównanie tekstu do środka, marginesy wewnętrzne 5 px, odstępy między literami 3 px
Jedna reguła dla dwóch selektorów. letter-spacing: 3px rozstrzela litery, jak „P o l a” na ilustracji 2 (R.4.7).
Dodatkowo dla bloku nawigacyjnego i bocznego: kolor tła DodgerBlue, szerokość 35%
Tło ze zmiennej. Szerokości tu nie ma - wszystkie trzy kolumny wyznaczy jedna linia siatki w kroku układu. Klucz R.4.4 dopuszcza to wprost: „szerokość (width lub grid-template-columns lub flex)”.
R.4.2 kolor tła: blok nagłówkowy i stopka - Navy, blok nawigacyjny i boczny - DodgerBlue, blok sekcji - SkyBlue
ok. 1 min
Polecenie z arkusza
Dodatkowo dla bloku sekcji: kolor tła SkyBlue, szerokość 30%, wyrównanie tekstu do środka
text-align: center działa też na obrazy, bo są elementami liniowymi - duża figura i obie miniatury stają na środku sekcji. Z tą regułą jest komplet kolorów tła (R.4.2).
R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z ilustracją 4 w arkuszu egzaminacyjnym (prawidłowo zastosowano 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)
R.4.4 szerokość: blok nawigacyjny i boczny - 35%, blok sekcji - 30% (width lub grid-template- columns lub flex) wysokość: blok nawigacyjny, boczny oraz blok sekcji - 500px
ok. 3 min
Polecenie z arkusza
Podział strony na bloki zrealizowany za pomocą semantycznych znaczników bloków języka HTML5 tak, aby po uruchomieniu w przeglądarce układ bloków na stronie był zgodny z ilustracją 4
<main> staje się siatką o trzech kolumnach: grid-template-columns: 35% 30% 35% - menu, sekcja i blok boczny wpadają do kolumn w kolejności z HTML. Szerokości wszystkich bloków stoją w jednej linii, więc od razu widać, że sumują się do 100%. Nagłówek i stopka są poza siatką, więc stoją nad i pod nią - bez float i bez clear (R.3.1). Z tą regułą są komplet wymiarów (R.4.4): szerokości w siatce i wysokości 500 px.
Typowe błędy
Odstęp gap przy kolumnach w procentach dokłada się do 100% - siatka wyjechałaby poza ekran. Przy procentach z arkusza odstępów nie ma.
Zawartość bloku bocznego strony index.html, rozkład elementów zgodny z ilustracją 2
Na ilustracji 2 każde pole stoi pod swoją etykietą, a przycisk pod drugim polem. display: block dla etykiet i pól kalkulatora daje każdemu z nich własną linię - to samo, co <br> w wersji podstawowej, ale wygląd zostaje w CSS, a HTML opisuje tylko treść. Selektory z aside nie ruszają innych etykiet na stronie.
Krok 33: Pierwsza litera nagłówka dwa razy większa
Kryteria:
R.4.9 pseudoelement first-letter dla nagłówka trzeciego stopnia: rozmiar czcionki 200%
ok. 2 min
Polecenie z arkusza
Dla selektora nagłówka trzeciego stopnia: pierwsza litera nagłówka ma rozmiar czcionki 200%
Pseudoelement ::first-letter (R.4.9) wybiera pierwszą literę tekstu - bez <span> w HTML. Podwójny dwukropek odróżnia pseudoelement (część elementu) od pseudoklasy (stanu, np. :hover); stary zapis z jednym dwukropkiem też działa.
R.4.10 styl klasy przypisanej do grafik 1m.bmp i 2m.bmp : box-shadow: 5px 5px 10px DimGray; zaokrąglenie rogów 10px, marginesy zewnętrzne 5px, kursor pointer
ok. 2 min
Polecenie z arkusza
Dla klasy przypisanej do grafik 1m.bmp i 2m.bmp: cień przesunięty o 5 px w pionie i poziomie, rozmycie 10 px kolor DimGray, zaokrąglenie rogów 10 px, marginesy zewnętrzne 5 px, kursor pointer.
box-shadow: 5px 5px 10px - przesunięcie w poziomie, w pionie, rozmycie, potem kolor ze zmiennej (R.4.10). cursor: pointer zmienia strzałkę w rączkę: miniaturę da się kliknąć.
Kliknięcie dowolnego z tych obrazów uruchamia skrypt 1
Miniatury będzie można wybrać także klawiszem Tab. :focus-visible rysuje granatową obwódkę tylko wtedy, gdy fokus przyszedł z klawiatury - kliknięcie myszą jej nie pokaże. Bez widocznego fokusu osoba korzystająca z klawiatury nie wie, na czym jest. Klucz tego nie ocenia.
Kroki 37-48 · po tym etapie masz 38 z 38 kryteriów (pkt)
Krok 37: Plik skrypt.js dołączony z atrybutem defer
ok. 2 min
Polecenie z arkusza
Wykonywane po stronie klienta, na stronie index.html
Skrypt mieszka w osobnym pliku skrypt.js, dołączonym tylko do index.html (podstrona go nie potrzebuje). <script src="skrypt.js" defer> stoi w <head>, a defer każe przeglądarce pobrać plik od razu, ale wykonać go dopiero po wczytaniu całego HTML - skrypt znajdzie wszystkie elementy, choć jest dołączony na górze. Arkusz pozwala na dodatkowe pliki, a osobny plik trafia na płytę razem ze stroną.
Typowe błędy
Skrypt w <head> bez defer wykona się przed wczytaniem <body> - document.querySelector("#figure") zwróci null.
R.5.1 Skrypt 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
Należy stosować znaczące nazewnictwo zmiennych i funkcji w języku polskim lub angielskim
Wszystko, czym różnią się figury, trafia do jednego obiektu: klucz triangle albo rectangle, a w środku plik dużego obrazu i nazwa do wyniku. Dalej skrypt nie będzie miał ani jednej nazwy pliku wpisanej w kod funkcji - dołożenie trzeciej figury (np. trapezu) to jeden wpis w obiekcie.
const - tej zmiennej nikt nie nadpisze. Nazwa wielkimi literami to umowa: „stała konfiguracja, nie stan”. To pierwsza instrukcja JavaScript na stronie (R.5.1).
skrypt.jsJavaScriptzmienione: 6 linii
// Skrypty strony index.html// Figury do wyboru: wszystko, czym się różniąconst FIGURES = { triangle: { image: '1d.bmp', name: 'trójkąta' }, rectangle: { image: '2d.bmp', name: 'prostokąta' },};
Podgląd strony po tym kroku (index.html)
Krok 39: Elementy strony i wybrana figura
ok. 2 min
Polecenie z arkusza
Obliczenia powinny też działać dla stanu początkowego witryny (Skrypt 1 nie wykonał się ani razu), wtedy liczone jest pole trójkąta
Elementy, których skrypt będzie używał, wyszukuje raz i trzyma w stałych: querySelector przyjmuje selektor CSS (#figure - identyfikator), więc ten sam zapis co w styl.css.
let currentFigure = 'triangle' to stan strony: która figura jest wybrana. Wartość startowa to trójkąt - dokładnie stan początkowy z arkusza, w którym duży obraz to 1d.bmp. let, bo ta zmienna będzie się zmieniać po kliknięciu miniatury.
skrypt.jsJavaScriptzmienione: 6 linii
// Skrypty strony index.html// Figury do wyboru: wszystko, czym się różniąconst FIGURES = { triangle: { image: '1d.bmp', name: 'trójkąta' }, rectangle: { image: '2d.bmp', name: 'prostokąta' },};const figureImage = document.querySelector('#figure');const sideA = document.querySelector('#side-a');const sideB = document.querySelector('#side-b');const result = document.querySelector('#result');let currentFigure = 'triangle'; // stan początkowy: duży obraz to 1d.bmp
Podgląd strony po tym kroku (index.html)
Krok 40: Skrypt 1: funkcja wybierająca figurę
ok. 2 min
Polecenie z arkusza
Skrypt 1: gdy kliknięto w obraz 1m.bmp to duży obraz powyżej ustawiany jest na 1d.bmp, gdy kliknięto w obraz 2m.bmp to duży obraz powyżej ustawiany jest na 2d.bmp
selectFigure robi dwie rzeczy: zapamiętuje wybór w currentFigure i podmienia plik dużego obrazu na ten z obiektu FIGURES. Jedna funkcja obsłuży obie miniatury - różnią się tylko kluczem figury w parametrze.
skrypt.jsJavaScriptzmienione: 6 linii
// Skrypty strony index.html// Figury do wyboru: wszystko, czym się różniąconst FIGURES = { triangle: { image: '1d.bmp', name: 'trójkąta' }, rectangle: { image: '2d.bmp', name: 'prostokąta' },};const figureImage = document.querySelector('#figure');const sideA = document.querySelector('#side-a');const sideB = document.querySelector('#side-b');const result = document.querySelector('#result');let currentFigure = 'triangle'; // stan początkowy: duży obraz to 1d.bmp// Skrypt 1: wybór figury miniaturąfunction selectFigure(figure) { currentFigure = figure; figureImage.src = FIGURES[figure].image;}
Podgląd strony po tym kroku (index.html)
Krok 41: Skrypt 1: kliknięcie miniatury trójkąta
Kryteria: ,
R.5.2 Po kliknięciu w obraz 1m.bmp duży obraz zmieniany jest na 1d.bmp (trójkąt)
R.3.4 Zdefiniowane dla przynajmniej jednej grafiki zdarzenie związane z jej kliknięciem, które uruchamia funkcję skryptu (obsługa zdarzenia zdefiniowana w HTML np. onClick lub w skrypcie np.: element.addEventListener(...), element.onClick = …)
ok. 3 min
Polecenie z arkusza
Gdy kliknięto w obraz 1m.bmp to duży obraz powyżej ustawiany jest na 1d.bmp
Miniatura trójkąta dostaje atrybut data-figure="triangle" - własny atrybut danych, który skrypt czyta jako thumbnail.dataset.figure. Skrypt wyszukuje wszystkie elementy z tym atrybutem ([data-figure]) i każdemu przypina obsługę kliknięcia: addEventListener('click', ...) (R.3.4). Funkcja strzałkowa () => ... to krótki zapis funkcji wywoływanej przy kliknięciu.
Podział ról: klasa choice jest dla stylu, data-figure - dla zachowania. Kliknięcie trójkąta ustawia 1d.bmp (R.5.2).
R.5.3 Po kliknięciu w obraz 2m.bmp duży obraz zmieniany jest na 2d.bmp (prostokąt)
ok. 1 min
Polecenie z arkusza
Gdy kliknięto w obraz 2m.bmp to duży obraz powyżej ustawiany jest na 2d.bmp
Wystarczy atrybut data-figure="rectangle" w HTML - pętla z poprzedniego kroku sama znajdzie drugą miniaturę i przypnie jej to samo kliknięcie, a obiekt FIGURES podpowie plik 2d.bmp (R.5.3). W skrypcie nie zmienia się ani jedna linia. Kliknij miniatury w podglądzie: duża figura zmienia się na prostokąt i z powrotem.
Kliknięcie dowolnego z tych obrazów uruchamia skrypt 1
Obraz nie jest przyciskiem, więc klawiatura go nie zauważa. tabindex="0" dodaje obie miniatury do kolejki klawisza Tab, a obsługa keydown reaguje na Enter i spację - tak jak działa prawdziwy przycisk. event.preventDefault() przy spacji powstrzymuje przewinięcie strony.
Klucz tego nie ocenia (R.2.6 dopuszcza nawet <button> z obrazem w środku, który miałby to wszystko wbudowane), ale bez tego osoba, która nie używa myszy, nie wybierze prostokąta.
// Skrypty strony index.html// Figury do wyboru: wszystko, czym się różniąconst FIGURES = { triangle: { image: '1d.bmp', name: 'trójkąta' }, rectangle: { image: '2d.bmp', name: 'prostokąta' },};const figureImage = document.querySelector('#figure');const sideA = document.querySelector('#side-a');const sideB = document.querySelector('#side-b');const result = document.querySelector('#result');let currentFigure = 'triangle'; // stan początkowy: duży obraz to 1d.bmp// Skrypt 1: wybór figury miniaturąfunction selectFigure(figure) { currentFigure = figure; figureImage.src = FIGURES[figure].image;}document.querySelectorAll('[data-figure]').forEach((thumbnail) => { thumbnail.addEventListener('click', () => selectFigure(thumbnail.dataset.figure)); thumbnail.addEventListener('keydown', (event) => {if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); selectFigure(thumbnail.dataset.figure); } });});
Podgląd strony po tym kroku (index.html)
Krok 44: Skrypt 2: dane z pól edycyjnych
Kryteria: ,
R.5.4 Skrypt 2 pobiera dane z dwóch pól edycyjnych
R.3.5 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.: element.addEventListener(...), element.onClick = …)
ok. 2 min
Polecenie z arkusza
Skrypt 2: pobiera dane z pól edycyjnych
calculateArea odczytuje oba pola właściwością valueAsNumber (R.5.4): pole type="number" oddaje wtedy od razu liczbę, a dla pustego pola - NaN („nie liczba”). Zwykłe value dałoby tekst „5”, a tekst przy dodawaniu skleja się zamiast sumować ("5" + "10" to „510”).
Przycisk dostaje obsługę kliknięcia przez addEventListener (R.3.5) - bez onclick w HTML.
skrypt.jsJavaScriptzmienione: 8 linii
// Skrypty strony index.html// Figury do wyboru: wszystko, czym się różniąconst FIGURES = { triangle: { image: '1d.bmp', name: 'trójkąta' }, rectangle: { image: '2d.bmp', name: 'prostokąta' },};const figureImage = document.querySelector('#figure');const sideA = document.querySelector('#side-a');const sideB = document.querySelector('#side-b');const result = document.querySelector('#result');let currentFigure = 'triangle'; // stan początkowy: duży obraz to 1d.bmp// Skrypt 1: wybór figury miniaturąfunction selectFigure(figure) { currentFigure = figure; figureImage.src = FIGURES[figure].image;}document.querySelectorAll('[data-figure]').forEach((thumbnail) => { thumbnail.addEventListener('click', () => selectFigure(thumbnail.dataset.figure)); thumbnail.addEventListener('keydown', (event) => {if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); selectFigure(thumbnail.dataset.figure); } });});// Skrypt 2: pole wybranej figuryfunction calculateArea() {const a = sideA.valueAsNumber;const b = sideB.valueAsNumber;}document.querySelector('#calculate').addEventListener('click', calculateArea);
Podgląd strony po tym kroku (index.html)
Krok 45: Skrypt 2: pole prostokąta
Kryteria:
R.5.6 Po wybraniu grafiki prostokąta skrypt liczy pole prostokąta na podstawie danych
ok. 3 min
Polecenie z arkusza
Gdy w bloku głównym wybrano prostokąt (duży obraz to 2d.bmp), to na podstawie danych jest liczone pole prostokąta (ilustracja 5)
Wzór trafia do obiektu: prostokąt dostaje funkcję area: (a, b) => a * b (R.5.6). W calculateArea wybrana figura to FIGURES[currentFigure], a jej pole - figure.area(a, b).
Wersja podstawowa sprawdzała, która figura jest wybrana, porównując getAttribute("src") z nazwą pliku. Tu decyduje zmienna currentFigure ustawiana razem z obrazem w selectFigure - wynik jest ten sam, a skrypt nie zależy od nazw plików ani od tego, czy przeglądarka zapisze w src pełny adres.
skrypt.jsJavaScriptzmienione: 3 linie
// Skrypty strony index.html// Figury do wyboru: wszystko, czym się różniąconst FIGURES = { triangle: { image: '1d.bmp', name: 'trójkąta' }, rectangle: { image: '2d.bmp', name: 'prostokąta', area: (a, b) => a * b },};const figureImage = document.querySelector('#figure');const sideA = document.querySelector('#side-a');const sideB = document.querySelector('#side-b');const result = document.querySelector('#result');let currentFigure = 'triangle'; // stan początkowy: duży obraz to 1d.bmp// Skrypt 1: wybór figury miniaturąfunction selectFigure(figure) { currentFigure = figure; figureImage.src = FIGURES[figure].image;}document.querySelectorAll('[data-figure]').forEach((thumbnail) => { thumbnail.addEventListener('click', () => selectFigure(thumbnail.dataset.figure)); thumbnail.addEventListener('keydown', (event) => {if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); selectFigure(thumbnail.dataset.figure); } });});// Skrypt 2: pole wybranej figuryfunction calculateArea() {const a = sideA.valueAsNumber;const b = sideB.valueAsNumber;const figure = FIGURES[currentFigure];const area = figure.area(a, b);}document.querySelector('#calculate').addEventListener('click', calculateArea);
Podgląd strony po tym kroku (index.html)
Krok 46: Skrypt 2: pole trójkąta, także na starcie
Kryteria:
R.5.5 Po wybraniu grafiki trójkąta skrypt liczy pole trójkąta na podstawie danych
ok. 2 min
Polecenie z arkusza
Gdy w bloku głównym wybrano trójkąt (duży obraz to 1d.bmp) to na podstawie danych jest liczone pole trójkąta (ilustracja 4)
Trójkąt dostaje wzór (a, b) => a * b / 2 - podstawa razy wysokość przez dwa (R.5.5). W calculateArea nie zmienia się nic: drabinkę if/else zastąpił wybór wzoru z obiektu. Stan początkowy jest obsłużony od kroku ze zmienną currentFigure = 'triangle' - zanim ktokolwiek kliknie miniaturę, liczy się pole trójkąta.
skrypt.jsJavaScriptzmienione: 1 linia
// Skrypty strony index.html// Figury do wyboru: wszystko, czym się różniąconst FIGURES = { triangle: { image: '1d.bmp', name: 'trójkąta', area: (a, b) => a * b / 2 }, rectangle: { image: '2d.bmp', name: 'prostokąta', area: (a, b) => a * b },};const figureImage = document.querySelector('#figure');const sideA = document.querySelector('#side-a');const sideB = document.querySelector('#side-b');const result = document.querySelector('#result');let currentFigure = 'triangle'; // stan początkowy: duży obraz to 1d.bmp// Skrypt 1: wybór figury miniaturąfunction selectFigure(figure) { currentFigure = figure; figureImage.src = FIGURES[figure].image;}document.querySelectorAll('[data-figure]').forEach((thumbnail) => { thumbnail.addEventListener('click', () => selectFigure(thumbnail.dataset.figure)); thumbnail.addEventListener('keydown', (event) => {if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); selectFigure(thumbnail.dataset.figure); } });});// Skrypt 2: pole wybranej figuryfunction calculateArea() {const a = sideA.valueAsNumber;const b = sideB.valueAsNumber;const figure = FIGURES[currentFigure];const area = figure.area(a, b);}document.querySelector('#calculate').addEventListener('click', calculateArea);
Podgląd strony po tym kroku (index.html)
Krok 47: Skrypt 2: wynik w akapicie pod przyciskiem
Kryteria: ,
R.5.7 Wynik jest wyświetlany pod przyciskiem
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. 2 min
Polecenie z arkusza
Wynik wyświetlany jest w paragrafie pod przyciskiem
Szablon tekstowy w odwrotnych apostrofach wstawia wartości w ${...}: „Pole trójkąta: 25”. Opis słowami mówi, czego dotyczy liczba - ilustracje 4 i 5 pokazują samą liczbę, a klucz ocenia, że wynik stoi pod przyciskiem (R.5.7).
textContent zamiast innerHTML: wpisuje zwykły tekst, którego przeglądarka nie interpretuje jako HTML. Nazwy mówią, do czego służą: FIGURES, currentFigure, selectFigure, calculateArea, figureImage, result (R.5.8).
skrypt.jsJavaScriptzmienione: 1 linia
// Skrypty strony index.html// Figury do wyboru: wszystko, czym się różniąconst FIGURES = { triangle: { image: '1d.bmp', name: 'trójkąta', area: (a, b) => a * b / 2 }, rectangle: { image: '2d.bmp', name: 'prostokąta', area: (a, b) => a * b },};const figureImage = document.querySelector('#figure');const sideA = document.querySelector('#side-a');const sideB = document.querySelector('#side-b');const result = document.querySelector('#result');let currentFigure = 'triangle'; // stan początkowy: duży obraz to 1d.bmp// Skrypt 1: wybór figury miniaturąfunction selectFigure(figure) { currentFigure = figure; figureImage.src = FIGURES[figure].image;}document.querySelectorAll('[data-figure]').forEach((thumbnail) => { thumbnail.addEventListener('click', () => selectFigure(thumbnail.dataset.figure)); thumbnail.addEventListener('keydown', (event) => {if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); selectFigure(thumbnail.dataset.figure); } });});// Skrypt 2: pole wybranej figuryfunction calculateArea() {const a = sideA.valueAsNumber;const b = sideB.valueAsNumber;const figure = FIGURES[currentFigure]; result.textContent = `Pole ${figure.name}: ${figure.area(a, b)}`;}document.querySelector('#calculate').addEventListener('click', calculateArea);
Podgląd strony po tym kroku (index.html)
Krok 48: Skrypt 2: sprawdzenie danych
ok. 2 min
Polecenie z arkusza
Skrypt 2: pobiera dane z pól edycyjnych
Wersja podstawowa z egzaminu dla pustych pól pokazuje pole 0, a dla podstawy -4 - pole -20. Warunek !(a > 0 && b > 0) łapie wszystko naraz: puste pole (NaN > 0 to fałsz), zero i liczby ujemne. Wtedy zamiast wyniku jest komunikat, a return kończy funkcję - to „wczesne wyjście”, dzięki któremu dalsza część funkcji nie potrzebuje już else.
skrypt.jsJavaScriptzmienione: 4 linie
// Skrypty strony index.html// Figury do wyboru: wszystko, czym się różniąconst FIGURES = { triangle: { image: '1d.bmp', name: 'trójkąta', area: (a, b) => a * b / 2 }, rectangle: { image: '2d.bmp', name: 'prostokąta', area: (a, b) => a * b },};const figureImage = document.querySelector('#figure');const sideA = document.querySelector('#side-a');const sideB = document.querySelector('#side-b');const result = document.querySelector('#result');let currentFigure = 'triangle'; // stan początkowy: duży obraz to 1d.bmp// Skrypt 1: wybór figury miniaturąfunction selectFigure(figure) { currentFigure = figure; figureImage.src = FIGURES[figure].image;}document.querySelectorAll('[data-figure]').forEach((thumbnail) => { thumbnail.addEventListener('click', () => selectFigure(thumbnail.dataset.figure)); thumbnail.addEventListener('keydown', (event) => {if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); selectFigure(thumbnail.dataset.figure); } });});// Skrypt 2: pole wybranej figuryfunction calculateArea() {const a = sideA.valueAsNumber;const b = sideB.valueAsNumber;if (!(a > 0 && b > 0)) { result.textContent = 'Podaj dwie liczby większe od zera.';return; }const figure = FIGURES[currentFigure]; result.textContent = `Pole ${figure.name}: ${figure.area(a, b)}`;}document.querySelector('#calculate').addEventListener('click', calculateArea);
Podgląd strony po tym kroku (index.html)
Etap 5: Porównanie z wersją podstawową
Kroki 49-50 · po tym etapie masz 38 z 38 kryteriów (pkt)
Krok 49: Co jest inaczej i dlaczego
ok. 3 min
Polecenie z arkusza
Ocenie będzie podlegać 5 rezultatów: animacja, zawartość witryny internetowej, działanie witryny internetowej, styl CSS witryny internetowej oraz skrypt.
Obie wersje dają te same punkty. Różnice:
wersja podstawowa
ta wersja
układ
display: flex na <main>, szerokości w trzech regułach
display: grid, grid-template-columns: 35% 30% 35%
kolory
wpisane w regułach
zmienne w :root
łamanie linii
<br> w HTML
blok .thumbnails i display: block w CSS
zdarzenia
onclick w HTML
addEventListener w skrypt.js z defer
wybrana figura
porównanie getAttribute("src")
zmienna currentFigure i obiekt FIGURES
wynik
innerHTML z samą liczbą
textContent z opisem, aria-live
złe dane
wynik 0 albo ujemny
komunikat
klawiatura
brak
Tab, Enter, spacja, widoczny fokus
W podglądzie tej wersji sprawdzone są w Chrome: kliknięcia obu miniatur, wybór Enterem i spacją, wynik 25 i 50 z ilustracji, liczba niecałkowita (2,5 × 4 = 10) oraz puste i ujemne pole.
Czas przeznaczony na wykonanie zadania wynosi 150 minut.
Wersja podstawowa, gdy liczy się czas: onclick i getElementById są w tabeli 2 arkusza, a cały skrypt to kilkanaście linii w jednym pliku.
Ta wersja, gdy addEventListener, obiekty i funkcje strzałkowe są pisane z pamięci. Osobny plik skrypt.js trzeba pamiętać nagrać na płytę - bez niego miniatury i kalkulator przestaną działać.
Mieszanie jest dopuszczalne: siatka z tej wersji i skrypt z podstawowej dadzą pełne punkty.
Krok 51 · po tym etapie masz 38 z 38 kryteriów (pkt)
Krok 51: 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 przeglądarka.txt nazwa przeglądarki, w której strona była sprawdzana.
W folderze z numerem zdającego: 1d.bmp, 1m.bmp, 2d.bmp, 2m.bmp (bez zmian z archiwum), index.html, kolo.html, kolo.gif, parametry.jpg, przeglądarka.txt, styl.css oraz skrypt.js - bez niego strona główna nie zareaguje na kliknięcia. Po nagraniu sprawdź odczyt płyty.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
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: Bartosz Bryniarski. 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.