script, noscript, dialog, details, summary, template + kompletní přehled globálních atributů — data-*, aria-*, tabindex a další.
Vloží nebo načte JS. defer/async zabrání blokování parsování. Vždy preferujte defer v head.
Script bez atributů blokuje parsování HTML — prohlížeč zastaví čtení stránky, stáhne a spustí JS, pak pokračuje. defer = spustí po parsování, zachová pořadí skriptů. async = spustí hned po stažení bez čekání. type="module" má automaticky defer.
| src | URL externího JS souboru | URL |
| defer | Spustí po parsování HTML, zachová pořadí | boolean |
| async | Spustí hned po stažení, bez pořadí | boolean |
| type | module = ES modules (auto defer), importmap | module |
| nomodule | Fallback pro prohlížeče bez ES modules | boolean |
| integrity | SRI hash pro bezpečnost CDN skriptů | sha384-... |
| crossorigin | CORS pro integrity check | anonymous |
<!-- ✅ DOPORUČENO: defer v head -->
<head>
<script src="app.js" defer></script>
</head>
<!-- ✅ ES Modules (auto defer) -->
<script type="module" src="main.js">
</script>
<!-- ✅ Analytika: async -->
<script async
src="https://analytics.example.com/tag.js">
</script>
<!-- ✅ SRI pro CDN bezpečnost -->
<script
src="https://cdn.example.com/lib.js"
integrity="sha384-abc123..."
crossorigin="anonymous"
defer
></script>
<!-- ✅ Import map (ES modules aliasy) -->
<script type="importmap">
{
"imports": {
"lodash": "/node_modules/lodash-es/lodash.js"
}
}
</script>
<!-- Nomodule fallback -->
<script type="module" src="modern.js">
</script>
<script nomodule src="legacy.js">
</script>
<!-- ❌ Blokuje parsování -->
<script src="app.js"></script>
Zobrazí obsah když JS není dostupný nebo zakázaný.
noscript zobrazí obsah pokud je JS vypnutý nebo nepodporovaný. V <head> může obsahovat link, style, meta. V <body> může obsahovat jakýkoliv HTML. Méně důležité dnes — ale stále relevantní pro SPA aplikace.
<!-- V head (jen meta/link/style) -->
<head>
<noscript>
<link rel="stylesheet"
href="no-js-styles.css">
</noscript>
</head>
<!-- V body -->
<body>
<noscript>
<div class="warning">
<strong>JavaScript je nutný.</strong>
<p>
Pro správné fungování aplikace
zapněte JavaScript v prohlížeči.
</p>
</div>
</noscript>
<div id="app"></div>
</body>
Moderní HTML modal bez JS knihoven. showModal() = modal s focus trap. Escape zavře automaticky.
dialog je nativní modální nebo nemodální dialog. showModal() = modal s automatickým focus trap (Tab uvízne uvnitř), Escape zavře automaticky, ::backdrop pro overlay. show() = nemodální dialog (bez overlay). Nahrazuje vlastní div.modal implementace.
| open | Zobrazí dialog bez JS (bez overlaye!) | boolean |
| showModal() | Otevře jako MODAL — s focus trap a overlay |
| show() | Otevře jako nemodální dialog — bez overlay |
| close(value) | Zavře dialog, volitelná návratová hodnota |
| returnValue | Hodnota předaná do close() |
<!-- Trigger -->
<button type="button"
onclick="
document.getElementById('dlg')
.showModal()
">
Smazat položku
</button>
<!-- Dialog -->
<dialog id="dlg">
<h2>Potvrdit smazání</h2>
<p>Opravdu smazat tuto položku?</p>
<div class="dialog-btns">
<button type="button"
id="dlg-cancel">Zrušit</button>
<button type="button"
id="dlg-ok">Smazat</button>
</div>
</dialog>
<script>
const dlg = document.getElementById('dlg');
// Zrušit
document.getElementById('dlg-cancel')
.addEventListener('click', () => {
dlg.close('cancel');
});
// Potvrdit
document.getElementById('dlg-ok')
.addEventListener('click', () => {
deleteItem();
dlg.close('ok');
});
// Klik mimo dialog = zavřít
dlg.addEventListener('click', (e) => {
if (e.target === dlg) dlg.close();
});
// Reakce na zavření
dlg.addEventListener('close', () => {
console.log(dlg.returnValue); // ok/cancel
});
</script>
<style>
dialog {
border: 1px solid #333;
border-radius: 8px;
padding: 1.5rem;
max-width: 400px;
}
dialog::backdrop {
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(4px);
}
/* Animace otevření */
@keyframes slideIn {
from { opacity: 0; transform: translateY(-20px); }
to { opacity: 1; transform: translateY(0); }
}
dialog[open] {
animation: slideIn 0.2s ease-out;
}
</style>
Nativní rozklikávací sekce. summary = klikatelný titulek. open = rozbaleno defaultně. Žádný JS!
details je nativní rozklikávací sekce bez JavaScriptu. summary je klikatelný titulek — musí být první child. Atribut open = rozbaleno defaultně. Klávesnice funguje nativně. Skvělé pro FAQ, spoilers, collapse sekce.
| open | Rozbaleno defaultně | boolean |
| name | Exclusive accordion skupina (HTML 2024) | string |
<!-- Základní FAQ -->
<details>
<summary>Jak dlouho trvá doručení?</summary>
<p>Standardně 2–3 pracovní dny.</p>
</details>
<!-- Defaultně otevřeno -->
<details open>
<summary>Popis produktu</summary>
<p>Victorinox Classic je...</p>
</details>
<!-- Exclusive accordion (HTML 2024) -->
<details name="faq">
<summary>Otázka 1</summary>
<p>Odpověď 1...</p>
</details>
<details name="faq">
<summary>Otázka 2</summary>
<p>Odpověď 2...</p>
</details>
<!-- Otevřením jednoho se ostatní zavřou -->
<!-- CSS -->
<style>
details {
border: 1px solid #eee;
border-radius: 6px;
margin-bottom: 0.5rem;
}
summary {
padding: 0.75rem 1rem;
cursor: pointer;
font-weight: 600;
list-style: none; /* skryje default šipku */
}
/* Vlastní šipka */
summary::before {
content: '▸ ';
transition: transform 0.2s;
display: inline-block;
}
details[open] summary::before {
transform: rotate(90deg);
}
details > :not(summary) {
padding: 0 1rem 0.75rem;
}
/* Animace (CSS-only) */
details[open] > :not(summary) {
animation: fadeDown 0.2s ease;
}
@keyframes fadeDown {
from { opacity: 0; transform: translateY(-8px); }
to { opacity: 1; transform: translateY(0); }
}
</style>
Kus HTML který se nerendiruje ani nespouští. Klonuje se JavaScriptem pro dynamické přidávání obsahu.
template obsahuje HTML které není renderováno ani stahováno (obrázky, skripty uvnitř se nespustí). Klonujeme ho JS pomocí content.cloneNode(true) pro dynamické vytváření elementů. Bezpečnější alternativa k innerHTML — žádné XSS riziko.
| id | Identifikátor pro JS selekci | string |
| shadowrootmode | Declarative Shadow DOM (nový) | open/closed |
<!-- Šablona (neviditelná) -->
<template id="product-card">
<div class="card">
<img class="card-img" alt="">
<div class="card-body">
<h3 class="card-title"></h3>
<p class="card-price"></p>
<button type="button"
class="card-btn">
Do košíku
</button>
</div>
</div>
</template>
<!-- Kontejner -->
<div id="product-list"></div>
<script>
const products = [
{
id: 1,
nazev: 'Victorinox Classic',
cena: '299 Kč',
img: 'classic.jpg'
},
{
id: 2,
nazev: 'Gerber Paraframe',
cena: '549 Kč',
img: 'paraframe.jpg'
}
];
const tmpl = document.getElementById(
'product-card'
);
const list = document.getElementById(
'product-list'
);
products.forEach(p => {
// Klonovat šablonu
const clone = tmpl.content.cloneNode(true);
// Vyplnit data
clone.querySelector('.card-img').src = p.img;
clone.querySelector('.card-img').alt = p.nazev;
clone.querySelector('.card-title')
.textContent = p.nazev;
clone.querySelector('.card-price')
.textContent = p.cena;
clone.querySelector('.card-btn')
.dataset.productId = p.id;
// Přidat do DOM
list.appendChild(clone);
});
</script>
id, class, data-*, aria-*, lang, hidden, tabindex, contenteditable, draggable...
Globální atributy lze použít na každém HTML elementu. Nejdůležitější skupiny: identifikace (id, class), datové atributy (data-*), přístupnost (aria-*, role, tabindex), chování (hidden, contenteditable, draggable).
<!-- data-* atributy -->
<button
type="button"
data-product-id="42"
data-price="299"
data-category="nože"
onclick="addToCart(this)"
>
Do košíku
</button>
<script>
function addToCart(btn) {
// el.dataset.atributName (camelCase)
const id = btn.dataset.productId; // "42"
const price = btn.dataset.price; // "299"
const cat = btn.dataset.category; // "nože"
console.log(id, price, cat);
}
</script>
<!-- aria-* pro přístupnost -->
<button
type="button"
aria-expanded="false"
aria-controls="menu"
id="menu-btn"
>
Menu
</button>
<ul id="menu" hidden
role="menu"
aria-labelledby="menu-btn">
<li role="menuitem">
<a href="/">Domů</a>
</li>
</ul>
<script>
const btn = document.getElementById('menu-btn');
const menu = document.getElementById('menu');
btn.addEventListener('click', () => {
const isOpen = btn.getAttribute(
'aria-expanded'
) === 'true';
btn.setAttribute('aria-expanded', !isOpen);
menu.hidden = isOpen;
});
</script>
<!-- tabindex -->
<!-- 0 = fokus v přirozeném pořadí -->
<div tabindex="0" role="button"
onkeydown="handleKey(event)"
onclick="doSomething()">
Klikatelný div (raději button!)
</div>
<!-- -1 = fokus jen z JS -->
<div id="modal-content" tabindex="-1">
Modal obsah
</div>
<script>
// Při otevření modalu
document.getElementById('modal-content')
.focus();
</script>
<!-- aria-live region -->
<div aria-live="polite"
aria-atomic="true"
id="cart-status">
3 položky v košíku
</div>
<script>
// Jakákoli změna obsahu bude oznámena
document.getElementById('cart-status')
.textContent = '4 položky v košíku';
// Screen reader automaticky přečte změnu
</script>
<!-- contenteditable -->
<h1 contenteditable="true"
spellcheck="true"
data-placeholder="Klikněte a editujte">
Nadpis ke editaci
</h1>
Prošli jste všech 9 stránek — přes 80 HTML tagů s vysvětlením, příklady a tipy.
Pokračovat na CSS Taháček →