Przejdź do głównej treści
INF.03-05-24.01-SGStyczeń 2024 · 42 kroki · ok. 83 min · 35 kryteriów z klucza

Rozwiązanie krok po kroku: Salon kosmetyczny z bazą (Nowoczesny kod (grid, osobny skrypt))

To drugi sposób rozwiązania tego samego arkusza: baza salon z czterema zapytaniami (w tym nowy użytkownik i jego uprawnienia), dwa obrazy przeskalowane do zadanej szerokości, strony index.html i twarz.html z czterema blokami w dwóch kolumnach, style w styl7.css i kalkulator ceny wizyty w JavaScript. Obie wersje spełniają wszystkie 35 kryteriów klucza - różni je sposób pisania kodu, nie wynik.

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

  • SQL czytelnie: klauzule w osobnych liniach, aliasy kolumn wyniku (srednia_cena, liczba_uslug), sortowanie; uprawnienia nowego konta sprawdzone logowaniem na to konto,
  • układ na siatce CSS z nazwanymi obszarami: bloki o różnych wysokościach w dwóch kolumnach (400 + 330 px po lewej, 150 + 580 px po prawej) bez kontenera o sztywnej wysokości, bloki w znacznikach, które mówią, czym są (header, nav, main, aside), kolory w zmiennych,
  • kalkulator jako formularz: pola wyboru w etykietach <label> jedno pod drugim bez <br>,
  • skrypt w osobnym pliku kalkulator.js z defer: cennik w obiekcie, pola zebrane po wspólnej nazwie, suma liczona metodami tablic filter i reduce na właściwości checked.

Baza i grafiki pochodzą z prawdziwego archiwum materialy5 (załącznik do arkusza, hasło w treści zadania). Zapytania są policzone na MariaDB 10.4 - tej samej, która jest w XAMPP. Kalkulator jest sprawdzony w prawdziwej przeglądarce Chrome dla wszystkich 16 kombinacji zaznaczonych pól, a układ - pomiarem położenia bloków. W podglądzie strony twarz.html można zaznaczać zabiegi i klikać „Oblicz cenę”.

Jak liczą się punkty. Klucz ma 35 kryteriów (R.1.1 - R.5.6), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 27 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 35 kryteriów (pkt)

    Krok 1: Baza danych salon

    Kryteria:

    R.1.1 Wykonano import tabel do bazy danych salon czynność udokumentowano plikiem o nazwie import w formacie PNG

    ok. 2 min
    Polecenie z arkusza

    Utwórz bazę danych o nazwie salon.

    Rozpakuj materialy5.7z z pulpitu (hasło Do!!@rozp@#) do folderu z numerem zdającego: egzamin.sql, obraz1.jpg i obraz2.jpg. W phpMyAdmin: Nowa, nazwa salon, porównywanie np. utf8mb4_polish_ci.

    Tabele z egzamin.sql mają zestaw znaków zapisany we własnej definicji (latin1), więc wybór dla bazy ich nie zmienia - nazwy usług w danych są bez polskich liter („Masaz twarzy”).

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

    Kryteria:

    R.1.1 Wykonano import tabel do bazy danych salon czynność udokumentowano plikiem o nazwie import w formacie PNG

    ok. 2 min
    Polecenie z arkusza

    Do bazy salon zaimportuj tabele z pliku egzamin.sql z rozpakowanego archiwum.

    Zaznaczona baza salon, Import → egzamin.sql. W zadaniu potrzebne są dwie tabele z obrazu 1: uslugi (10 usług z ceną i rodzajem: 1 - kosmetyczne, 2 - fryzjerskie, 3 - inne) i kadra (pracownicy).

  3. Krok 3: Zrzut ekranu import.png

    Kryteria:

    R.1.1 Wykonano import tabel do bazy danych salon czynność udokumentowano plikiem o nazwie import w formacie PNG

    ok. 2 min
    Polecenie z arkusza

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

    Print Screen i zapis jako import.png - import w PNG, a zrzuty zapytań w JPEG (kw1.jpg - kw4.jpg), z widoczną treścią zapytania.

    Typowe błędy

    Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany.

  4. Krok 4: Zapytanie 1: usługi od 50 zł

    Kryteria: ,

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

    R.1.3 Wykonano zapytanie 1 wybierające jedynie pola nazwa i cena z tabeli uslugi dla usług, których cena jest wyższa lub równa 50 zł. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa, cena FROM uslugi WHERE cena >= 50; oraz wynik działania udokumentowano zrzutem, na którym widoczne są jedynie dane: Farbowanie 50; Ustalenie diety 70; Paznokcie 90

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 1: wybierające jedynie pola nazwa i cena z tabeli uslugi dla usług, których cena jest wyższa lub równa 50 zł.

    • SELECT nazwa, cena / FROM uslugi - dwie kolumny z tabeli usług,
    • WHERE cena >= 50 - „wyższa lub równa”; usługa za dokładnie 50 zł też się liczy,
    • ORDER BY cena - od najtańszej. Arkusz kolejności nie podaje, ale bez ORDER BY baza może oddać wiersze w dowolnej kolejności, a lista cen czyta się lepiej posortowana.

    Wynik: trzy usługi - Farbowanie 50, Ustalenie diety 70, Paznokcie 90 (R.1.3). Zapytanie do kwerendy.txt, zrzut kw1.jpg.

    Typowe błędy

    cena > 50 gubi Farbowanie za równe 50 zł.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT nazwa, cena
    FROM uslugi
    WHERE cena >= 50
    ORDER BY cena;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: średnia cena i liczba usług kosmetycznych

    Kryteria:

    R.1.4 Wykonano zapytanie 2 liczące jedynie dla usług kosmetycznych średnią arytmetyczną cen usług oraz liczbę usług. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT AVG(cena), COUNT(*) FROM uslugi WHERE rodzaj = 1; oraz wynik działania udokumentowano zrzutem, na którym widoczne są liczby 36 i 5

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 2: liczące średnią arytmetyczną cen usług oraz liczbę usług jedynie dla usług kosmetycznych.

    • AVG(cena) - średnia arytmetyczna, COUNT(*) - liczba wierszy; razem dają jeden wiersz wyniku,
    • AS srednia_cena, AS liczba_uslug - aliasy, czyli nazwy kolumn wyniku. Bez nich phpMyAdmin podpisze kolumny tekstem wyrażeń (AVG(cena)), a w PHP trzeba by się do nich odwoływać tym samym napisem,
    • WHERE rodzaj = 1 - usługi kosmetyczne (opis pola rodzaj w arkuszu).

    Wynik: 36 i 5 (R.1.4). Zrzut kw2.jpg.

    Typowe błędy

    WHERE rodzaj = 'kosmetyczne' nic nie znajdzie - rodzaj jest liczbą, nie nazwą.

    kwerendy.txt Tekst zmienione: 5 linii
    -- Zapytanie 1
    SELECT nazwa, cena
    FROM uslugi
    WHERE cena >= 50
    ORDER BY cena;
    
    -- Zapytanie 2
    SELECT AVG(cena) AS srednia_cena, COUNT(*) AS liczba_uslug
    FROM uslugi
    WHERE rodzaj = 1;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: użytkownik kosmetyczka

    Kryteria:

    R.1.5 Wykonano zapytanie 3 tworzące użytkownika kosmetyczka na localhost z hasłem Kosmet34 W pliku z kwerendami lub na zrzucie istnieje zapis np.: CREATE USER 'kosmetyczka'@'localhost' IDENTIFIED BY 'Kosmet34'; oraz wynik działania udokumentowano zrzutem, na którym widoczny jest komunikat o pomyślnym wykonaniu zapytania oraz zapytanie z jawnie podanym hasłem

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 3: tworzące użytkownika kosmetyczka na localhost z hasłem Kosmet34.

    • CREATE USER 'kosmetyczka'@'localhost' - konto to para nazwa@host; localhost pozwala logować się tylko z tego samego komputera,
    • IDENTIFIED BY 'Kosmet34' - hasło podane jawnie, baza zapisuje tylko jego skrót.

    phpMyAdmin pokazuje komunikat o wykonaniu zapytania. Zrzut kw3.jpg z widocznym zapytaniem i hasłem - tego wymaga klucz (R.1.5).

    Typowe błędy

    Konto założone kreatorem Konta użytkowników nie zostawia zapytania na zrzucie ani w kwerendach.

    kwerendy.txt Tekst zmienione: 4 linie
    -- Zapytanie 1
    SELECT nazwa, cena
    FROM uslugi
    WHERE cena >= 50
    ORDER BY cena;
    
    -- Zapytanie 2
    SELECT AVG(cena) AS srednia_cena, COUNT(*) AS liczba_uslug
    FROM uslugi
    WHERE rodzaj = 1;
    
    -- Zapytanie 3
    CREATE USER 'kosmetyczka'@'localhost'
    IDENTIFIED BY 'Kosmet34';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: prawa do tabeli uslugi

    Kryteria:

    R.1.6 Wykonano zapytanie 4 nadające prawa przeglądania danych i aktualizacji do tabeli uslugi bazy salon dla użytkownika kosmetyczka. W pliku z kwerendami lub na zrzucie istnieje zapis np.: GRANT SELECT, UPDATE ON uslugi TO 'kosmetyczka'@'localhost'; oraz wynik działania udokumentowano zrzutem, na którym widoczny jest komunikat o poprawnym wykonaniu zapytania

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 4: nadające prawa przeglądania danych i aktualizacji do tabeli uslugi bazy salon dla użytkownika kosmetyczka.

    • GRANT SELECT, UPDATE - „przeglądanie danych” to SELECT, „aktualizacja” to UPDATE,
    • ON salon.uslugi - jedna tabela jednej bazy,
    • TO 'kosmetyczka'@'localhost' - dokładnie konto z zapytania 3 (R.1.6).

    To zasada najmniejszych uprawnień: konto dostaje tylko to, czego potrzebuje do pracy. Sprawdzone logowaniem na konto kosmetyczka: odczyt i zmiana ceny w uslugi działają, a usunięcie wiersza (DELETE command denied) i odczyt tabeli kadra kończą się odmową. Zrzut kw4.jpg.

    Typowe błędy

    TO kosmetyczka bez hosta odwołuje się do konta kosmetyczka@'%' - innego niż utworzone, więc zapytanie kończy się błędem.

    kwerendy.txt Tekst zmienione: 5 linii
    -- Zapytanie 1
    SELECT nazwa, cena
    FROM uslugi
    WHERE cena >= 50
    ORDER BY cena;
    
    -- Zapytanie 2
    SELECT AVG(cena) AS srednia_cena, COUNT(*) AS liczba_uslug
    FROM uslugi
    WHERE rodzaj = 1;
    
    -- Zapytanie 3
    CREATE USER 'kosmetyczka'@'localhost'
    IDENTIFIED BY 'Kosmet34';
    
    -- Zapytanie 4
    GRANT SELECT, UPDATE
    ON salon.uslugi
    TO 'kosmetyczka'@'localhost';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strony HTML

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

    Krok 8: Obrazy: szerokość 240 i 700 px

    Kryteria:

    R.2.1 Przynajmniej jedną grafikę przeskalowano z zachowaniem proporcji. Wymiary dla obraz1.jpg szerokość 240 px i odpowiadająca temu wysokość 300 px (± 5 px) lub obraz2.jpg szerokość 700 px i odpowiadająca temu wysokość 296 px (± 5 px)

    ok. 3 min
    Polecenie z arkusza

    Plik obraz1.jpg, wypakowany z archiwum, należy przeskalować z zachowaniem proporcji tak, aby jego szerokość wynosiła dokładnie 240 px. Plik obraz2.jpg, wypakowany z archiwum, należy przeskalować z zachowaniem proporcji tak, aby jego szerokość wynosiła dokładnie 700 px.

    W GIMP-ie dla każdego pliku Obraz → Skaluj obraz z zamkniętym łańcuchem: obraz1.jpg - szerokość 240, wysokość wychodzi 300 px; obraz2.jpg - szerokość 700, wysokość 296 px (R.2.1). Plik → Nadpisz zostawia format JPG.

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

    Kryteria:

    R.2.2 Witrynę internetową zapisano w plikach index.html i twarz.html oraz na stronie zastosowano deklarację języka HTML5 <!DOCTYPE html>, zadeklarowano język witryny polski np. <html lang = "pl"> oraz zapisano jawnie właściwy standard kodowania polskich znaków

    ok. 1 min
    Polecenie z arkusza

    Cechy witryny: Składa się ze stron o nazwach index.html oraz twarz.html. Obie strony różnią się jedynie drugim blokiem prawym. Strony index.html i twarz.html zapisane w języku HTML 5.

    Najpierw w całości index.html - twarz.html będzie jej kopią z innym drugim blokiem prawym.

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

    Kryteria:

    R.2.2 Witrynę internetową zapisano w plikach index.html i twarz.html oraz na stronie zastosowano deklarację języka HTML5 <!DOCTYPE html>, zadeklarowano język witryny polski np. <html lang = "pl"> oraz zapisano jawnie właściwy standard kodowania polskich znaków

    ok. 1 min
    Polecenie z arkusza

    Ustawiony język zawartości stron na polski.

    Atrybut lang="pl" w <html>.

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

    Kryteria:

    R.2.2 Witrynę internetową zapisano w plikach index.html i twarz.html oraz na stronie zastosowano deklarację języka HTML5 <!DOCTYPE html>, zadeklarowano język witryny polski np. <html lang = "pl"> oraz zapisano jawnie właściwy standard kodowania polskich znaków

    ok. 1 min
    Polecenie z arkusza

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

    <meta charset="UTF-8"> (R.2.2), pod nim <meta name="viewport"> - telefon pokaże stronę w swojej szerokości. Arkusz drugiej linii nie wymaga.

    index.html HTML zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  12. Krok 12: Tytuł strony

    Kryteria:

    R.2.3 Stronie nadano tytuł: "Salon kosmetyczny"

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony widoczny na karcie przeglądarki: „Salon kosmetyczny”.

    <title> w <head>.

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

    Kryteria:

    R.3.5 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl7.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 styl7.css prawidłowo połączony z kodem strony.

    Nazwa z cyfrą: styl7.css.

    Typowe błędy

    styl.css bez siódemki odcina wszystkie style (R.3.5).

    index.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Salon kosmetyczny</title>
        <link rel="stylesheet" href="styl7.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  14. Krok 14: Bloki strony

    Kryteria:

    R.2.4 Układ strony zdefiniowano dzieląc ją na bloki: dwa lewe, dwa prawe i stopkę. Zastosowano znaczniki sekcji

    ok. 3 min
    Polecenie z arkusza

    Podział strony na bloki: dwa bloki po lewej stronie i dwa po prawej, poniżej stopka. Podział zrealizowany za pomocą znaczników sekcji tak, aby po uruchomieniu w przeglądarce układ bloków był zgodny z Obrazem 2.

    Cztery bloki w kontenerze <div class="layout">, każdy w znaczniku, który mówi, czym jest (R.2.4):

    • pierwszy prawy - <header class="title">, nagłówek strony z nazwą salonu,
    • pierwszy lewy - <nav class="offer">, oferta z odnośnikami między stronami,
    • drugi prawy - <main class="content">, treść główna (ta, która różni obie strony),
    • drugi lewy - <aside class="photo">, zdjęcie personelu jako dodatek do treści.

    Kolejność w kodzie to kolejność czytania: nagłówek, nawigacja, treść, dodatek. Tak przeczyta stronę czytnik ekranu. Miejsce bloków na ekranie wyznaczy siatka CSS, niezależnie od kolejności w kodzie. Stopka stoi pod kontenerem.

    index.html HTML zmienione: 12 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Salon kosmetyczny</title>
        <link rel="stylesheet" href="styl7.css">
    </head>
    <body>
        <div class="layout">
            <header class="title">
            </header>
            <nav class="offer">
            </nav>
            <main class="content">
            </main>
            <aside class="photo">
            </aside>
        </div>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  15. Krok 15: Pierwszy blok lewy: nagłówek

    Kryteria:

    R.2.5 W bloku pierwszym lewym zapisano nagłówek h2: "Nasza oferta", w pierwszym prawym h1: "Usługi kosmetyczne" oraz w drugim prawym h3: "Telefon: 111 222 333" lub "Kalkulator ceny wizyty" oraz przynajmniej jeden paragraf

    ok. 1 min
    Polecenie z arkusza

    Zawartość pierwszego bloku po lewej stronie: Nagłówek drugiego stopnia o treści „Nasza oferta”.

    <h2> (R.2.5).

    index.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Salon kosmetyczny</title>
        <link rel="stylesheet" href="styl7.css">
    </head>
    <body>
        <div class="layout">
            <header class="title">
            </header>
            <nav class="offer">
                <h2>Nasza oferta</h2>
            </nav>
            <main class="content">
            </main>
            <aside class="photo">
            </aside>
        </div>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  16. Krok 16: Lista numerowana

    Kryteria:

    R.2.6 Umieszczono jedną trójelementową listę numerowaną, której pierwszy element zagnieżdża dwuelementową listę punktowaną, zastosowano znaczniki <ol>, <ul>, <li>. Podlista <ul> zawarta wewnątrz pierwszego <li> listy głównej

    ok. 1 min
    Polecenie z arkusza

    Lista numerowana (uporządkowana) z elementami: Oczyszczanie twarzy, Masaż, Makijaż.

    Lista uporządkowana <ol>, numery wstawia przeglądarka.

    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>Salon kosmetyczny</title>
        <link rel="stylesheet" href="styl7.css">
    </head>
    <body>
        <div class="layout">
            <header class="title">
            </header>
            <nav class="offer">
                <h2>Nasza oferta</h2>
                <ol>
                    <li>Oczyszczanie twarzy</li>
                    <li>Masaż</li>
                    <li>Makijaż</li>
                </ol>
            </nav>
            <main class="content">
            </main>
            <aside class="photo">
            </aside>
        </div>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  17. Krok 17: Lista zagnieżdżona

    Kryteria:

    R.2.6 Umieszczono jedną trójelementową listę numerowaną, której pierwszy element zagnieżdża dwuelementową listę punktowaną, zastosowano znaczniki <ol>, <ul>, <li>. Podlista <ul> zawarta wewnątrz pierwszego <li> listy głównej

    ok. 2 min
    Polecenie z arkusza

    Element „Oczyszczanie twarzy” zawiera zagnieżdżoną listę punktowaną (nieuporządkowaną) z elementami: Peeling, Maska.

    Podlista <ul> stoi wewnątrz pierwszego <li>, między jego tekstem a </li> - klucz sprawdza to wprost (R.2.6).

    Typowe błędy

    <ul> wstawione między dwa <li> (po zamknięciu pierwszego) to niepoprawny HTML i nie spełnia R.2.6.

    index.html HTML zmienione: 6 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Salon kosmetyczny</title>
        <link rel="stylesheet" href="styl7.css">
    </head>
    <body>
        <div class="layout">
            <header class="title">
            </header>
            <nav class="offer">
                <h2>Nasza oferta</h2>
                <ol>
                    <li>Oczyszczanie twarzy
                        <ul>
                            <li>Peeling</li>
                            <li>Maska</li>
                        </ul>
                    </li>
                    <li>Masaż</li>
                    <li>Makijaż</li>
                </ol>
            </nav>
            <main class="content">
            </main>
            <aside class="photo">
            </aside>
        </div>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  18. Krok 18: Odnośnik do twarz.html

    Kryteria:

    R.3.2 Po wybraniu odnośnika "Oczyszczanie twarzy" otwiera się strona twarz.html

    ok. 1 min
    Polecenie z arkusza

    Tekst elementu „Oczyszczanie twarzy” jest odnośnikiem do strony twarz.html.

    <a> obejmuje sam tekst, podlista zostaje poza odnośnikiem (R.3.2).

    index.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Salon kosmetyczny</title>
        <link rel="stylesheet" href="styl7.css">
    </head>
    <body>
        <div class="layout">
            <header class="title">
            </header>
            <nav class="offer">
                <h2>Nasza oferta</h2>
                <ol>
                    <li><a href="twarz.html">Oczyszczanie twarzy</a>
                        <ul>
                            <li>Peeling</li>
                            <li>Maska</li>
                        </ul>
                    </li>
                    <li>Masaż</li>
                    <li>Makijaż</li>
                </ol>
            </nav>
            <main class="content">
            </main>
            <aside class="photo">
            </aside>
        </div>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  19. Krok 19: Odnośnik do strony głównej

    Kryteria:

    R.3.3 Po wybraniu odnośnika "Strona główna" otwiera się strona index.html

    ok. 1 min
    Polecenie z arkusza

    Odnośnik o treści „Strona główna” prowadzący do strony index.html.

    Odnośnik dostaje klasę home-link - arkusz każe nadać mu osobny styl (R.3.3).

    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>Salon kosmetyczny</title>
        <link rel="stylesheet" href="styl7.css">
    </head>
    <body>
        <div class="layout">
            <header class="title">
            </header>
            <nav class="offer">
                <h2>Nasza oferta</h2>
                <ol>
                    <li><a href="twarz.html">Oczyszczanie twarzy</a>
                        <ul>
                            <li>Peeling</li>
                            <li>Maska</li>
                        </ul>
                    </li>
                    <li>Masaż</li>
                    <li>Makijaż</li>
                </ol>
                <a href="index.html" class="home-link">Strona główna</a>
            </nav>
            <main class="content">
            </main>
            <aside class="photo">
            </aside>
        </div>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  20. Krok 20: Pierwszy blok prawy: nagłówek

    Kryteria:

    R.2.5 W bloku pierwszym lewym zapisano nagłówek h2: "Nasza oferta", w pierwszym prawym h1: "Usługi kosmetyczne" oraz w drugim prawym h3: "Telefon: 111 222 333" lub "Kalkulator ceny wizyty" oraz przynajmniej jeden paragraf

    ok. 1 min
    Polecenie z arkusza

    Zawartość pierwszego bloku po prawej stronie: nagłówek pierwszego stopnia o treści „Usługi kosmetyczne”.

    <h1> w nagłówku strony (R.2.5).

    index.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Salon kosmetyczny</title>
        <link rel="stylesheet" href="styl7.css">
    </head>
    <body>
        <div class="layout">
            <header class="title">
                <h1>Usługi kosmetyczne</h1>
            </header>
            <nav class="offer">
                <h2>Nasza oferta</h2>
                <ol>
                    <li><a href="twarz.html">Oczyszczanie twarzy</a>
                        <ul>
                            <li>Peeling</li>
                            <li>Maska</li>
                        </ul>
                    </li>
                    <li>Masaż</li>
                    <li>Makijaż</li>
                </ol>
                <a href="index.html" class="home-link">Strona główna</a>
            </nav>
            <main class="content">
            </main>
            <aside class="photo">
            </aside>
        </div>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  21. Krok 21: Drugi blok lewy: zdjęcie personelu

    Kryteria:

    R.2.7 Umieszczono co najmniej jedną grafikę: obraz1.jpg z tekstem alternatywnym "Personel" w bloku drugim lewym lub obraz2.jpg z tekstem alternatywnym "Zrelaksuj się" w bloku drugim prawym

    ok. 1 min
    Polecenie z arkusza

    Zawartość drugiego bloku po lewej stronie: obraz o nazwie obraz1.jpg z tekstem alternatywnym „Personel”.

    Obraz z alt (R.2.7) i wymiarami pliku w width/height - przeglądarka rezerwuje miejsce, zanim zdjęcie się wczyta.

    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>Salon kosmetyczny</title>
        <link rel="stylesheet" href="styl7.css">
    </head>
    <body>
        <div class="layout">
            <header class="title">
                <h1>Usługi kosmetyczne</h1>
            </header>
            <nav class="offer">
                <h2>Nasza oferta</h2>
                <ol>
                    <li><a href="twarz.html">Oczyszczanie twarzy</a>
                        <ul>
                            <li>Peeling</li>
                            <li>Maska</li>
                        </ul>
                    </li>
                    <li>Masaż</li>
                    <li>Makijaż</li>
                </ol>
                <a href="index.html" class="home-link">Strona główna</a>
            </nav>
            <main class="content">
            </main>
            <aside class="photo">
                <img src="obraz1.jpg" alt="Personel" width="240" height="300">
            </aside>
        </div>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  22. Krok 22: Stopka

    Kryteria:

    R.2.5 W bloku pierwszym lewym zapisano nagłówek h2: "Nasza oferta", w pierwszym prawym h1: "Usługi kosmetyczne" oraz w drugim prawym h3: "Telefon: 111 222 333" lub "Kalkulator ceny wizyty" oraz przynajmniej jeden paragraf

    ok. 1 min
    Polecenie z arkusza

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

    Akapit w <footer> (R.2.5). Na egzaminie po „Autor:” wpisujesz swój numer zdającego (PESEL); tu stoi autor 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>Salon kosmetyczny</title>
        <link rel="stylesheet" href="styl7.css">
    </head>
    <body>
        <div class="layout">
            <header class="title">
                <h1>Usługi kosmetyczne</h1>
            </header>
            <nav class="offer">
                <h2>Nasza oferta</h2>
                <ol>
                    <li><a href="twarz.html">Oczyszczanie twarzy</a>
                        <ul>
                            <li>Peeling</li>
                            <li>Maska</li>
                        </ul>
                    </li>
                    <li>Masaż</li>
                    <li>Makijaż</li>
                </ol>
                <a href="index.html" class="home-link">Strona główna</a>
            </nav>
            <main class="content">
            </main>
            <aside class="photo">
                <img src="obraz1.jpg" alt="Personel" width="240" height="300">
            </aside>
        </div>
        <footer>
            <p>Autor: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  23. Krok 23: Drugi blok prawy strony głównej

    Kryteria: ,

    R.2.5 W bloku pierwszym lewym zapisano nagłówek h2: "Nasza oferta", w pierwszym prawym h1: "Usługi kosmetyczne" oraz w drugim prawym h3: "Telefon: 111 222 333" lub "Kalkulator ceny wizyty" oraz przynajmniej jeden paragraf

    R.2.7 Umieszczono co najmniej jedną grafikę: obraz1.jpg z tekstem alternatywnym "Personel" w bloku drugim lewym lub obraz2.jpg z tekstem alternatywnym "Zrelaksuj się" w bloku drugim prawym

    ok. 2 min
    Polecenie z arkusza

    Zawartość drugiego bloku po prawej stronie dla strony index.html: Akapit (paragraf) o treści: „Witaj! Miło nam, że odwiedziłeś nasz salon. Zapoznaj się z ofertą lub skontaktuj się z nami.” Obraz o nazwie obraz2.jpg z tekstem alternatywnym „Zrelaksuj się”. Nagłówek trzeciego stopnia o treści „Telefon: 111 222 333”.

    Akapit, obraz i <h3>, w tej kolejności jak na obrazie 2 (R.2.5, R.2.7).

    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>Salon kosmetyczny</title>
        <link rel="stylesheet" href="styl7.css">
    </head>
    <body>
        <div class="layout">
            <header class="title">
                <h1>Usługi kosmetyczne</h1>
            </header>
            <nav class="offer">
                <h2>Nasza oferta</h2>
                <ol>
                    <li><a href="twarz.html">Oczyszczanie twarzy</a>
                        <ul>
                            <li>Peeling</li>
                            <li>Maska</li>
                        </ul>
                    </li>
                    <li>Masaż</li>
                    <li>Makijaż</li>
                </ol>
                <a href="index.html" class="home-link">Strona główna</a>
            </nav>
            <main class="content">
                <p>Witaj! Miło nam, że odwiedziłeś nasz salon. Zapoznaj się z ofertą lub skontaktuj się z nami.</p>
                <img src="obraz2.jpg" alt="Zrelaksuj się" width="700" height="296">
                <h3>Telefon: 111 222 333</h3>
            </main>
            <aside class="photo">
                <img src="obraz1.jpg" alt="Personel" width="240" height="300">
            </aside>
        </div>
        <footer>
            <p>Autor: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.html)
  24. Krok 24: Strona twarz.html z kopii

    Kryteria:

    R.2.5 W bloku pierwszym lewym zapisano nagłówek h2: "Nasza oferta", w pierwszym prawym h1: "Usługi kosmetyczne" oraz w drugim prawym h3: "Telefon: 111 222 333" lub "Kalkulator ceny wizyty" oraz przynajmniej jeden paragraf

    ok. 2 min
    Polecenie z arkusza

    Wygląd drugiego bloku po prawej stronie dla twarz.html przedstawiono na Obrazie 3, jego zawartość to: Nagłówek trzeciego stopnia o treści „Kalkulator ceny wizyty”.

    Zapisz jako twarz.html z kopii strony głównej i wymień tylko zawartość <main> - reszta zostaje identyczna, jak każe arkusz (R.2.5).

    twarz.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>Salon kosmetyczny</title>
        <link rel="stylesheet" href="styl7.css">
    </head>
    <body>
        <div class="layout">
            <header class="title">
                <h1>Usługi kosmetyczne</h1>
            </header>
            <nav class="offer">
                <h2>Nasza oferta</h2>
                <ol>
                    <li><a href="twarz.html">Oczyszczanie twarzy</a>
                        <ul>
                            <li>Peeling</li>
                            <li>Maska</li>
                        </ul>
                    </li>
                    <li>Masaż</li>
                    <li>Makijaż</li>
                </ol>
                <a href="index.html" class="home-link">Strona główna</a>
            </nav>
            <main class="content">
                <h3>Kalkulator ceny wizyty</h3>
            </main>
            <aside class="photo">
                <img src="obraz1.jpg" alt="Personel" width="240" height="300">
            </aside>
        </div>
        <footer>
            <p>Autor: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (twarz.html)
  25. Krok 25: Cztery pola wyboru

    Kryteria:

    R.2.8 Na stronie twarz.html umieszczono cztery kontrolki checkbox z opisami: Peeling, Maska, Masaż twarzy, Makijaż oraz jeden przycisk "Oblicz cenę"

    ok. 3 min
    Polecenie z arkusza

    Cztery pola checkbox jeden pod drugim z podpisami: Peeling, Maska, Masaż twarzy, Makijaż.

    Pola stoją w formularzu <form class="calculator"> - to zbiór kontrolek, które skrypt odczyta razem.

    • każde pole siedzi wewnątrz swojej etykiety <label> - kliknięcie podpisu zaznacza pole, a etykieta nie potrzebuje atrybutów for/id,
    • wszystkie cztery mają wspólną nazwę name="treatment", a value mówi, który to zabieg - skrypt zbierze je po tej nazwie,
    • „jeden pod drugim” zrobi CSS (etykiety jako bloki), bez znaczników <br> (R.2.8).
    twarz.html HTML zmienione: 6 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Salon kosmetyczny</title>
        <link rel="stylesheet" href="styl7.css">
    </head>
    <body>
        <div class="layout">
            <header class="title">
                <h1>Usługi kosmetyczne</h1>
            </header>
            <nav class="offer">
                <h2>Nasza oferta</h2>
                <ol>
                    <li><a href="twarz.html">Oczyszczanie twarzy</a>
                        <ul>
                            <li>Peeling</li>
                            <li>Maska</li>
                        </ul>
                    </li>
                    <li>Masaż</li>
                    <li>Makijaż</li>
                </ol>
                <a href="index.html" class="home-link">Strona główna</a>
            </nav>
            <main class="content">
                <h3>Kalkulator ceny wizyty</h3>
                <form class="calculator">
                    <label><input type="checkbox" name="treatment" value="peeling"> Peeling</label>
                    <label><input type="checkbox" name="treatment" value="mask"> Maska</label>
                    <label><input type="checkbox" name="treatment" value="massage"> Masaż twarzy</label>
                    <label><input type="checkbox" name="treatment" value="makeup"> Makijaż</label>
                </form>
            </main>
            <aside class="photo">
                <img src="obraz1.jpg" alt="Personel" width="240" height="300">
            </aside>
        </div>
        <footer>
            <p>Autor: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (twarz.html)
  26. Krok 26: Przycisk i akapit na wynik

    Kryteria:

    R.2.8 Na stronie twarz.html umieszczono cztery kontrolki checkbox z opisami: Peeling, Maska, Masaż twarzy, Makijaż oraz jeden przycisk "Oblicz cenę"

    ok. 2 min
    Polecenie z arkusza

    Poniżej przycisk o treści „Oblicz cenę”, którego wybranie powoduje uruchomienie skryptu.

    Przycisk type="submit" zamyka formularz - skrypt przejmie zdarzenie wysłania formularza. Pod formularzem pusty akapit na wynik; aria-live="polite" każe czytnikowi ekranu odczytać wynik, gdy się pojawi (R.2.8).

    Na razie skryptu nie ma - kliknięcie przeładowuje stronę.

    twarz.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>Salon kosmetyczny</title>
        <link rel="stylesheet" href="styl7.css">
    </head>
    <body>
        <div class="layout">
            <header class="title">
                <h1>Usługi kosmetyczne</h1>
            </header>
            <nav class="offer">
                <h2>Nasza oferta</h2>
                <ol>
                    <li><a href="twarz.html">Oczyszczanie twarzy</a>
                        <ul>
                            <li>Peeling</li>
                            <li>Maska</li>
                        </ul>
                    </li>
                    <li>Masaż</li>
                    <li>Makijaż</li>
                </ol>
                <a href="index.html" class="home-link">Strona główna</a>
            </nav>
            <main class="content">
                <h3>Kalkulator ceny wizyty</h3>
                <form class="calculator">
                    <label><input type="checkbox" name="treatment" value="peeling"> Peeling</label>
                    <label><input type="checkbox" name="treatment" value="mask"> Maska</label>
                    <label><input type="checkbox" name="treatment" value="massage"> Masaż twarzy</label>
                    <label><input type="checkbox" name="treatment" value="makeup"> Makijaż</label>
                    <button type="submit">Oblicz cenę</button>
                </form>
                <p class="result" aria-live="polite"></p>
            </main>
            <aside class="photo">
                <img src="obraz1.jpg" alt="Personel" width="240" height="300">
            </aside>
        </div>
        <footer>
            <p>Autor: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (twarz.html)
  27. Etap 3: Styl CSS

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

    Krok 27: Plik styl7.css: kolory z arkusza w zmiennych

    ok. 2 min
    Polecenie z arkusza

    Styl CSS zdefiniowany w całości w zewnętrznym pliku o nazwie styl7.css.

    Trzy kolory arkusza jako zmienne CSS w :root: jasny fiolet bloków lewych, ciemny fiolet nagłówka i stopki, Indigo tekstu i ramki. Reguły odwołują się do nich przez var(--nazwa). Sama definicja nic nie zmienia na stronie.

    styl7.css CSS nowy plik
    :root {
        --color-light: #E1BEE7;
        --color-dark: #9C64A6;
        --color-text: Indigo;
    }
    Podgląd strony po tym kroku (index.html)
  28. Krok 28: Czcionka dla wszystkich elementów

    Kryteria:

    R.4.1 Ustawiono domyślne formatowanie wszystkich selektorów (*): krój czcionki Cambria

    ok. 1 min
    Polecenie z arkusza

    Ustawione domyślne wartości dla wszystkich selektorów stylu CSS: krój czcionki Cambria.

    Selektor uniwersalny * (R.4.1). Cambria to krój szeryfowy z pakietu Microsoft - na innych systemach zastąpi go Georgia, a na końcu rodzina ogólna serif.

    styl7.css CSS zmienione: 4 linie
    :root {
        --color-light: #E1BEE7;
        --color-dark: #9C64A6;
        --color-text: Indigo;
    }
    
    * {
        font-family: Cambria, Georgia, serif;
    }
    Podgląd strony po tym kroku (index.html)
  29. Krok 29: Bloki lewe

    Kryteria: ,

    R.4.2 Ustawiono kolor tła #E1BEE7 dla obu bloków lewych oraz #9C64A6 dla pierwszego bloku prawego i stopki

    R.4.5 Ustawiono wysokość dla bloków: pierwszy lewy: 400px, drugi lewy: 330px, pierwszy prawy: 150px, drugi prawy: 580px

    ok. 2 min
    Polecenie z arkusza

    Wspólne dla obu bloków lewych: kolor tła #E1BEE7, szerokość 25%. Dodatkowo wysokość pierwszego lewego bloku wynosi 400 px, drugiego 330 px.

    Wspólny kolor w jednej regule, wysokości osobno (R.4.2, R.4.5). Szerokość 25% dostaną bloki z siatki - w kroku układu.

    styl7.css CSS zmienione: 13 linii
    :root {
        --color-light: #E1BEE7;
        --color-dark: #9C64A6;
        --color-text: Indigo;
    }
    
    * {
        font-family: Cambria, Georgia, serif;
    }
    
    .offer,
    .photo {
        background-color: var(--color-light);
    }
    
    .offer {
        height: 400px;
    }
    
    .photo {
        height: 330px;
    }
    Podgląd strony po tym kroku (index.html)
  30. Krok 30: Bloki prawe

    Kryteria: , , , ,

    R.4.2 Ustawiono kolor tła #E1BEE7 dla obu bloków lewych oraz #9C64A6 dla pierwszego bloku prawego i stopki

    R.4.3 Ustawiono biały kolor czcionki dla pierwszego bloku prawego i stopki oraz Indigo dla drugiego bloku prawego

    R.4.5 Ustawiono wysokość dla bloków: pierwszy lewy: 400px, drugi lewy: 330px, pierwszy prawy: 150px, drugi prawy: 580px

    R.4.7 Ustawiono wyrównanie do środka dla obu bloków prawych i selektora h2

    R.4.8 Ustawiono dla obu bloków prawych rozmiar czcionki 170% oraz dla pierwszego prawego odstępy między literami 5px (letter-spacing)

    ok. 3 min
    Polecenie z arkusza

    Wspólne dla obu bloków prawych: szerokość 75%, rozmiar czcionki 170%, wyrównanie tekstu do środka. Dodatkowo dla pierwszego bloku prawego: kolor tła #9C64A6, biały kolor czcionki, wysokość 150 px, odstępy między literami 5 px. Dodatkowo dla drugiego bloku prawego: kolor czcionki Indigo, wysokość 580 px.

    Wspólne cechy obu prawych bloków w jednej regule, reszta osobno (R.4.2, R.4.3, R.4.5, R.4.7, R.4.8). Odstępy między literami to letter-spacing - stąd rozstrzelony napis „Usługi kosmetyczne”. Szerokość 75% da siatka.

    styl7.css CSS zmienione: 18 linii
    :root {
        --color-light: #E1BEE7;
        --color-dark: #9C64A6;
        --color-text: Indigo;
    }
    
    * {
        font-family: Cambria, Georgia, serif;
    }
    
    .offer,
    .photo {
        background-color: var(--color-light);
    }
    
    .offer {
        height: 400px;
    }
    
    .photo {
        height: 330px;
    }
    
    .title,
    .content {
        font-size: 170%;
        text-align: center;
    }
    
    .title {
        background-color: var(--color-dark);
        color: white;
        height: 150px;
        letter-spacing: 5px;
    }
    
    .content {
        color: var(--color-text);
        height: 580px;
    }
    Podgląd strony po tym kroku (index.html)
  31. Krok 31: Układ: siatka z trzema wierszami

    Kryteria: ,

    R.3.1 Układ bloków po uruchomieniu przynajmniej jednej strony w przeglądarce jest zgodny z obrazem 2 w arkuszu (prawidłowo zastosowano właściwości CSS decydujące o układzie strony, np. float i clear albo display flex albo grid albo position)

    R.4.4 Ustawiono szerokość 25% dla obu bloków lewych i 75% dla obu prawych (width lub grid- template-columns lub flex)

    ok. 4 min
    Polecenie z arkusza

    Podział strony na bloki: dwa bloki po lewej stronie i dwa po prawej, poniżej stopka. Podział zrealizowany za pomocą znaczników sekcji tak, aby po uruchomieniu w przeglądarce układ bloków był zgodny z Obrazem 2.

    Kolumny bloków mają różne podziały: po lewej 400 + 330 px, po prawej 150 + 580 px. Obie dają 730 px, więc da się je opisać jedną siatką o trzech wierszach, wyznaczonych przez wszystkie granice bloków: 150 px, potem 250 px (do 400) i 330 px (do 730).

    • grid-template-columns: 25% 75% - szerokości bloków z arkusza (klucz przyjmuje grid-template-columns, R.4.4),
    • grid-template-areas rysuje plan: oferta zajmuje dwa górne wiersze (150 + 250 = 400 px), zdjęcie - dolny (330 px); nagłówek - górny (150 px), treść - dwa dolne (250 + 330 = 580 px).

    Wysokości w blokach z poprzednich kroków zgadzają się z wierszami siatki. W wersji podstawowej ten sam układ daje flexbox w kolumnie z zawijaniem i kontener o sztywnej wysokości 730 px - tu nie trzeba liczyć wysokości kontenera, a plan strony widać w kodzie (R.3.1).

    Typowe błędy

    Szerokości bloków w siatce wpisuj tylko w grid-template-columns. Dodatkowe width: 25% w bloku liczyłoby się od kolumny siatki - blok miałby ćwierć kolumny.

    styl7.css CSS zmienione: 15 linii
    :root {
        --color-light: #E1BEE7;
        --color-dark: #9C64A6;
        --color-text: Indigo;
    }
    
    * {
        font-family: Cambria, Georgia, serif;
    }
    
    .offer,
    .photo {
        background-color: var(--color-light);
    }
    
    .offer {
        height: 400px;
    }
    
    .photo {
        height: 330px;
    }
    
    .title,
    .content {
        font-size: 170%;
        text-align: center;
    }
    
    .title {
        background-color: var(--color-dark);
        color: white;
        height: 150px;
        letter-spacing: 5px;
    }
    
    .content {
        color: var(--color-text);
        height: 580px;
    }
    
    .layout {
        display: grid;
        grid-template-columns: 25% 75%;
        grid-template-rows: 150px 250px 330px;
        grid-template-areas:
            "offer title"
            "offer content"
            "photo content";
    }
    
    .title   { grid-area: title; }
    .offer   { grid-area: offer; }
    .content { grid-area: content; }
    .photo   { grid-area: photo; }
    Podgląd strony po tym kroku (index.html)
  32. Krok 32: Stopka

    Kryteria: , ,

    R.4.2 Ustawiono kolor tła #E1BEE7 dla obu bloków lewych oraz #9C64A6 dla pierwszego bloku prawego i stopki

    R.4.3 Ustawiono biały kolor czcionki dla pierwszego bloku prawego i stopki oraz Indigo dla drugiego bloku prawego

    R.4.6 Ustawiono marginesy wewnętrzne (padding) 10px dla stopki, 4px dla selektora img i 25px dla odsyłacza do Strony głównej oraz marginesy zewnętrzne (margin) 15px dla selektora img

    ok. 1 min
    Polecenie z arkusza

    Dla stopki: kolor tła #9C64A6, biały kolor czcionki, marginesy wewnętrzne 10 px.

    Selektor footer (R.4.2, R.4.3, R.4.6). Akapit bez domyślnych marginesów - stopka ma tylko 10 px dopełnienia z arkusza.

    styl7.css CSS zmienione: 10 linii
    :root {
        --color-light: #E1BEE7;
        --color-dark: #9C64A6;
        --color-text: Indigo;
    }
    
    * {
        font-family: Cambria, Georgia, serif;
    }
    
    .offer,
    .photo {
        background-color: var(--color-light);
    }
    
    .offer {
        height: 400px;
    }
    
    .photo {
        height: 330px;
    }
    
    .title,
    .content {
        font-size: 170%;
        text-align: center;
    }
    
    .title {
        background-color: var(--color-dark);
        color: white;
        height: 150px;
        letter-spacing: 5px;
    }
    
    .content {
        color: var(--color-text);
        height: 580px;
    }
    
    .layout {
        display: grid;
        grid-template-columns: 25% 75%;
        grid-template-rows: 150px 250px 330px;
        grid-template-areas:
            "offer title"
            "offer content"
            "photo content";
    }
    
    .title   { grid-area: title; }
    .offer   { grid-area: offer; }
    .content { grid-area: content; }
    .photo   { grid-area: photo; }
    
    footer {
        background-color: var(--color-dark);
        color: white;
        padding: 10px;
    }
    
    footer p {
        margin: 0;
    }
    Podgląd strony po tym kroku (index.html)
  33. Krok 33: Nagłówek drugiego stopnia i lista punktowana

    Kryteria: ,

    R.4.7 Ustawiono wyrównanie do środka dla obu bloków prawych i selektora h2

    R.4.9 Ustawiono dla selektora ul: okrąg jako punktor (list-style lub list-style-type: circle;)

    ok. 1 min
    Polecenie z arkusza

    Dla selektora nagłówka drugiego stopnia: wyrównanie tekstu do środka. Dla selektora listy punktowanej (nieuporządkowanej): punktorem jest okrąg.

    Selektory znaczników h2 i ul - arkusz zastrzega, że styl ma być zdefiniowany wyłącznie nimi (R.4.7, R.4.9). Okrąg to circle.

    Typowe błędy

    Styl dla klasy (.offer ul) nie spełnia R.4.9 - klucz uznaje tylko selektor znacznika.

    styl7.css CSS zmienione: 8 linii
    :root {
        --color-light: #E1BEE7;
        --color-dark: #9C64A6;
        --color-text: Indigo;
    }
    
    * {
        font-family: Cambria, Georgia, serif;
    }
    
    .offer,
    .photo {
        background-color: var(--color-light);
    }
    
    .offer {
        height: 400px;
    }
    
    .photo {
        height: 330px;
    }
    
    .title,
    .content {
        font-size: 170%;
        text-align: center;
    }
    
    .title {
        background-color: var(--color-dark);
        color: white;
        height: 150px;
        letter-spacing: 5px;
    }
    
    .content {
        color: var(--color-text);
        height: 580px;
    }
    
    .layout {
        display: grid;
        grid-template-columns: 25% 75%;
        grid-template-rows: 150px 250px 330px;
        grid-template-areas:
            "offer title"
            "offer content"
            "photo content";
    }
    
    .title   { grid-area: title; }
    .offer   { grid-area: offer; }
    .content { grid-area: content; }
    .photo   { grid-area: photo; }
    
    footer {
        background-color: var(--color-dark);
        color: white;
        padding: 10px;
    }
    
    footer p {
        margin: 0;
    }
    
    h2 {
        text-align: center;
    }
    
    ul {
        list-style-type: circle;
    }
    Podgląd strony po tym kroku (index.html)
  34. Krok 34: Obrazy i ramka po wskazaniu

    Kryteria: ,

    R.4.6 Ustawiono marginesy wewnętrzne (padding) 10px dla stopki, 4px dla selektora img i 25px dla odsyłacza do Strony głównej oraz marginesy zewnętrzne (margin) 15px dla selektora img

    R.4.10 W momencie, gdy kursor znajduje się na obrazie, styl obrazu zmienia się na: marginesy wewnętrzne (padding) 3px oraz obramowanie 1px dashed Indigo

    ok. 2 min
    Polecenie z arkusza

    Dla selektora obrazu: marginesy wewnętrzne 4 px, marginesy zewnętrzne 15 px. W momencie, gdy kursor znajduje się na obrazie, styl obrazu zmienia się na: marginesy wewnętrzne 3 px, obramowanie linią kreskową o szerokości 1 px i kolorze Indigo (efekt widoczny na Obrazie 2).

    Selektor img (R.4.6) i img:hover z linią kreskową dashed (R.4.10). Arkusz sam dba o to, żeby nic nie podskakiwało: dopełnienie maleje o 1 px dokładnie wtedy, gdy pojawia się ramka 1 px. Najedź w podglądzie na obraz.

    styl7.css CSS zmienione: 10 linii
    :root {
        --color-light: #E1BEE7;
        --color-dark: #9C64A6;
        --color-text: Indigo;
    }
    
    * {
        font-family: Cambria, Georgia, serif;
    }
    
    .offer,
    .photo {
        background-color: var(--color-light);
    }
    
    .offer {
        height: 400px;
    }
    
    .photo {
        height: 330px;
    }
    
    .title,
    .content {
        font-size: 170%;
        text-align: center;
    }
    
    .title {
        background-color: var(--color-dark);
        color: white;
        height: 150px;
        letter-spacing: 5px;
    }
    
    .content {
        color: var(--color-text);
        height: 580px;
    }
    
    .layout {
        display: grid;
        grid-template-columns: 25% 75%;
        grid-template-rows: 150px 250px 330px;
        grid-template-areas:
            "offer title"
            "offer content"
            "photo content";
    }
    
    .title   { grid-area: title; }
    .offer   { grid-area: offer; }
    .content { grid-area: content; }
    .photo   { grid-area: photo; }
    
    footer {
        background-color: var(--color-dark);
        color: white;
        padding: 10px;
    }
    
    footer p {
        margin: 0;
    }
    
    h2 {
        text-align: center;
    }
    
    ul {
        list-style-type: circle;
    }
    
    img {
        padding: 4px;
        margin: 15px;
    }
    
    img:hover {
        padding: 3px;
        border: 1px dashed var(--color-text);
    }
    Podgląd strony po tym kroku (index.html)
  35. Krok 35: Odnośnik do strony głównej

    Kryteria:

    R.4.6 Ustawiono marginesy wewnętrzne (padding) 10px dla stopki, 4px dla selektora img i 25px dla odsyłacza do Strony głównej oraz marginesy zewnętrzne (margin) 15px dla selektora img

    ok. 2 min
    Polecenie z arkusza

    Dla odsyłacza do Strony głównej: margines wewnętrzny 25 px.

    Klasa .home-link - tylko ten jeden odnośnik (R.4.6).

    display: inline-block sprawia, że dopełnienie z góry i z dołu naprawdę rozsuwa sąsiednie elementy. Zwykły odnośnik jest elementem w linii tekstu: dopełnienie pionowe powiększa wtedy tylko jego tło i obszar kliknięcia, ale nie odsuwa listy nad nim.

    styl7.css CSS zmienione: 5 linii
    :root {
        --color-light: #E1BEE7;
        --color-dark: #9C64A6;
        --color-text: Indigo;
    }
    
    * {
        font-family: Cambria, Georgia, serif;
    }
    
    .offer,
    .photo {
        background-color: var(--color-light);
    }
    
    .offer {
        height: 400px;
    }
    
    .photo {
        height: 330px;
    }
    
    .title,
    .content {
        font-size: 170%;
        text-align: center;
    }
    
    .title {
        background-color: var(--color-dark);
        color: white;
        height: 150px;
        letter-spacing: 5px;
    }
    
    .content {
        color: var(--color-text);
        height: 580px;
    }
    
    .layout {
        display: grid;
        grid-template-columns: 25% 75%;
        grid-template-rows: 150px 250px 330px;
        grid-template-areas:
            "offer title"
            "offer content"
            "photo content";
    }
    
    .title   { grid-area: title; }
    .offer   { grid-area: offer; }
    .content { grid-area: content; }
    .photo   { grid-area: photo; }
    
    footer {
        background-color: var(--color-dark);
        color: white;
        padding: 10px;
    }
    
    footer p {
        margin: 0;
    }
    
    h2 {
        text-align: center;
    }
    
    ul {
        list-style-type: circle;
    }
    
    img {
        padding: 4px;
        margin: 15px;
    }
    
    img:hover {
        padding: 3px;
        border: 1px dashed var(--color-text);
    }
    
    .home-link {
        display: inline-block;
        padding: 25px;
    }
    Podgląd strony po tym kroku (index.html)
  36. Krok 36: Pola kalkulatora jedno pod drugim

    ok. 2 min
    Polecenie z arkusza

    Cztery pola checkbox jeden pod drugim z podpisami: Peeling, Maska, Masaż twarzy, Makijaż.

    Etykiety z polami jako bloki (display: block) - każda zajmuje własny wiersz, więc pola stoją jedno pod drugim, jak na obrazie 3. Wyrównanie do środka bloku prawego zostaje.

    accent-color barwi zaznaczone pola kolorem Indigo, pasującym do bloku. Arkusz tego nie wymaga.

    styl7.css CSS zmienione: 8 linii
    :root {
        --color-light: #E1BEE7;
        --color-dark: #9C64A6;
        --color-text: Indigo;
    }
    
    * {
        font-family: Cambria, Georgia, serif;
    }
    
    .offer,
    .photo {
        background-color: var(--color-light);
    }
    
    .offer {
        height: 400px;
    }
    
    .photo {
        height: 330px;
    }
    
    .title,
    .content {
        font-size: 170%;
        text-align: center;
    }
    
    .title {
        background-color: var(--color-dark);
        color: white;
        height: 150px;
        letter-spacing: 5px;
    }
    
    .content {
        color: var(--color-text);
        height: 580px;
    }
    
    .layout {
        display: grid;
        grid-template-columns: 25% 75%;
        grid-template-rows: 150px 250px 330px;
        grid-template-areas:
            "offer title"
            "offer content"
            "photo content";
    }
    
    .title   { grid-area: title; }
    .offer   { grid-area: offer; }
    .content { grid-area: content; }
    .photo   { grid-area: photo; }
    
    footer {
        background-color: var(--color-dark);
        color: white;
        padding: 10px;
    }
    
    footer p {
        margin: 0;
    }
    
    h2 {
        text-align: center;
    }
    
    ul {
        list-style-type: circle;
    }
    
    img {
        padding: 4px;
        margin: 15px;
    }
    
    img:hover {
        padding: 3px;
        border: 1px dashed var(--color-text);
    }
    
    .home-link {
        display: inline-block;
        padding: 25px;
    }
    
    .calculator label {
        display: block;
    }
    
    .calculator input {
        accent-color: var(--color-text);
    }
    Podgląd strony po tym kroku (twarz.html)
  37. Etap 4: Skrypt JavaScript

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

    Krok 37: Plik kalkulator.js: cennik i obsługa przycisku

    Kryteria: , ,

    R.3.4 Wybranie przycisku powoduje uruchomienie funkcji skryptu (obsługa zdarzenia zdefiniowana np. inline w znaczniku jako atrybut onClick lub w skrypcie JS np.: element.addEventListener("click", funkcja); lub element.onClick = …)

    R.5.1 Skrypt napisano w języku JavaScript i zawiera on co najmniej jedną instrukcję tego języka zapisaną zgodnie ze składnią

    R.5.2 Skrypt wykorzystuje przynajmniej jedną metodę DOM

    ok. 3 min
    Polecenie z arkusza

    Napisany w języku wykonywanym po stronie przeglądarki. Uruchamia się po wciśnięciu przycisku na stronie twarz.html.

    Skrypt w osobnym pliku kalkulator.js, dołączony w <head> strony twarz.html z defer - uruchomi się po wczytaniu całego HTML-u.

    • PRICES - cennik z tabeli arkusza jako obiekt: klucz to wartość pola (value), wartość - cena w zł. Nazwa wielkimi literami to zwyczajowy znak stałej, której nikt nie zmienia w trakcie działania,
    • document.querySelector znajduje formularz i akapit wyniku (metody DOM, R.5.2),
    • addEventListener('submit', calculatePrice) - funkcja uruchamia się po kliknięciu „Oblicz cenę” (R.3.4, R.5.1), a event.preventDefault() zatrzymuje przeładowanie strony.
    kalkulator.js JavaScript nowy plik
    const PRICES = {
        peeling: 45,
        mask: 30,
        massage: 20,
        makeup: 50,
    };
    
    const form = document.querySelector('.calculator');
    const result = document.querySelector('.result');
    
    function calculatePrice(event) {
        event.preventDefault();
    }
    
    form.addEventListener('submit', calculatePrice);
    twarz.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>Salon kosmetyczny</title>
        <link rel="stylesheet" href="styl7.css">
        <script src="kalkulator.js" defer></script>
    </head>
    <body>
        <div class="layout">
            <header class="title">
                <h1>Usługi kosmetyczne</h1>
            </header>
            <nav class="offer">
                <h2>Nasza oferta</h2>
                <ol>
                    <li><a href="twarz.html">Oczyszczanie twarzy</a>
                        <ul>
                            <li>Peeling</li>
                            <li>Maska</li>
                        </ul>
                    </li>
                    <li>Masaż</li>
                    <li>Makijaż</li>
                </ol>
                <a href="index.html" class="home-link">Strona główna</a>
            </nav>
            <main class="content">
                <h3>Kalkulator ceny wizyty</h3>
                <form class="calculator">
                    <label><input type="checkbox" name="treatment" value="peeling"> Peeling</label>
                    <label><input type="checkbox" name="treatment" value="mask"> Maska</label>
                    <label><input type="checkbox" name="treatment" value="massage"> Masaż twarzy</label>
                    <label><input type="checkbox" name="treatment" value="makeup"> Makijaż</label>
                    <button type="submit">Oblicz cenę</button>
                </form>
                <p class="result" aria-live="polite"></p>
            </main>
            <aside class="photo">
                <img src="obraz1.jpg" alt="Personel" width="240" height="300">
            </aside>
        </div>
        <footer>
            <p>Autor: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (twarz.html)
  38. Krok 38: Suma cen zaznaczonych zabiegów

    Kryteria: ,

    R.5.3 Skrypt stosuje własność checked dla przynajmniej jednego pola checkbox

    R.5.4 Skrypt liczy sumę jedynie wszystkich zaznaczonych pól checkbox zgodnie z cenami podanymi w tabeli w arkuszu

    ok. 4 min
    Polecenie z arkusza

    Oblicza łączną cenę zabiegów wybranych za pomocą pól checkbox zgodnie z cennikiem w tabeli.

    • form.elements.treatment zwraca wszystkie pola o nazwie treatment naraz, a Array.from zamienia je w zwykłą tablicę,
    • filter((checkbox) => checkbox.checked) zostawia tylko pola zaznaczone - to właściwość checked z tabeli arkusza (R.5.3),
    • reduce((sum, checkbox) => sum + PRICES[checkbox.value], 0) sumuje: zaczyna od 0 i do każdego kolejnego wyniku dodaje cenę zabiegu z cennika (R.5.4).

    W wersji podstawowej są cztery osobne if. Tu piąty zabieg w ofercie to jedno pole w HTML i jedna linia w PRICES - funkcja się nie zmienia.

    Typowe błędy

    Sprawdzanie pól łańcuchem if / else if liczy tylko pierwszy zaznaczony zabieg - zaznaczyć można dowolną liczbę naraz.

    kalkulator.js JavaScript zmienione: 4 linie
    const PRICES = {
        peeling: 45,
        mask: 30,
        massage: 20,
        makeup: 50,
    };
    
    const form = document.querySelector('.calculator');
    const result = document.querySelector('.result');
    
    function calculatePrice(event) {
        event.preventDefault();
        const checkboxes = Array.from(form.elements.treatment);
        const total = checkboxes
            .filter((checkbox) => checkbox.checked)
            .reduce((sum, checkbox) => sum + PRICES[checkbox.value], 0);
    }
    
    form.addEventListener('submit', calculatePrice);
    Podgląd strony po tym kroku (twarz.html)
  39. Krok 39: Wynik pod przyciskiem

    Kryteria: ,

    R.5.5 Skrypt wyświetla obliczony wynik w akapicie pod przyciskiem według wzoru: "Cena zabiegów: <suma>”, gdzie <suma> oznacza sumę wyliczoną przez skrypt

    R.5.6 Zastosowano znaczące nazewnictwo dla wszystkich zmiennych i funkcji w języku polskim lub angielskim. Nazwy odzwierciedlają cel zastosowania

    ok. 2 min
    Polecenie z arkusza

    Wyświetla wynik działania w akapicie pod przyciskiem według wzoru: „Cena zabiegów: <suma>”, gdzie <suma> oznacza całkowitą cenę wybranych zabiegów.

    Szablon tekstowy wstawia sumę w zdanie, a textContent wpisuje je do akapitu jako zwykły tekst (R.5.5).

    Zaznacz w podglądzie Maskę, Masaż twarzy i Makijaż i kliknij „Oblicz cenę”: „Cena zabiegów: 100”, jak na obrazie 3. Nazwy mówią, co przechowują: PRICES, checkboxes, total, calculatePrice (R.5.6).

    kalkulator.js JavaScript zmienione: 1 linia
    const PRICES = {
        peeling: 45,
        mask: 30,
        massage: 20,
        makeup: 50,
    };
    
    const form = document.querySelector('.calculator');
    const result = document.querySelector('.result');
    
    function calculatePrice(event) {
        event.preventDefault();
        const checkboxes = Array.from(form.elements.treatment);
        const total = checkboxes
            .filter((checkbox) => checkbox.checked)
            .reduce((sum, checkbox) => sum + PRICES[checkbox.value], 0);
        result.textContent = `Cena zabiegów: ${total}`;
    }
    
    form.addEventListener('submit', calculatePrice);
    Podgląd strony po tym kroku (twarz.html)
  40. Etap 5: Porównanie z wersją podstawową

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

    Krok 40: Co jest inaczej i dlaczego

    ok. 3 min
    Polecenie z arkusza

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

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

    wersja podstawowata wersja
    SQLzapytania w jednej liniiklauzule w liniach, aliasy wyniku, ORDER BY
    układflexbox w kolumnie, flex-wrap, kontener height: 730pxsiatka z trzema wierszami i nazwanymi obszarami
    blokicztery <section> z identyfikatoramiheader, nav, main, aside z klasami
    kolorywpisane w każdej regulezmienne w :root
    pola wyboru<input> + <label for> + <br>pole w <label>, display: block
    przyciskonclick="calculate()"formularz, zdarzenie submit
    skrypt<script> w twarz.htmlkalkulator.js z defer
    liczeniecztery if z cenami w kodzieobiekt PRICES, filter + reduce
    wynikinnerHTMLtextContent

    Sprawdzone: uprawnienia konta kosmetyczka logowaniem na to konto, kalkulator w prawdziwym Chrome dla wszystkich 16 kombinacji pól (np. maska, masaż twarzy i makijaż = 100, jak na obrazie 3), układ pomiarem: bloki 25% i 75%, wysokości 400/330 i 150/580 px, stopka 730 px pod górną krawędzią bloków.

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

  41. Krok 41: 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: cztery if z getElementById i checked pisze się bez zastanowienia, a flexbox z zawijaniem wymaga jednej reguły.
    • Ta wersja, gdy siatkę z nazwanymi obszarami i metody tablic filter/reduce zna się na pamięć. Plik kalkulator.js trzeba nagrać na płytę - bez niego kalkulator nie działa, a punkty skryptu egzaminator sprawdzi już tylko w kodzie.

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

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

  42. Etap 6: Oddanie pracy

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

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

    ok. 5 min
    Polecenie z arkusza

    Po zakończeniu pracy utwórz w folderze z numerem zdającego 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 przeglądarka.txt nazwa przeglądarki, w której strony były sprawdzane.

    W folderze: import.png, index.html, kw1.jpg - kw4.jpg, kwerendy.txt, obraz1.jpg, obraz2.jpg, przeglądarka.txt, styl7.css, twarz.html oraz kalkulator.js („ewentualnie inne przygotowane pliki”). Nagraj płytę, sprawdź jej odczyt i opisz ją numerem zdającego.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

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.