JavaScript 2 29.10.2025

Listy i nawigacje


Lista

jedna z częściej używanych struktur, służy do pokazywania informacji w prosty, łatwy, uporządkowany sposób. Wyróżnia się 3 główne typy list:

a) nieuporządkowana unordered list <ul>

tworzona elementem ul (lista zakupów, funkcje cechy produktu, tworzenie menu nawigacyjnego), każdy element jest oznaczony przez li list itemnumber, przeglądarka - wypunktowuje.

znacznik ul może zawierać jedynie elementy li, nie może mieć żadnych innych elementów. nie umieszcza się w nich, to nieprawidłowa składnia, ale można je umieszczać w tagu li

b) uporządkowana ordered list <ol>

kolejność ma znaczenie np. przepis, instrukcje krok po kroku, rankingi, domyślnie elementy są numerowane mimo ze w kodzie nie ma numerków tylko znaczniki li, definiowane przez liczby arabskie ale można dodać atrybuty styl numeracji ( 1, a, rzymskie itd), atrybut start określa od której liczby, pozycji nasza lista powinna startować, bo jest możliwość kontynuowania takiej listy (np. w przepisie,1, 2,3 potem tekst potem 4 5 6), można użyć reverse - odwrócić listę.

W liście uporządkowanej pojedynczy element li może mieć wartość value która zmienia numer i każde kolejne nr elementów za nim (48)

c) lista definicji definition list dl

służy do prezentowania par termin - definicja, idealna do słowników, często zadawanych pytań FAQ, struktura jest 3 członowa, rożni się tym właśnie od typu a i b, głównym tagiem jest dl, ale mamy dt definition term dd definition description, błędem jest umieszczanie tagów w dl, ale wew. tag dt i dd mozna dodawac np <p>

  1. Listy zagnieżdżone - hierarchiczna struktura, punktury zmieniają się, max 3 levele zagnieżdżenia, nie więcej bo wygląda źle, może byc to uporządkowane, może być mieszane, może być lista definicja, a w każdym z opisów definicji ma listę uporządkowana lub nieuporządkowaną

Jeśli mówimy o listach, nie służą one jedyne do wyświetlania danych. List również używa się aby czytelnie tworzyć hierarchie w nawigacji.

<h1>Typy list w HTML</h1>
    
    <!-- Lista nieuporządkowana - kolejność nie ma znaczenia -->
    <h2>Lista zakupów (nieuporządkowana)</h2>
    <ul>
        <li> podlista
            <ul>
                <li>1</li>
                <li>2</li>
                <li>3</li>
            </ul>
        </li>
        <li>Chleb</li>
        <li>Jajka</li>
        <li>Masło</li>
    </ul>
    
    <!-- Lista uporządkowana - kolejność ma znaczenie -->
    <h2>Przepis na ciasto (uporządkowana)</h2>
    <ol type="1" start="5" reversed>
        <li>Rozgrzej piekarnik do 180°C</li>
        <li value="5">Wymieszaj mąkę z cukrem</li>
        <li>Dodaj jajka i mleko</li>
        <li>Piecz przez 30 minut</li>
    </ol>
    
    <!-- Lista definicji - pary termin-definicja -->
    <h2>Słowniczek HTML (lista definicji)</h2>
    <dl>
        <dt>HTML</dt>
        <dd>HyperText Markup Language <p>język znaczników do tworzenia stron internetowych</p></dd>
        
        <dt>CSS</dt>
        <dd>Cascading Style Sheets - język stylów do formatowania dokumentów HTML</dd>
        
        <dt>JavaScript</dt>
        <dd>Język programowania używany do tworzenia interaktywnych stron internetowych</dd>
    </dl>
<h1>Hierarchiczna struktura z zagnieżdżonymi listami</h1>
    
    <h2>Struktura kursu programowania</h2>
    <ul>
        <li>Frontend Development
            <!-- Zagnieżdżona lista WEWNĄTRZ elementu li -->
            <ul>
                <li>HTML
                    <ul>
                        <li>Podstawy HTML</li>
                        <li>Formularze</li>
                        <li>Semantic HTML</li>
                    </ul>
                </li>
                <li>CSS
                    <ul>
                        <li>Selektory</li>
                        <li>Flexbox</li>
                        <li>Grid</li>
                    </ul>
                </li>
                <li>JavaScript</li>
            </ul>
        </li>
        <li>Backend Development
            <ul>
                <li>Node.js</li>
                <li>Python</li>
                <li>Bazy danych</li>
            </ul>
        </li>
    </ul>
    
    <!-- Mieszanie typów list -->
    <h2>Plan dnia (uporządkowane z nieuporządkowanymi)</h2>
    <ol>
        <li>Poranek
            <ul>
                <li>Śniadanie</li>
                <li>Prysznic</li>
            </ul>
        </li>
        <li>Praca
            <ul>
                <li>Spotkanie zespołu</li>
                <li>Programowanie</li>
                <li>Code review</li>
            </ul>
        </li>
        <li>Wieczór
            <ul>
                <li>Kolacja</li>
                <li>Relaks</li>
            </ul>
        </li>
    </ol>

wzorce tworzenia nawigacji, wzorce projektowe tworzenia elementów menu. Najważniejsze to primary navigation, zwykle w sekcji nav, dodatkowe secondary navigation często w tagu aside, dodatkowo tagi, linki, menu w stopce, te wszystkie rzeczy mogą być tworzone za pomocą listy, jeżeli ta struktura zostanie zachowana np. główne menu tworzymy w tagu nav, technologie pomagają użytkownikowi który potrzebuje accesbility, jeśli nie będzie się stosować semantycznego podejścia tych wzorców do tworzenia nawigacji, być może przeglądarka zinterpretuje to dobrze, ale może zdarzyć się, że nie powinno mieć dodatkowa właściwość aria-label by opisać co to jest - czytelny tekst. Dodatkowo główne menu powinno być listą nieuporządkowaną.

to co jest istotne dla linku - ma adres pod który się odwołuje, jak ma również current page wskazujący gdzie w obecnej chwili użytkownik się znajduje, technologie asysty bedą potrafiły to wtedy zinterpretować

<– Breadcrumbs - ścieżka nawigacyjna --> inne podejście, ale również jest to lista, jest uporządkowana tak aby dało się zobaczyć gdzie my jesteśmy, tam gdzie mamy aria current page tam nie mamy linku, a w związku z tym użytkownik intuicyjnie nie jest w stanie wybrać takiego adresu, ale jest w stanie wybrać wszystkie inne (allegro ścieżka produktu). Te okruszki pozwalają na zorientowanie się użytkownikowi jak daleko zabrnął, pozwalają mu się zorientować jak wrócić. Najczęstszym separatorem pomiędzy linkami powinna być > ostry nawias lub / lub strzałeczka, ten separator dodaje się automatycznie, css może go dać, jesteśmy w stanie odpowiednimi tagami w css uzyskać odpowiedni efekt

To poprawia użyteczność, ale również pomaga w SEO, w pozycjonowaniu strony, webcrawler indeksuje okruszki i wyświetla je w wynikach wyszukiwania.

Side navigation - szeroki termin, on obejmuje wszystkie aspekty nawigacyjne strony, dobra nawigacja - czytelna, przewidywalna, dostępna (opisy np. a aria-current) powinny być używane

Struktura nawigacji powinna odzwierciedlać stronę, jeśli ma zbyt wiele poziomów- przemyśleć. 3 max 4 poziomy zagnieżdżania. Nawigacja dobrze intepretowana poprzez urządzenia mobilne, na małych ekranach nie ma miejsca, ikonka hamburger trzy poziome kreski. Dobrym pomysłem jest używanie nawigacji dolnej, a przynajmniej linku aby wrócić do góry strony (go to top, top)

Skip navigation link- dodajemy taki niewidoczny link na dole strony, lub widoczny w sytuacji kiedy używamy z poziomu klawiatury, to pozwala przeskoczyć do góry, lub przejść do głównej treści. (1:16) (reader, do głównej str. nie widać ale go przeczyta, pod warunkiem display hidden a nie non).

<!-- Skip link dla dostępności -->
    <a href="#main-content">Przeskocz do głównej treści</a>
    
    <!-- Główna nawigacja strony -->
    <header>
        <h1>Moja Firma</h1>
        
        <nav aria-label="Główna nawigacja">
            <ul>
                <li><a href="/" aria-current="page">Strona główna</a></li>
                <li><a href="/o-nas">O nas</a></li>
                <li><a href="/uslugi">Usługi</a>
                    <!-- Menu rozwijane -->
                    <ul>
                        <li><a href="/uslugi/web">Web Development</a></li>
                        <li><a href="/uslugi/mobile">Mobile Apps</a></li>
                        <li><a href="/uslugi/consulting">Consulting</a></li>
                    </ul>
                </li>
                <li><a href="/portfolio">Portfolio</a></li>
                <li><a href="/kontakt">Kontakt</a></li>
            </ul>
        </nav>
    </header>
    
    <!-- Breadcrumbs - ścieżka nawigacyjna -->
    <nav aria-label="Ścieżka nawigacji">
        <ol>
            <li><a href="/">Strona główna</a></li>
            <li><a href="/uslugi">Usługi</a></li>
            <li><a href="/uslugi/web">Web Development</a></li>
            <li aria-current="page">Frontend Development</li>
        </ol>
    </nav>
    
    <!-- Główna treść -->
    <main id="main-content">
        <h2>Frontend Development</h2>
        <p>Treść strony o frontend development...</p>
    </main>
    
    <!-- Nawigacja boczna -->
    <aside>
        <nav aria-label="Nawigacja boczna">
            <h3>Powiązane tematy</h3>
            <ul>
                <li><a href="/blog/html">HTML Tutorial</a></li>
                <li><a href="/blog/css">CSS Tutorial</a></li>
                <li><a href="/blog/js">JavaScript Tutorial</a></li>
            </ul>
        </nav>
    </aside>
    
    <!-- Nawigacja stopki -->
    <footer>
        <nav aria-label="Nawigacja stopki">
            <h3>Linki</h3>
            <ul>
                <li><a href="/polityka-prywatnosci">Polityka prywatności</a></li>
                <li><a href="/regulamin">Regulamin</a></li>
                <li><a href="/mapa-strony">Mapa strony</a></li>
            </ul>
        </nav>
        
        <p>Copyright 2024 - Moja Firma</p>
    </footer>

Linki i multimedia


Linki

w początkach html to była kotiwca, a nie link. Tag do linków <a od anchor (kotwica). Linki to fundament hipertekstowości, czyli umożliwianie połączeń miedzy teksami, zasobami. Element pozornie prosty ale coveruje duży zestaw atrybutów.

href - hipertext reference wskazuje nam cel naszego linku, może mieć rożne typy - zewnętrzny dokument, adres, bezwzględny url

może być względna ścieżka - odnosić się względem tego dokumentu do jakiegoś innego katalogu, dokumentu products/laptops.html

../content przeglądarka ma pójść katalog wyżej i otworzyć katalog contact -> do js2, do głównego katalogu

/about

#top #section kotwice wewnątrz strony, góra str, dół str, footer

Linki protokołowe - mail to, tel, sms, co jest celem takiego linku, np otworzyć pocztę domyślny klient i otworzy nowego maila, nr tel na urządzeniu mobilnym - otwiera klawiaturę itd

Linki protokołowe, mówią przeglądarce co ma zrobić z takim linkiem, normalnie przeglądarka idzie do zasobu,

możemy zdefiniować: email, tytuł, treść email. w html nie stawia sie spacji, %20 to spacja aby to rozumieć

atrybut target kontroluje sposób otwierania linku - blank otwarcie w nowym oknie, kartce przydatne dla linków zewnętrznych - nawigacja aside np

blank implikacje związane z bezpieczeństwem - czy linki są dobre i bezpieczne, czy jeśli są dziś to czy zawsze będą, dostępnością dla użytkownika który używa technologii asystującej takie nowe okno lub karta może nie być do końca zrozumiałe

js 5 html screen, bezpieczne otwieranie SEO, semantyka dokumentu noooperner noreferrer

rel- ma zastosowanie

nofollow - nie przekazuje PageRank, np. reklama na zupełnie inny temat niż treści strony, jeśli nie będzie tego nofollow to nasza strona spadnie, bo webcrawler ją źle skataloguje

nofollow noopener - jeśli nie ma pewności czy str. jest bezpieczna, to mówi przeglądarce by nie mówić nowej stronie skąd przyszliście

canonical- już się nie używa, ale zdarzają się w starszych kodach strony. Oznacza ze ktoś np. pisał prace na podst. jakiegoś artykułu i wkleja wersje kanoniczną tego artykuły, ale teraz dużo częściej publikuje się prace inaczej, na specjalnych str., zamiast linkować na stronie html

rel next, prev - next, previous

rel author, category, tag

rel license, sponsored - rel license warto zrobić aby nasze treści były zabezpieczone, np żądamy podania autora bo autorem jesteśmy my to nas zabezpiecza

<a linki

title - informacyjny tytuł po najechaniu kursorem, dostarcza dodatkowe inf. o linku, wspiera accesibility, uzupełniające treść linku a nie powielające, przy weryfikacji str. pod wzgl. accesibility - super sprawa

<!-- Linki zewnętrzne - pełne adresy URL -->
<a href="https://www.example.com">Link do zewnętrznej strony</a>
<a href="https://www.google.com">Wyszukiwarka Google</a>

<!-- Linki względne - wewnątrz tej samej witryny -->
<a href="/about">O nas</a>
<a href="../contact">Kontakt (katalog wyżej)</a>
<a href="products/laptops.html">Laptopy (podkatalog)</a>

<!-- Linki do sekcji na tej samej stronie -->
<a href="#top">Góra strony</a>
<a href="#section-services">Przejdź do sekcji usług</a>
<a href="#footer">Stopka</a>

<!-- Linki protokołowe -->
<a href="mailto:[email protected]">Wyślij email</a>
<a href="tel:+48123456789">Zadzwoń: 123-456-789</a>
<a href="sms:+48123456789">Wyślij SMS</a>
 <!-- Otwieranie w nowym oknie/karcie -->
<a href="https://external-site.com" target="_blank">
    Link zewnętrzny (nowa karta)
</a>

<!-- Bezpieczne otwieranie zewnętrznych linków -->
<a href="https://external-site.com" target="_blank" rel="noopener noreferrer">
    Bezpieczny link zewnętrzny
</a>

<!-- Otwieranie w tym samym oknie (domyślne) -->
<a href="/internal-page" target="_self">
    Link wewnętrzny
</a>

<!-- Otwieranie w oknie nadrzędnym (dla ramek) -->
<a href="/main-page" target="_parent">
    Wyjdź z ramki
</a>

<!-- Otwieranie w najwyższym oknie (całkowite wyjście z ramek) -->
<a href="/home" target="_top">
    Strona główna (pełne okno)
</a>
<!-- Relacje dla wyszukiwarek -->
<a href="https://partner-site.com" rel="nofollow">
    Link sponsorowany (nie przekazuj PageRank)
</a>

<a href="https://untrusted-site.com" rel="nofollow noopener">
    Link do niezaufanej strony
</a>

<!-- Relacje kanoniczne -->
<a href="/canonical-version" rel="canonical">
    Wersja kanoniczna artykułu
</a>

<!-- Relacje nawigacyjne -->
<a href="/next-article" rel="next">Następny artykuł</a>
<a href="/previous-article" rel="prev">Poprzedni artykuł</a>

<!-- Relacje zasobów -->
<a href="/author-profile" rel="author">Profil autora</a>
<a href="/category/technology" rel="category">Kategoria: Technologia</a>
<a href="/tags/html" rel="tag">Tag: HTML</a>

<!-- Relacje biznesowe -->
<a href="/privacy-policy" rel="license">Licencja</a>
<a href="https://affiliate-link.com" rel="sponsored">Link partnerski</a>    
    <!-- Informacyjne tytuły -->
<a href="/download/manual.pdf" 
   title="Pobierz instrukcję obsługi (PDF, 2.3MB)">
   Instrukcja obsługi
</a>

<a href="https://external-news.com" 
   target="_blank"
   title="Artykuł otworzy się w nowej karcie">
   Przeczytaj więcej
</a>

<!-- Tytuły z dodatkowymi szczegółami -->
<a href="/product/smartphone-x" 
   title="SmartPhone X - 128GB, Black, 5G ready">
   SmartPhone X
</a>

<a href="mailto:[email protected]"
   title="Napisz do działu wsparcia technicznego">
   Pomoc techniczna
</a>

<!-- Tytuły dla nawigacji -->
<a href="#top" 
   title="Przejdź na początek strony">
   ↑ Góra
</a>

    <!-- Zaawansowane linki email -->
<a href="mailto:[email protected]?subject=Zapytanie%20ofertowe&body=Dzień%20dobry,%0D%0A%0D%0AChciałbym%20otrzymać%20ofertę...">
    Poproś o ofertę
</a><br>

<!-- Email z kopią i ukrytą kopią -->
<a href="mailto:[email protected][email protected]&[email protected]&subject=Raport%20miesięczny">
    Wyślij raport miesięczny
</a><br>

<!-- Linki telefoniczne z formatowaniem -->
<a href="tel:+48123456789" title="Zadzwoń na numer 123-456-789">
    📞 123-456-789
</a><br>

<!-- SMS z predefiniowaną wiadomością -->
<a href="sms:+48123456789?body=Witam,%20chciałbym%20umówić%20wizytę">
    📱 Wyślij SMS
</a>

MEDIA

Obrazki, filmy, zdjęcia powszechnie używane w dokumentach html


IMG

src - względna - ścieżka z neta, lub bezwzględna ścieżka u nas z katalogu

alt- alternative opis tekstowy obrazka który odczytuje czytniki obrazu, ale wyświetlany dla nas w przeglądarce w sytuacji gdy przeglądarka nie może załadować obrazu, np. link nie działa, nie ma już obrazka itd. KLUCZOWY ELEMENT DLA DOSTĘPNOŚCI I DLA PAGE RANK

longdesc - link do description

title- tytuł po najechaniu kursorem, np. przy użyciu galerii obrazków praca malarska kliknij żeby powiększyć

width, height - co do zasady rzeczywiste rozmiary img w px, ale jak podamy inna niż nasz obraz ma, to nasz obraz będzie rozciągnięty, ale zmniejszony, ale np. zależy mi tylko na wysokości to wystarczy ze nie podamy drugiej właściwości, i przeglądarka proporcjonalnie dopasuje ten obrazek do zadanego rozmiaru

Najlepiej mieć obrazki załadowane na swój server, ew. zewnątrz które szybciej się cashuja, krytyczne obrazki trzymać razem ze str. na serverze

Jakby obrazek się nie ładował, to pierwsze co warto zrobić to najechać w kodzie na src i nacisnąć ctrl i zobaczyć czy się otwiera, jak się otworzy to dobrze, ale może się okazać, że coś nie działa (2:30)

konsola f12 w chrome narzędzia developerskie, lub ppm źródło/zbadaj

src set, musimy obsłużyć wiele rozdzielczości, więc możemy ułożyć kolekcje obrazków, pokazuje który obrazek ma się wyświetlić w zależności jaki mamy rozmiar wyświetlacza,

sizes - minimalne rozm obrazka

loading- lazy ten obrazek nie musi się od razu ładować, info dla przeglądarki, jak inne załadują się to załaduj ten; eager - załaduj w pierwszej kolejności

nowoczesne formaty .avif, ma dużo lepsza kompresje, ale nie wszystkie przeglądarki lubią się z tymi nowoczesnymi formatami, wiec warto dodać do img bezpieczna ścieżkę fallback.

 <!-- Podstawowe użycie obrazu -->
<img src="https://fastly.picsum.photos/id/866/200/300.jpg?hmac=rcadCENKh4rD6MAp6V_ma-AyWv641M4iiOpe1RyFHeI" 
     alt="Logo firmy TechSolutions - niebieski napis na białym tle">

<!-- Obraz z opisem kontekstualnym -->
<img src="pics/866-200x300.jpga" 
     alt="Wykres słupkowy &quot;pokazujący&quot; wzrost sprzedaży o 23% w 2024 roku" height="200">

<!-- Obraz dekoracyjny (bez wartości informacyjnej) -->
<img src="/images/decorative-border.png" alt="">

<!-- Obraz z długim opisem -->
<img src="/images/complex-diagram.png" 
     alt="Schemat architektury systemu"
     longdesc="/descriptions/architecture-description.html">

<!-- Obrazy z różnymi formatami -->
<img src="/images/photo.webp" 
     alt="Zespół pracowników podczas spotkania w biurze"
     title="Spotkanie zespołu projektowego - styczeń 2024">

<!-- Obraz z wymiarami dla optymalizacji -->
<img src="/images/product-thumbnail.jpg" 
     alt="Miniatura produktu - Laptop Gaming Pro"
     width="200" 
     height="150">   

     <!-- Responsive images z srcset (density descriptors) -->
<img src="/images/hero-image-1x.jpg"
     srcset="/images/hero-image-1x.jpg 1x,
             /images/hero-image-2x.jpg 2x,
             /images/hero-image-3x.jpg 3x"
     alt="Główny obraz promocyjny pokazujący nasze produkty">

<!-- Responsive images z width descriptors -->
<img src="/images/product-400.jpg"
     srcset="/images/product-400.jpg 400w,
             /images/product-800.jpg 800w,
             /images/product-1200.jpg 1200w,
             /images/product-1600.jpg 1600w"
     sizes="(max-width: 400px) 100vw,
            (max-width: 800px) 50vw,
            25vw"
     alt="Zdjęcie produktu w wysokiej rozdzielczości">

<!-- Loading attribute dla performance -->
<img src="/images/below-fold-image.jpg"
     alt="Obraz widoczny po przewinięciu strony"
     loading="lazy"
     width="600"
     height="400">

<!-- Eager loading dla krytycznych obrazów -->
<img src="/images/hero-banner.jpg"
     alt="Główny banner promocyjny"
     loading="eager"
     fetchpriority="high">

<!-- Modern formats z fallback -->
<img src="/images/modern-format.avif"
     alt="Obraz w nowoczesnym formacie AVIF"
     onerror="this.src='/images/fallback.jpg'">

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
      <circle cx="150" cy="75" r="50" fill="blue" />
    </svg>

AUDIO

W zależności jakie przeglądarki wspierają formaty, jesteśmy w stanie podać kilka źródeł, oraz dodać fallback twoja przeglądarka nie obsługuje, ale tu masz link do pobrania

podstawowe audio kontrolki audio controls

audio z preloadowaniem audio cotrols preload - bufor, kawałek pliku załaduje się więcej do bufora, utrata Internetu nie spowoduje zastopowania

audio z pętlą (ostrożnie używać) audio controls loop - reklamy

audio z informacjami o pliku

figure - struktura opisująca co w audio się znajduje - dobra metoda na tworzenie str która ma być dostępna

<!-- Podstawowe audio z kontrolkami -->
<audio controls>
    <source src="av/offspring.mp3" type="audio/mpeg">
    <source src="/audio/podcast-episode-1.ogg" type="audio/ogg">
    <source src="/audio/podcast-episode-1.wav" type="audio/wav">
    <!-- Fallback dla starszych przeglądarek -->
    Twoja przeglądarka nie obsługuje elementu audio.
    <a href="/audio/podcast-episode-1.mp3">Pobierz plik audio</a>
</audio>

<!-- Audio z preloadowaniem -->
<audio controls preload="metadata">
    <source src="/audio/background-music.mp3" type="audio/mpeg">
    <source src="/audio/background-music.ogg" type="audio/ogg">
    Nie można odtworzyć pliku audio.
</audio>

<!-- Audio z pętlą (ostrożnie używać) -->
<audio controls loop>
    <source src="/audio/ambient-sound.mp3" type="audio/mpeg">
    <source src="/audio/ambient-sound.ogg" type="audio/ogg">
</audio>

<!-- Audio z informacjami o pliku -->
<figure>
    <figcaption>
        <h3>Wywiad z ekspertem - Odcinek 15</h3>
        <p>Czas trwania: 45 minut | Format: MP3 | Rozmiar: 32MB</p>
    </figcaption>
    <audio controls>
        <source src="/audio/interview-ep15.mp3" type="audio/mpeg">
        <source src="/audio/interview-ep15.ogg" type="audio/ogg">
        <p>Twoja przeglądarka nie obsługuje odtwarzania audio. 
           <a href="/audio/interview-ep15.mp3">Pobierz plik</a></p>
    </audio>
</figure>

WIDEO

mamy wpływ na rozmiar wyświetlanego odtwarzacza, możemy pokazać na nim obrazek - thumbnail

za pomocą css możemy tworzyć responsywny odtwarzacz który będzie się dostosowywał

autoplay od razu odtwarza się

loop pętla

muted wyciszone

<!-- Podstawowe wideo z posterem -->
<video controls width="800" height="450" poster="/images/video-thumbnail.jpg">
    <source src="/video/presentation.mp4" type="video/mp4">
    <source src="/video/presentation.webm" type="video/webm">
    <source src="/video/presentation.ogg" type="video/ogg">
    <!-- Napisy podrzędne -->
    <track kind="subtitles" src="/subtitles/presentation-pl.vtt" 
           srclang="pl" label="Polski">
    <track kind="subtitles" src="/subtitles/presentation-en.vtt" 
           srclang="en" label="English">
    
    <p>Twoja przeglądarka nie obsługuje odtwarzania wideo.
       <a href="/video/presentation.mp4">Pobierz film</a></p>
</video>

<!-- Wideo responsywne -->
<div style="position: relative; width: 100%; height: 0; padding-bottom: 56.25%;">
    <video controls 
           style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"
           poster="/images/tutorial-thumb.jpg">
        <source src="/video/tutorial-hd.mp4" type="video/mp4">
        <source src="/video/tutorial-hd.webm" type="video/webm">
        Nie można odtworzyć wideo.
    </video>
</div>

<!-- Wideo z opisami dla dostępności -->
<figure>
    <figcaption>
        <h3>Samouczek: Tworzenie formularzy HTML</h3>
        <p>W tym 10-minutowym filmie pokażemy, jak krok po kroku 
           stworzyć funkcjonalny formularz kontaktowy.</p>
    </figcaption>
    <video controls width="720" height="405">
        <source src="/video/html-forms-tutorial.mp4" type="video/mp4">
        <source src="/video/html-forms-tutorial.webm" type="video/webm">
        
        <!-- Napisy i opisy -->
        <track kind="subtitles" src="/tracks/subtitles-pl.vtt" 
               srclang="pl" label="Polskie napisy" default>
        <track kind="descriptions" src="/tracks/descriptions-pl.vtt" 
               srclang="pl" label="Audiodeskrypcja">
        <track kind="chapters" src="/tracks/chapters.vtt" 
               srclang="pl" label="Rozdziały">
        
        Wideo niedostępne w Twojej przeglądarce.
    </video>
</figure>

TABELE

Tabele powinny być używane wyłącznie do wyświetlania danych. Kiedyś używano tabel do budowania layoutów strony, dziś się tego nie robi i jest to b. zła praktyka. Nowoczesna struktura tabeli składa się z części semantycznych, które pomagają przeglądarka zrozumieć co to jest oraz technologiom asystującym.

border - stary atrybut! NIE UŻYWAĆ, nawet podkreśla się na czerwono by go nie używać

<table> kontener, definiujemy wew. niego różne sekcje, thead - nagłówek, tbody- ciało tabeli, tfoot stopka tabeli

tr- table row, th- table hedder, td table data

scope - czy nagłowek odnosci sie do kolumny, czy to wiersza,

colgroup

rowgroup

colspan tu jest tylko jedna komórka i ma sie rozciagnac na 5, rowspan- jedna komórka która ma sie rozciagac na dwa wiersze

dostępność dla tabel:

aria-label

role- jaka jest rola tego elementu na stronie,

caption- opis tabeli

Nowoczesne stylowanie tabel odbywa się w CSS

  <!-- Podstawowa struktura tabeli -->
<table border="1">
    <!-- Nagłówek tabeli -->
    <thead>
        <tr>
            <th>Nazwa produktu</th>
            <th>Cena</th>
            <th>Dostępność</th>
        </tr>
    </thead>
    
    <!-- Ciało tabeli z danymi -->
    <tbody>
        <tr>
            <td>Laptop Pro X</td>
            <td>4999 zł</td>
            <td>W magazynie</td>
        </tr>
        <tr>
            <td>Tablet Ultra</td>
            <td>1299 zł</td>
            <td>Brak w magazynie</td>
        </tr>
        <tr>
            <td>Smartphone Z</td>
            <td>899 zł</td>
            <td>W magazynie</td>
        </tr>
    </tbody>
</table>

<!-- Tabela z sekcją podsumowania -->
<table>
    <thead>
        <tr>
            <th>Miesiąc</th>
            <th>Przychody</th>
            <th>Koszty</th>
            <th>Zysk</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Styczeń</td>
            <td>50,000 zł</td>
            <td>30,000 zł</td>
            <td>20,000 zł</td>
        </tr>
        <tr>
            <td>Luty</td>
            <td>60,000 zł</td>
            <td>35,000 zł</td>
            <td>25,000 zł</td>
        </tr>
    </tbody>
    <!-- Stopka z podsumowaniem -->
    <tfoot>
        <tr>
            <th>RAZEM</th>
            <td>110,000 zł</td>
            <td>65,000 zł</td>
            <td>45,000 zł</td>
        </tr>
    </tfoot>
</table>


<!-- Tabela z colspan - komórki rozciągnięte poziomo -->
<table>
    <thead>
        <tr>
            <th colspan="3">Raport kwartalny - Q2 2024</th>
        </tr>
        <tr>
            <th scope="col">Dział</th>
            <th scope="col">Przychody</th>
            <th scope="col">Wzrost</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th scope="row">Sprzedaż</th>
            <td>250,000 zł</td>
            <td>+15%</td>
        </tr>
        <tr>
            <th scope="row">Marketing</th>
            <td>80,000 zł</td>
            <td>+8%</td>
        </tr>
        <tr>
            <td colspan="2"><strong>SUMA:</strong></td>
            <td><strong>330,000 zł</strong></td>
        </tr>
    </tbody>
</table>

<!-- Tabela z rowspan - komórki rozciągnięte pionowo -->
<table>
    <thead>
        <tr>
            <th scope="col">Kategoria</th>
            <th scope="col">Produkt</th>
            <th scope="col">Cena</th>
            <th scope="col">Ocena</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <!-- Komórka rozciągnięta na 3 wiersze -->
            <th scope="rowgroup" rowspan="3">Laptopy</th>
            <td>MacBook Pro</td>
            <td>8,999 zł</td>
            <td>9.5/10</td>
        </tr>
        <tr>
            <!-- Brak pierwszej komórki - jest częścią rowspan -->
            <td>Dell XPS</td>
            <td>6,499 zł</td>
            <td>9.0/10</td>
        </tr>
        <tr>
            <td>ThinkPad X1</td>
            <td>7,299 zł</td>
            <td>8.8/10</td>
        </tr>
        <tr>
            <th scope="rowgroup" rowspan="2">Tablety</th>
            <td>iPad Pro</td>
            <td>4,599 zł</td>
            <td>9.3/10</td>
        </tr>
        <tr>
            <td>Surface Pro</td>
            <td>4,999 zł</td>
            <td>8.9/10</td>
        </tr>
    </tbody>
</table>

<!-- Złożona tabela łącząca colspan i rowspan -->
<table border="1" cellpadding="0" cellspacing="0">
    <thead>
        <tr>
            <th colspan="5">Harmonogram szkoleń - Grudzień 2024</th>
        </tr>
        <tr>
            <th scope="col">Godzina</th>
            <th scope="col">Poniedziałek</th>
            <th scope="col">Wtorek</th>
            <th scope="col">Środa</th>
            <th scope="col">Czwartek</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th scope="row">9:00-10:30</th>
            <td rowspan="2">HTML/CSS<br>Sala A</td>
            <td>JavaScript<br>Sala B</td>
            <td>React<br>Sala A</td>
            <td rowspan="2">Workshop<br>Sala C</td>
        </tr>
        <tr>
            <th scope="row">11:00-12:30</th>
            <!-- Pierwsza komórka jest częścią rowspan -->
            <td>Node.js<br>Sala B</td>
            <td>Database<br>Sala B</td>
            <!-- Czwarta komórka jest częścią rowspan -->
        </tr>
        <tr>
            <th scope="row">14:00-15:30</th>
            <td colspan="4">Prezentacje projektów - Aula główna</td>
        </tr>
    </tbody>
</table>

<!-- Tabela z opisowym caption -->
<table>
    <caption>
        Wyniki sprzedaży produktów elektronicznych w pierwszym kwartale 2024 roku
        (kwoty w tysiącach złotych)
    </caption>
    <thead>
        <tr>
            <th scope="col">Produkt</th>
            <th scope="col">Styczeń</th>
            <th scope="col">Luty</th>
            <th scope="col">Marzec</th>
            <th scope="col">Razem Q1</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th scope="row">Smartfony</th>
            <td>320</td>
            <td>285</td>
            <td>410</td>
            <td>1,015</td>
        </tr>
        <tr>
            <th scope="row">Laptopy</th>
            <td>150</td>
            <td>165</td>
            <td>180</td>
            <td>495</td>
        </tr>
        <tr>
            <th scope="row">Tablety</th>
            <td>80</td>
            <td>95</td>
            <td>110</td>
            <td>285</td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
            <th scope="row">SUMA KATEGORII</th>
            <td>550</td>
            <td>545</td>
            <td>700</td>
            <td>1,795</td>
        </tr>
    </tfoot>
</table>
<br>
<!-- Tabela z dodatkowymi atrybutami accessibility -->
<table role="table" aria-label="Porównanie planów abonamentowych">
    <caption id="plans-caption">
        Dostępne plany abonamentowych - porównanie cech i cen
        <div>Aktualne na dzień: <time datetime="2024-12-01">1 grudnia 2024</time></div>
    </caption>
    <thead>
        <tr role="row">
            <th scope="col" role="columnheader">Cecha planu</th>
            <th scope="col" role="columnheader">Starter</th>
            <th scope="col" role="columnheader">Professional</th>
            <th scope="col" role="columnheader">Enterprise</th>
        </tr>
    </thead>
    <tbody>
        <tr role="row">
            <th scope="row" role="rowheader">Miesięczna opłata</th>
            <td role="gridcell">29 zł</td>
            <td role="gridcell">79 zł</td>
            <td role="gridcell">199 zł</td>
        </tr>
        <tr role="row">
            <th scope="row" role="rowheader">Liczba użytkowników</th>
            <td role="gridcell">Do 5</td>
            <td role="gridcell">Do 25</td>
            <td role="gridcell">Nieograniczona</td>
        </tr>
        <tr role="row">
            <th scope="row" role="rowheader">Przestrzeń dyskowa</th>
            <td role="gridcell">10 GB</td>
            <td role="gridcell">100 GB</td>
            <td role="gridcell">1 TB</td>
        </tr>
        <tr role="row">
            <th scope="row" role="rowheader">Wsparcie techniczne</th>
            <td role="gridcell">Email (24h)</td>
            <td role="gridcell">Email + Chat (8h)</td>
            <td role="gridcell">24/7 Premium</td>
        </tr>
    </tbody>
</table>
<p></p>
<!-- Tabela z explicitly linked headers -->
<table>
    <caption>Wyniki badań satysfakcji klientów według regionów i kategorii wiekowych</caption>
    <thead>
        <tr>
            <th id="region" scope="col">Region</th>
            <th id="age-18-30" scope="col">18-30 lat</th>
            <th id="age-31-50" scope="col">31-50 lat</th>
            <th id="age-51-plus" scope="col">51+ lat</th>
            <th id="average" scope="col">Średnia</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th id="north" scope="row">Północ</th>
            <td headers="north age-18-30">8.5</td>
            <td headers="north age-31-50">7.8</td>
            <td headers="north age-51-plus">8.2</td>
            <td headers="north average">8.17</td>
        </tr>
        <tr>
            <th id="south" scope="row">Południe</th>
            <td headers="south age-18-30">7.9</td>
            <td headers="south age-31-50">8.1</td>
            <td headers="south age-51-plus">8.4</td>
            <td headers="south average">8.13</td>
        </tr>
        <tr>
            <th id="east" scope="row">Wschód</th>
            <td headers="east age-18-30">8.0</td>
            <td headers="east age-31-50">7.7</td>
            <td headers="east age-51-plus">8.0</td>
            <td headers="east average">7.9</td>
        </tr>
        <tr>
            <th id="west" scope="row">Zachód</th>
            <td headers="west age-18-30">8.2</td>
            <td headers="west age-31-50">8.3</td>
            <td headers="west age-51-plus">8.6</td>
            <td headers="west average">8.37</td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
            <th id="total" scope="row">Średnia ogólna</th>
            <td headers="total age-18-30">8.15</td>
            <td headers="total age-31-50">7.98</td>
            <td headers="total age-51-plus">8.3</td>
            <td headers="total average">8.14</td>
        </tr>
    </tfoot>
</table>

<!-- Grupowanie kolumn dla lepszej semantyki -->
<table>
    <caption>Budżet projektu - podział na kategorie</caption>
    
    <!-- Definicja grup kolumn -->
    <colgroup>
        <!-- Pierwsza kolumna - nazwy kategorii -->
        <col style="width: 30%;">
        <!-- Grupa kolumn z kwotami -->
        <colgroup span="3">
            <col style="width: 20%; text-align: right;">
            <col style="width: 20%; text-align: right;">  
            <col style="width: 20%; text-align: right;">
        </colgroup>
        <!-- Kolumna podsumowująca -->
        <col style="width: 10%; text-align: right; font-weight: bold;">
    </colgroup>
    
    <thead>
        <tr>
            <th scope="col">Kategoria wydatków</th>
            <th scope="col">Q1</th>
            <th scope="col">Q2</th>
            <th scope="col">Q3</th>
            <th scope="col">SUMA</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th scope="row">Wynagrodzenia</th>
            <td>120,000</td>
            <td>125,000</td>
            <td>130,000</td>
            <td>375,000</td>
        </tr>
        <tr>
            <th scope="row">Materiały</th>
            <td>25,000</td>
            <td>30,000</td>
            <td>28,000</td>
            <td>83,000</td>
        </tr>
        <tr>
            <th scope="row">Marketing</th>
            <td>15,000</td>
            <td>20,000</td>
            <td>18,000</td>
            <td>53,000</td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
            <th scope="row">RAZEM</th>
            <td>160,000</td>
            <td>175,000</td>
            <td>176,000</td>
            <td>511,000</td>
        </tr>
    </tfoot>
</table>

<!-- Tabela z podstawowym formatowaniem semantycznym -->
<table>
    <caption>
        <strong>Ranking sprzedawców - III kwartał 2024</strong><br>
        <small>*kwoty w tysiącach złotych</small>
    </caption>
    
    <thead>
        <tr>
            <th scope="col">Pozycja</th>
            <th scope="col">Sprzedawca</th>
            <th scope="col">Sprzedaż*</th>
            <th scope="col">Cel*</th>
            <th scope="col">% celu</th>
            <th scope="col">Status</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><strong>1</strong></td>
            <th scope="row">Anna Kowalska</th>
            <td>485</td>
            <td>400</td>
            <td><strong>121%</strong></td>
            <td>🏆 Przekroczono</td>
        </tr>
        <tr>
            <td><strong>2</strong></td>
            <th scope="row">Jan Nowak</th>
            <td>392</td>
            <td>380</td>
            <td><strong>103%</strong></td>
            <td>✅ Osiągnięto</td>
        </tr>
        <tr>
            <td>3</td>
            <th scope="row">Maria Wiśniewska</th>
            <td>341</td>
            <td>360</td>
            <td><em>95%</em></td>
            <td>⚠️ Nieznacznie poniżej</td>
        </tr>
        <tr>
            <td>4</td>
            <th scope="row">Piotr Kaczmarek</th>
            <td>298</td>
            <td>340</td>
            <td><em>88%</em></td>
            <td>❌ Poniżej celu</td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
            <th scope="row" colspan="2">ŚREDNIA ZESPOŁU</th>
            <td>379</td>
            <td>370</td>
            <td><strong>102%</strong></td>
            <td>✅ Cel osiągnięty</td>
        </tr>
    </tfoot>
</table>   

Formularze

Podstawowa funkcja która pozwala użytkownikowi na interakcje ze stroną

action - wskazuje na url do którego zostaną przesłane dane formularza po jego przesyłaniu, może być względna i bezwzględna ścieżka

method - określa metode http używana do przesyłania danych, najczęściej używana jest metoda post (formularze wysyłające dane wrażliwe lub powodujące zmiany na serwerze) ale jest też używana metoda get, metoda get jest używana w przypadku formularzy wykorzystywanych do wyszukiwania (przykład z google)

enctype - jakiego rodzaju jest to formularza

novalidate - nie chcemy by się walidował

autocomplete on - nasze zapisane wpisy zapisane w przeglądarce

fieldset - wygenerowanie ramki dookoła, grupuje zesatw elementów w nich zawarty, z opisem ktróy wygeneraujemy w elemencie legend

input type text, number

id username, tel

name username

autocomplete username

minlenght maxlenght- długość wpisu, do walidacji.

required - obowiązkowe

Formularze mogą przyjmować pliki

type file

id avatar

name avatar

accept image - jaki rodzaj pliku akceptuje

button type submit wysyła inf

button type reset czyści formularz

phone tel pattern - można wprowadzić regex aby np było napisane +48 666 555 444

url pattern = https?:// też można sobie w regex wpisać pattern

id wyróżnik naszego elementu

label używają tego id do tego aby przyczepić się do tego elementu i go opisywać, tworzą semantyczne połączenie między opisem a kontrolką formularza, umożliwiając technologiom asystującym prawidłowe odczytanie i nawigacje

dwa sposoby tworzenia label - za pomoca id for a drugi metoda zagnieżdżenia samej kontrolki, inputu w tagu label, oba przypadki są poprawie intepretowane przez przeglądarkę

check box możemy mieć więcej niż 1, każdy może być do zaznaczenia

radiobuttony w grupie służą do wyboru 1 opcji z

Powinniśmy grupować nasze formularze, jak są pola wymagające czegoś od użytkownika, używać label, ważne by te label dobrze się nazywały, używać aria label aby nazywać formularze

select pole pozwalające na wybór, jest on kontenerem który ma opcje do wyboru, każda taka opcja musi mieć wartość, musi mieć opis, warto dodać opcję więcej która się wyświetli jako tzw pusta, w javascript zweryfikujemy sobie czy ta wartość została dobrze wybrana

<!-- Podstawowy formularz kontaktowy -->
<form action="/contact/submit" method="post">
    <!-- Kontener dla pól formularza -->
    <fieldset>
        <legend>Dane kontaktowe</legend>
        
        <!-- Pole tekstowe z etykietą -->
        <label for="name">Imię i nazwisko:</label>
        <input type="text" id="name" name="name" required>
        
        <label for="email">Email:</label>
        <input type="email" id="email" name="email" required>
        
        <label for="message">Wiadomość:</label>
        <textarea id="message" name="message" rows="5" cols="40" required></textarea>
    </fieldset>
    
    <!-- Przyciski akcji -->
    <button type="submit">Wyślij wiadomość</button>
    <button type="reset">Wyczyść formularz</button>
</form>

<!-- Formularz wyszukiwania -->
<form action="/search" method="get" role="search">
    <fieldset>
        <legend>Wyszukiwanie w serwisie</legend>
        
        <label for="query">Szukana fraza:</label>
        <input type="search" 
               id="query" 
               name="q" 
               placeholder="Wpisz słowa kluczowe..." 
               required>
               
        <button type="submit">Szukaj</button>
    </fieldset>
</form>

<!-- Formularz rejestracji z dodatkowymi atrybutami -->
<form action="/user/register" 
      method="post" 
      enctype="multipart/form-data"
      novalidate 
      autocomplete="on">
    
    <fieldset>
        <legend>Rejestracja nowego użytkownika</legend>
        
        <!-- Podstawowe dane -->
        <label for="username">Nazwa użytkownika:</label>
        <input type="text" 
               id="username" 
               name="username" 
               autocomplete="username"
               minlength="3" 
               maxlength="20" 
               required>
               
        <label for="reg-email">Adres email:</label>
        <input type="email" 
               id="reg-email" 
               name="email" 
               autocomplete="email"
               required>
               
        <!-- Pole hasła -->
        <label for="password">Hasło:</label>
        <input type="password" 
               id="password" 
               name="password" 
               autocomplete="new-password"
               minlength="8" 
               required>
               
        <!-- Upload pliku -->
        <label for="avatar">Zdjęcie profilowe (opcjonalne):</label>
        <input type="file" 
               id="avatar" 
               name="avatar" 
               accept="image/*">
    </fieldset>
    
    <button type="submit">Załóż konto</button>
    <button type="reset">Reset</button>
</form>   
<!-- Różne typy pól tekstowych -->
<form action="/profile/update" method="post">
    <fieldset>
        <legend>Dane osobowe</legend>
        
        <!-- Standardowe pole tekstowe -->
        <label for="first-name">Imię:</label>
        <input type="text" 
               id="first-name" 
               name="firstName" 
               autocomplete="given-name"
               placeholder="np. Jan"
               maxlength="50"
               required>
               
        <label for="last-name">Nazwisko:</label>
        <input type="text" 
               id="last-name" 
               name="lastName" 
               autocomplete="family-name"
               placeholder="np. Kowalski"
               maxlength="50"
               required>
               
        <!-- Pole email z walidacją -->
        <label for="user-email">Adres email:</label>
        <input type="email" 
               id="user-email" 
               name="email" 
               autocomplete="email"
               placeholder="[email protected]"
               required>
               
        <!-- Pole hasła -->
        <label for="current-password">Aktualne hasło:</label>
        <input type="password" 
               id="current-password" 
               name="currentPassword" 
               autocomplete="current-password"
               required>
               
        <label for="new-password">Nowe hasło:</label>
        <input type="password" 
               id="new-password" 
               name="newPassword" 
               autocomplete="new-password"
               minlength="8"
               pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d@$!%*?&]{8,}$"
               title="Hasło musi zawierać min. 8 znaków, w tym małą literę, dużą literę i cyfrę">
    </fieldset>
    
    <!-- Pola numeryczne -->
    <fieldset>
        <legend>Informacje dodatkowe</legend>
        
        <label for="age">Wiek:</label>
        <input type="number" 
               id="age" 
               name="age" 
               min="13" 
               max="120" 
               step="1"
               placeholder="np. 25">
               
        <label for="phone">Numer telefonu:</label>
        <input type="tel" 
               id="phone" 
               name="phone" 
               autocomplete="tel"
               placeholder="+48 123 456 789"
               pattern="^\+?[0-9\s\-\(\)]{9,15}$">

               <!-- phone.value     name="gfdfbvdfbd" -->

        <!-- URL -->
        <label for="website">Strona internetowa:</label>
        <input type="url" 
               id="website" 
               name="website" 
               placeholder="https://example.com"
               pattern="https?://.+">
    </fieldset>
    
    <button type="submit">Aktualizuj profil</button>
</form>    
<!-- Różne metody łączenia labels z kontrolkami -->
<form action="/newsletter" method="post">
    <fieldset>
        <legend>Zapisz się do newslettera</legend>
        
        <!-- Metoda 1: Atrybut for -->
        <label for="subscriber-email">Twój adres email:</label>
        <input type="email" 
               id="subscriber-email" 
               name="email" 
               placeholder="[email protected]"
               required 
               aria-describedby="email-help">
        <div id="email-help">
            Wyślemy Ci maksymalnie 2 wiadomości miesięcznie
        </div>
        
        <!-- Metoda 2: Zagnieżdżona kontrolka -->
        <label>
            <input type="checkbox" name="terms" value="accepted" required>
            Akceptuję <a href="/terms" target="_blank">warunki serwisu</a>
        </label>
        
        <!-- Grupy opcji z fieldset i legend -->
        <fieldset>
            <legend>Preferowane tematy:</legend>
            
            <label>
                <input type="checkbox" name="topics" value="tech">
                Technologia
            </label>
            
            <label>
                <input type="checkbox" name="topics" value="business">
                Biznes
            </label>
            
            <label>
                <input type="checkbox" name="topics" value="design">
                Design
            </label>
            
            <label>
                <input type="checkbox" name="topics" value="marketing">
                Marketing
            </label>
        </fieldset>
        <p></p>
        <!-- Radio buttons z jednakową nazwą -->
        <fieldset>
            <legend>Jak często chcesz otrzymywać newsletter?</legend>
            
            <label>
                <input type="radio" name="frequency" value="weekly" checked>
                Raz w tygodniu
            </label>
            
            <label>
                <input type="radio" name="frequency" value="monthly">
                Raz w miesiącu
            </label>
            
            <label>
                <input type="radio" name="frequency" value="quarterly">
                Raz na kwartał
            </label>
        </fieldset>
    </fieldset>
    
    <button type="submit">Zapisz się</button>
</form>

<!-- Formularz kontaktowy z rozbudowanymi etykietami -->
<form action="/support" method="post">
    <fieldset>
        <legend>Formularz wsparcia technicznego</legend>
        
        <label for="ticket-subject">
            Temat zgłoszenia: <span aria-label="pole wymagane">*</span>
        </label>
        <input type="text" 
               id="ticket-subject" 
               name="subject" 
               required 
               aria-required="true"
               aria-describedby="subject-hint">
        <div id="subject-hint">
            Opisz problem w kilku słowach
        </div>
        
        <label for="priority-level">
            Priorytet: <span aria-label="pole wymagane">*</span>
        </label>
        <select id="priority-level" 
                name="priority" 
                required 
                aria-required="true">
            <option value="">Wybierz priorytet</option>
            <option value="low">Niski</option>
            <option value="medium">Średni</option>
            <option value="high">Wysoki</option>
            <option value="critical">Krytyczny</option>
        </select>
        
        <label for="issue-description">
            Szczegółowy opis problemu:
        </label>
        <textarea id="issue-description" 
                  name="description" 
                  rows="8" 
                  cols="50"
                  placeholder="Opisz szczegółowo napotkany problem, kroki jego odtworzenia oraz oczekiwane zachowanie systemu..."
                  aria-describedby="description-help"></textarea>
        <div id="description-help">
            Im więcej szczegółów podasz, tym szybciej pomożemy rozwiązać problem
        </div>
    </fieldset>
    
    <button type="submit">Wyślij zgłoszenie</button> aaaaa
</form>