Anatomia znacznika HTML — Składnia, Atrybuty i Struktura Drzewa

Kąt widzenia: precyzyjne rozumienie składni HTML — elementy, atrybuty, zagnieżdżanie, void elements i DOM — z przykładami z kontekstu .NET (karty produktów, pola formularzy)
Przykład przewodni: karta produktu w sklepie i pole logowania
Element vs znacznik (tag) — ważna różnica
Te dwa słowa są często używane zamiennie, ale mają precyzyjne znaczenia:
Znacznik (tag) to pojedynczy fragment składni: <div>, </div>, <img>. Jest otoczony nawiasami kątowymi < i >.
Element to całość: znacznik otwierający + treść + znacznik zamykający.
<h1>Klawiatura mechaniczna</h1>
<!-- ↑ znacznik ↑ treść ↑ znacznik zamykający -->
<!-- całość to jeden element h1 -->
Analogia: w C# klasa ma nagłówek (public class Product) i ciało ({ ... }). Razem tworzą całą klasę. Tak samo <h1> i </h1> razem z treścią tworzą element.
Struktura elementu
Elementy z treścią (zawartością)
<p>Klawiatura mechaniczna Cherry MX Red, 10-keyless, podświetlenie RGB.</p>
Budowa:
<p>— znacznik otwierający (ang. opening tag)- tekst między nimi — treść (ang. content), może to być tekst lub inne elementy
</p>— znacznik zamykający (ang. closing tag) — ukośnik przed nazwą
Void elements — elementy bez treści
Niektóre elementy z definicji nie mają treści ani dzieci. Nigdy. Są to tzw. void elements:
<img src="/images/keyboard.jpg" alt="Klawiatura mechaniczna">
<br>
<hr>
<input type="text" name="search">
<meta charset="UTF-8">
<link rel="stylesheet" href="styles.css">
Nie mają znacznika zamykającego. Pisanie </img> lub <img /> to HTML5 toleruje (dla kompatybilności z XHTML), ale <img> to poprawna i zalecana forma.
Kompletna lista void elements: area, base, br, col, embed, hr, img, input, link, meta, param, source, track, wbr.
Różnica od XML/XHTML: w XML każdy element musi być zamknięty — <br/> lub <br></br>. W HTML5 void elements nie mają zamknięcia.
Atrybuty — dane o elemencie
Atrybuty dają dodatkowe informacje o elemencie. Umieszcza się je wewnątrz znacznika otwierającego, jako pary nazwa="wartość":
<img src="/images/keyboard.jpg" alt="Klawiatura mechaniczna" width="400" height="300">
Rozkład:
src— atrybut, wartość"/images/keyboard.jpg"— źródło obrazualt— atrybut, wartość"Klawiatura mechaniczna"— tekst alternatywny (dostępność, SEO)widthiheight— wymiary w pikselach
Kilka zasad o atrybutach
Kolejność atrybutów nie ma znaczenia — przeglądarka traktuje je tak samo niezależnie od kolejności.
Wartości w cudzysłowach — technicznie HTML5 dopuszcza brak cudzysłowów dla prostych wartości, ale konwencja (i wymóg w Razor) to zawsze cudzysłowy:
<!-- Technicznie OK, ale zły styl -->
<img src=/images/keyboard.jpg alt=Klawiatura width=400>
<!-- Poprawnie -->
<img src="/images/keyboard.jpg" alt="Klawiatura" width="400">
Atrybuty logiczne (boolean) — nie mają wartości. Sama obecność atrybutu oznacza true:
<!-- Pole zaznaczone domyślnie -->
<input type="checkbox" name="newsletter" checked>
<!-- Pole wyłączone -->
<input type="text" name="promocode" disabled>
<!-- Pole wymagane -->
<input type="email" name="email" required>
checked, disabled, required, readonly, selected — to boolean attributes. checked="false" nie wyłącza checkboxa — żeby wyłączyć, usuń atrybut checked w ogóle.
Atrybuty globalne — działają na każdym elemencie
Kilka atrybutów jest dostępnych dla każdego elementu HTML:
<!-- id — unikalny identyfikator na stronie -->
<div id="product-42">...</div>
<!-- class — przypisanie do grupy elementów (CSS, JavaScript) -->
<div class="product-card featured">...</div>
<!-- style — style inline (unikaj w produkcji) -->
<p style="color: red;">Ostrzeżenie</p>
<!-- data-* — własne dane dla JavaScript -->
<div class="product-card" data-product-id="42" data-category="keyboards">...</div>
<!-- hidden — ukrywa element -->
<div hidden>Ten tekst jest niewidoczny</div>
<!-- title — tooltip po najechaniu -->
<abbr title="Graphical User Interface">GUI</abbr>
<!-- lang — język treści elementu -->
<p lang="en">This paragraph is in English.</p>
Atrybut data-* jest szczególnie ważny: pozwala osadzić dowolne dane w HTML, które JavaScript może odczytać bez dodatkowych żądań do serwera. W Razor możesz go generować z modelu:
<!-- Razor -->
<div class="product-card" data-product-id="@product.Id" data-in-stock="@product.IsInStock.ToString().ToLower()">
<!-- HTML output -->
<div class="product-card" data-product-id="42" data-in-stock="true">
Zagnieżdżanie — relacja rodzic–dziecko
HTML tworzy drzewo przez zagnieżdżanie elementów. Element zewnętrzny to rodzic, wewnętrzny to dziecko.
<div class="product-card"> <!-- rodzic -->
<div class="product-image"> <!-- dziecko div, rodzic img -->
<img src="/img/kb.jpg" alt="Klawiatura"> <!-- wnuk -->
</div>
<div class="product-info"> <!-- dziecko div -->
<h2 class="product-name">Klawiatura mechaniczna</h2> <!-- wnuk -->
<p class="product-desc">Cherry MX Red, podświetlenie RGB.</p>
<span class="price">299,00 zł</span>
</div>
<div class="product-actions">
<a href="/products/42" class="btn btn-primary">Szczegóły</a>
<button class="btn btn-secondary" data-product-id="42">Do koszyka</button>
</div>
</div>
Kluczowa zasada: elementy muszą być prawidłowo zagnieżdżone — zamykasz dziecko przed rodzicem:
<!-- ❌ Błąd — overlapping elements -->
<p>Klawiatura <strong>mechaniczna</p></strong>
<!-- ✅ Poprawnie -->
<p>Klawiatura <strong>mechaniczna</strong></p>
Przeglądarka naprawi błąd zagnieżdżenia (HTML jest tolerancyjny), ale DOM może wyglądać inaczej niż zamierzałeś, co prowadzi do trudnych do debugowania problemów CSS.
Elementy blokowe vs inline
Każdy element HTML ma domyślny typ wyświetlania:
Block elements (blokowe): zajmują całą dostępną szerokość, zaczynają się w nowej linii. Przykłady: div, p, h1–h6, ul, ol, section, header, footer, form.
Inline elements (liniowe): zajmują tylko tyle miejsca, ile potrzebuje ich treść. Nie łamią linii. Przykłady: span, a, strong, em, img, input, label, button.
<!-- Block — każdy div od nowej linii, pełna szerokość -->
<div>Produkt 1</div>
<div>Produkt 2</div>
<!-- Inline — span obok siebie w tej samej linii -->
Cena: <span class="old-price">349 zł</span> <span class="new-price">299 zł</span>
Ta właściwość jest definiowana przez CSS (wartość display), nie HTML — ale domyślne zachowanie elementów wynika z ich semantyki.
Komentarze w HTML
<!-- To jest komentarz HTML — przeglądarka go ignoruje -->
<!-- Komentarz wieloliniowy:
Sekcja produktów — wyświetlana tylko zalogowanym użytkownikom
Warunek sprawdzany po stronie serwera (Razor)
-->
Komentarze HTML są widoczne w źródle strony — widzi je każdy, kto wybierze “Pokaż źródło” w przeglądarce. Nigdy nie umieszczaj w komentarzach HTML wrażliwych informacji (kluczy API, haseł, wewnętrznych nazw endpointów). To jest błąd bezpieczeństwa.
W Razor masz komentarze Razor (@* ... *@), które NIE trafiają do wyjścia HTML:
@* Ten komentarz jest przetwarzany przez Razor — nie pojawi się w HTML *@
<!-- Ten komentarz POJAWI SIĘ w HTML wysłanym do przeglądarki -->
Znaki specjalne — HTML entities
Niektóre znaki mają specjalne znaczenie w HTML (<, >, &, ") i nie mogą być użyte bezpośrednio w treści. Używamy encji HTML:
| Znak | Encja | Użycie |
|---|---|---|
< | < | Wyświetlenie nawiasu (np. w tekście o kodzie) |
> | > | j.w. |
& | & | Ampersand w tekście (np. “R&D”) |
" | " | Cudzysłów wewnątrz atrybutu |
© | © | Symbol copyright |
€ | € | Symbol euro |
| Twarda spacja (non-breaking space) |
<p>Warunek: <code>if (price < 100 && isOnSale)</code></p>
<p>© 2026 Dev-Hobby. Wszelkie prawa zastrzeżone.</p>
<footer>Cena: 299 zł</footer> <!-- zapobiega łamaniu "299 zł" -->
W Razor — Razor automatycznie enkoduje HTML w wyrażeniach @. Jeśli masz w modelu "<script>", to @Model.Name wyświetli <script> — bezpiecznie. Tylko @Html.Raw() wyłącza enkodowanie (i jest niebezpieczne, jeśli dane pochodzą od użytkownika).
Jak czytać HTML w DevTools
Najważniejsze narzędzie do debugowania widoków: F12 → zakładka Elements (Chrome) lub Inspector (Firefox).
DevTools pokazuje live DOM — nie surowy HTML z odpowiedzi, ale aktualny stan drzewa po modyfikacjach przez JavaScript. To jest źródło prawdy o tym, co przeglądarka faktycznie widzi.
Praktyczne użycie:
- Kliknij prawym na element → Inspect → wiesz dokładnie jaki HTML odpowiada temu co widzisz
- W panelu Elements możesz edytować atrybuty i treść na żywo — bez przeładowania
- Zakładka Network → żądanie strony → Response — to surowy HTML z serwera (przed JavaScript)
Podsumowanie
| Pojęcie | Definicja |
|---|---|
| Tag | <div> lub </div> — jeden ogranicznik |
| Element | Kompletna struktura: <div>treść</div> |
| Void element | Element bez treści i zamknięcia: <img>, <input> |
| Atrybut | Para nazwa="wartość" wewnątrz tagu otwierającego |
| Boolean attribute | Atrybut bez wartości: disabled, required, checked |
| DOM | Drzewo obiektów w pamięci przeglądarki zbudowane z HTML |
Rozumienie tych elementarnych konceptów jest podstawą poprawnego pisania Razor Views i debugowania problemów z renderowaniem widoków ASP.NET Core.
Następny post: Semantyczne tagi HTML5 — struktura strony i znaczenie dla SEO i dostępności — które tagi używać zamiast <div> do tworzenia struktury strony i dlaczego ma to znaczenie dla wyszukiwarek i dostępności.
🚀 Co dalej?
Zobacz to w praktyce na wideo i pobierz darmową roadmapę, żeby ułożyć naukę w spójną ścieżkę do pierwszej pracy.
- 🗺️ Pobierz darmową roadmapę Junior .NET Developer — 12 kroków od podstaw C# do pierwszej pracy: dev-hobby.pl
- 🎬 Subskrybuj kanał YouTube — nowe filmy co tydzień.
2 comments
Dodaj komentarz
Musisz się zalogować, aby móc dodać komentarz.
Zamień wiedzę w umiejętności
Pobierz darmową Roadmapę .NET i ułóż takie tematy jak ten w spójną ścieżkę do pierwszej pracy.
Pobieram roadmapę →
Keep up the good work!