Moderní tvorba webových aplikací

O webu

Zanořování nezanořitelných HTML značek

Jak funguje zanořování značek jako <p> nebo <button> v HTML parseru versus DOM metodách.

8 minut

Některé HTML značky nelze do sebe zanořovat. Typickým příkladem jsou odstavce <p> nebo tlačítka <button>. HTML parser takové pokusy automaticky opraví. Ale co se stane, když stejnou strukturu vytvoříme pomocí DOM metod v JavaScriptu?

Porovnání HTML parseru a DOM metod při zanořování nezanořitelných značek

Problém s vnořováním

Zkusme napsat následující HTML kód, kde jeden odstavec zanořujeme do druhého:

<p>Vnější odstavec
  <p>Vnitřní odstavec</p>
</p>

HTML parser tento kód automaticky opraví a výsledný DOM bude vypadat následovně:

<p>Vnější odstavec</p>
<p>Vnitřní odstavec</p>
<p></p>

Parser při zjištění otevírací značky <p> uvnitř jiného <p> automaticky uzavře vnější odstavec. Poslední zavírací značka </p> pak vytvoří prázdný odstavec, protože nemá co uzavírat.

Vytvoření přes DOM metody

Co se ale stane, když stejnou strukturu vytvoříme pomocí JavaScriptu a DOM metod createElement a appendChild?

var vnejsi = document.createElement("p");
var vnitrni = document.createElement("p");

vnitrni.textContent = "Vnitřní odstavec";
vnejsi.textContent = "Vnější odstavec ";
vnejsi.appendChild(vnitrni);

document.body.appendChild(vnejsi);

V tomto případě žádná automatická oprava neproběhne! Výsledný DOM skutečně obsahuje <p> uvnitř jiného <p>, což je v HTML nevalidní struktura.

Vnořený odstavec v DevTools

Živá ukázka

Proč to funguje jinak?

Rozdíl je v tom, kdy se HTML parsuje:

  1. HTML parser zpracovává textový řetězec a podle HTML specifikace musí nevalidní struktury opravit. Parser , že <p> nemůže obsahovat další <p>, a automaticky první uzavře.
  2. DOM metody pracují přímo s objektovým modelem dokumentu. Když voláte appendChild, pouze říkáte prohlížeči „přidej tento element jako potomka". Parser se na to už nedívá, protože nepracujete s HTML řetězcem.

Další příklady nezanořitelných značek

Podobně jako <p> se chovají i další značky:

Tlačítko <button>

Tlačítko nesmí obsahovat další tlačítko:

<!-- HTML parser automaticky opraví -->
<button>Vnější
  <button>Vnitřní</button>
</button>

Ale přes DOM metody to jde:

var vnejsi = document.createElement("button");
var vnitrni = document.createElement("button");
vnitrni.textContent = "Vnitřní";
vnejsi.textContent = "Vnější ";
vnejsi.appendChild(vnitrni); // Funguje!

Živá ukázka

Vypadá to vskutku zajímavě:

Zanořené tlačítko

Odkaz <a>

Odkaz nesmí obsahovat další interaktivní element, jako je další odkaz nebo tlačítko:

<!-- Nevalidní, parser opraví -->
<a href="url1">
  <a href="url2">Vnořený odkaz</a>
</a>

Formulář <form>

Formulář nesmí obsahovat další formulář:

<!-- Nevalidní -->
<form>
  <form></form>
</form>

Praktické důsledky

Tento rozdíl je důležitý zejména pro JavaScriptové frameworky a knihovny, které vytvářejí DOM dynamicky.

innerHTML vs createElement

Při použití innerHTML se HTML řetězec parsuje stejně jako běžný HTML kód, takže se aplikují všechna omezení:

// HTML parser opraví strukturu
element.innerHTML = '<p>Vnější<p>Vnitřní</p></p>';

Zatímco při použití DOM metod se omezení neaplikují:

// Vytvoří nevalidní, ale funkční strukturu
var p1 = document.createElement('p');
var p2 = document.createElement('p');
p1.appendChild(p2);

Frameworky jako Svelte

Některé frameworky (např. Svelte) generují kód, který používá DOM metody. To znamená, že mohou vytvořit HTML struktury, které by v čistém HTML nešly napsat.

Toto chování může vést k neočekávaným výsledkům, pokud komponenta vytvoří strukturu, která je technicky nevalidní, ale v DOM funguje. Při použití innerHTML nebo server-side renderingu se taková struktura může chovat jinak.

HTML validace

I když DOM metody umožňují vytvořit nevalidní struktury, nedoporučuje se to dělat záměrně:

  • Může to způsobit nekonsistentní chování při různých způsobech renderování (CSR – klientské vs. SSR – serverové)
  • Validátory HTML budou hlásit chyby
  • Může to ovlivnit přístupnost (screen readery mohou mít problémy)
  • Budoucí verse prohlížečů mohou takové struktury opravovat

Stylování vnořených nezanořitelných elementů

Pokud se vám přes DOM metody podaří vytvořit vnořené nezanořitelné elementy, může se jejich stylování chovat neočekávaně.

CSS dědičnost a specifičnost

CSS pravidla se aplikují normálně, protože prohlížeč vidí validní DOM strukturu (i když je nevalidní podle HTML specifikace).

Takže tento nesmyslný selektor bude fungovat:

p p {
  color: blue;
}

Stylování vnořených tlačítek

U tlačítek je situace ještě komplikovanější. Tlačítko má speciální výchozí styly a chování (kursor, hover stavy, focus). Vnořené tlačítko zdědí některé vlastnosti, ale může mít problémy s:

  • Kliknutím – které tlačítko se má aktivovat?
  • Focus stavem – může dojít k neočekávanému visuálnímu zvýraznění
  • Z-indexem – vnořené tlačítko může překrývat vnější

Správné řešení

Namísto vnořování nezanořitelných značek použijte jiné elementy:

<!-- Místo vnořených odstavců -->
<div>
  <p>První odstavec</p>
  <p>Druhý odstavec</p>
</div>

<!-- Místo vnořených tlačítek -->
<div class="button-group">
  <button>První tlačítko</button>
  <button>Druhé tlačítko</button>
</div>

Teoreticky jde problém obejít použitím <span role="button" onclick=""> a CSS pro stylování, ale lepší řešení je většinou do sebe tlačítka nezanořovat.

Visuálně jde efektu tlačítka v tlačítku docílit absolutním posicováním.

Závěr

HTML parser a DOM metody se chovají odlišně při práci s nezanořitelnými značkami:

  • HTML parser (včetně innerHTML) automaticky opraví nevalidní struktury podle HTML specifikace
  • DOM metody (createElement, appendChild) umožňují vytvořit i nevalidní struktury, protože neprochází parserem
  • Tento rozdíl může způsobit problémy při různých způsobech renderování (CSR vs. SSR)
  • Nejlepší je dodržovat HTML specifikaci a nevytvářet nevalidní struktury záměrně

Odkazy jinam

Související články

Možnosti stylování <iframe>

Co lze a nelze u <iframe> ovlivnit pomocí CSS a jak na změnu textu nebo barev.

10 minut

HTML značka <keygen>

K čemu sloužila HTML značka <keygen>.

7 minut

Vložení CSS do stránky

Jakými všemi způsoby připojit CSS do stránky.

9 minut

Detekce otevření DevTools

Jak zjistit, že se na stránce otevřely vývojářské nástroje.

13 minut

Web jecas.cz píše Bohumil Jahoda, kontakt
Seznam všech článků
2013–2025