Мультимедіа та розширені елементи HTML
Мультимедіа та розширені елементи HTML
Коли текст недостатній
1993 рік. Марк Андрессен додає тег <img> у браузер Mosaic — і вперше в інтернеті з'являються зображення у тексті. Колеги кричали на нього: «Це зламає простоту вебу!». Але саме <img> перетворив WWW із академічної мережі на масовий феномен.
З тих пір шлях був довгим: Flash, QuickTime, RealPlayer, ActiveX — кожен намагався принести відео і звук у браузер через плагіни. У 2007 році Стів Джобс оголосив, що iPhone не підтримуватиме Flash. Це підштовхнуло до стандартизації — і у HTML5 з'явилися <video> та <audio>.
Сьогодні ми розберемо всю екосистему мультимедіа в HTML: від нативного відео до <canvas>, від <iframe> до <template>.
<video> — відеоплеєр
Що каже специфікація
<video> (video) є embedded content та interactive content (якщо є атрибути керування). Це замінний елемент (replaced element): його розміри визначаються зовнішнім ресурсом — відеофайлом.
Content model: нуль або більше <source>, нуль або більше <track>, потім transparent content (якщо немає атрибута src).
Базовий синтаксис
<div class="video-container">
<h3>1. Базовий плеєр (controls)</h3>
<video controls poster="https://peach.blender.org/wp-content/uploads/bbb-splash.png">
<source src="https://media.w3.org/2010/05/sintel/trailer.mp4" type="video/mp4" />
Ваш браузер не підтримує відео.
</video>
<h3>2. Фонове відео (autoplay, muted, loop)</h3>
<video autoplay muted loop playsinline>
<source src="https://media.w3.org/2010/05/sintel/trailer.mp4" type="video/mp4" />
</video>
<h3>3. Керування через JavaScript API</h3>
<video id="demoVideo">
<source src="https://media.w3.org/2010/05/sintel/trailer.mp4" type="video/mp4" />
</video>
<div class="controls">
<button onclick="playVideo()">Play</button>
<button onclick="pauseVideo()">Pause</button>
<button onclick="resetVideo()">Reset</button>
</div>
<div id="status" class="status-panel">Час: 0.0s</div>
</div>
.video-container {
padding: 1rem;
background-color: #f8fafc;
font-family: system-ui, sans-serif;
color: #1e293b;
border-radius: 8px;
}
h3 {
margin-top: 1.5rem;
font-size: 1rem;
color: #3b82f6;
}
video {
width: 100%;
border-radius: 6px;
background: #000;
}
.controls {
margin: 1rem 0;
display: flex;
gap: 0.5rem;
}
button {
padding: 0.5rem 1rem;
background-color: #3b82f6;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #2563eb;
}
.status-panel {
padding: 0.5rem;
background: #e2e8f0;
border-radius: 4px;
font-family: monospace;
}
const v = document.getElementById('demoVideo')
const s = document.getElementById('status')
function playVideo() {
v.play()
}
function pauseVideo() {
v.pause()
}
function resetVideo() {
v.pause()
v.currentTime = 0
}
v.ontimeupdate = () => {
s.textContent = `Час: ${v.currentTime.toFixed(1)}s / ${v.duration ? v.duration.toFixed(1) + 's' : '?'}`
}
Атрибути <video>
<source> для кількох форматів.muted. Обмежте використання.autoplay у більшості браузерів.none — не завантажувати; metadata — лише метадані (тривалість, розміри); auto — браузер вирішує.anonymous або use-credentials — для CORS при завантаженні з іншого домену.Відмінності кодеків
| Кодек | Контейнер | Підтримка | Якість/розмір | Коли |
|---|---|---|---|---|
| H.264 (AVC) | MP4 | ✅ Всі | Середня | Максимальна сумісність |
| H.265 (HEVC) | MP4 | ⚠️ Обмежена | Відмінна | Safari, платна ліцензія |
| VP9 | WebM | ✅ Сучасні | Добра | YouTube, Chrome |
| AV1 | MP4/WebM | ✅ Зростає | Найкраща | Майбутнє, YouTube 4K |
<source> — AV1 → VP9 (WebM) → H.264 (MP4). Браузер завантажить лише обраний формат.Hero-відео у фоні
<!-- Відео як фонова анімація (без звуку, без контролів) -->
<video autoplay muted loop playsinline preload="auto" aria-hidden="true" width="1920" height="1080">
<source src="/videos/hero-bg.av1.mp4" type="video/mp4; codecs=av01" />
<source src="/videos/hero-bg.vp9.webm" type="video/webm; codecs=vp9" />
<source src="/videos/hero-bg.h264.mp4" type="video/mp4" />
</video>
<!-- aria-hidden="true" — декоративне відео, скринрідер ігнорує -->
<track> — субтитри та текстові доріжки
<track> (track — доріжка) підключає текстові доріжки до <video> або <audio>. Файл повинен бути у форматі WebVTT (.vtt).
Значення атрибута kind
subtitles— переклад діалогів для тих, хто не розуміє мову відеоcaptions— субтитри для глухих: діалоги + звукові ефектиdescriptions— описи для незрячих (зачитує скринрідер)chapters— розділи для навігації по відеоmetadata— дані для JavaScript (не відображаються)
WEBVTT
00:00:00.000 --> 00:00:05.000
Привіт! Сьогодні ми розглянемо семантичний HTML.
00:00:05.500 --> 00:00:12.000
Семантика — це відповідність між виглядом і змістом елемента.
00:00:12.500 --> 00:00:18.000
[Звук клавіатури] Розробник відкриває редактор коду.
<video controls width="800" height="450">
<source src="/lesson.mp4" type="video/mp4" />
<!-- Субтитри (переклад) -->
<track kind="subtitles" src="/tracks/uk.vtt" srclang="uk" label="Українська" default />
<track kind="subtitles" src="/tracks/en.vtt" srclang="en" label="English" />
<!-- Captions (для глухих) -->
<track kind="captions" src="/tracks/uk-captions.vtt" srclang="uk" label="Субтитри (UK)" />
<!-- Розділи відео -->
<track kind="chapters" src="/tracks/chapters.vtt" srclang="uk" />
</video>
<audio> — аудіоплеєр
<audio> (audio — звук) — аналог <video> для звуку. Підтримує ті самі атрибути (controls, autoplay, muted, loop, preload) та дочірні <source> і <track>.
<div class="audio-container">
<h3>1. Нативний плеєр (controls)</h3>
<audio controls>
<source src="https://www.w3schools.com/html/horse.mp3" type="audio/mpeg" />
Ваш браузер не підтримує аудіо.
</audio>
<h3>2. Кастомне керування (JS API)</h3>
<audio id="demoAudio">
<source src="https://www.w3schools.com/html/horse.mp3" type="audio/mpeg" />
</audio>
<div class="controls">
<button onclick="playAudio()">Play</button>
<button onclick="pauseAudio()">Pause</button>
<button onclick="setVolume(0.5)">50% Vol</button>
<button onclick="setVolume(1)">100% Vol</button>
</div>
<div id="audioStatus" class="status-panel">Статус: Готовий</div>
</div>
.audio-container {
padding: 1rem;
background-color: #f8fafc;
font-family: system-ui, sans-serif;
color: #1e293b;
border-radius: 8px;
}
h3 {
margin-top: 1.5rem;
font-size: 1rem;
color: #3b82f6;
}
audio {
width: 100%;
margin: 1rem 0;
}
.controls {
display: flex;
gap: 0.5rem;
margin-bottom: 1rem;
}
button {
padding: 0.5rem 1rem;
background-color: #3b82f6;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #2563eb;
}
.status-panel {
padding: 0.5rem;
background: #e2e8f0;
border-radius: 4px;
font-family: monospace;
}
const a = document.getElementById('demoAudio')
const s = document.getElementById('audioStatus')
function playAudio() {
a.play()
}
function pauseAudio() {
a.pause()
}
function setVolume(v) {
a.volume = v
}
a.onplay = () => (s.textContent = 'Статус: Відтворення...')
a.onpause = () => (s.textContent = 'Статус: Пауза')
a.ontimeupdate = () => {
s.textContent = `Час: ${a.currentTime.toFixed(1)}s | Гучність: ${Math.round(a.volume * 100)}%`
}
Аудіоформати
| Формат | MIME-тип | Підтримка | Коли |
|---|---|---|---|
| MP3 | audio/mpeg | ✅ Всі | Найбезпечніший fallback |
| AAC | audio/aac | ✅ Всі | Кращий за MP3 за якістю |
| Opus | audio/ogg; codecs=opus | ✅ Сучасні | Найкраще стиснення |
| FLAC | audio/flac | ✅ Сучасні | Без втрат, великий розмір |
| OGG Vorbis | audio/ogg | ⚠️ Safari погано | Замінений Opus |
<iframe> — вбудований фрейм
<iframe> (inline frame — вбудований фрейм) вставляє вміст іншого HTML-документа в поточну сторінку. Це ціла пісочниця — окреме вікно перегляду зі своїм HTML, CSS, JavaScript.
Атрибути <iframe>
src).eager або lazy — відкладене завантаження iframe.no-referrer, strict-origin-when-cross-origin та ін.Вбудовані відео з YouTube
<div class="iframe-demo">
<p>1. Вміст через srcdoc (пісочниця):</p>
<iframe
title="Demo srcdoc"
sandbox="allow-scripts"
srcdoc="
<body style='font-family: system-ui, sans-serif; padding: 20px; background: #f0f9ff;'>
<h3 style='color: #3b82f6'>Привіт з iframe!</h3>
<p>Цей контент передано через <code>srcdoc</code>.</p>
<button onclick='alert(\"Працює!\")'>JS Тест</button>
</body>
">
</iframe>
<p>2. Вбудоване відео (YouTube):</p>
<iframe
width="100%"
height="300"
src="https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ"
title="YouTube"
allowfullscreen>
</iframe>
</div>
.iframe-demo {
padding: 1rem;
background-color: #f8fafc;
font-family: system-ui, sans-serif;
border-radius: 8px;
}
iframe {
border: 2px solid #e2e8f0;
border-radius: 6px;
width: 100%;
margin-bottom: 1.5rem;
background: white;
}
p {
font-weight: bold;
color: #3b82f6;
margin-bottom: 0.5rem;
}
Атрибут sandbox
<!-- Максимальна ізоляція (порожній sandbox) -->
<iframe src="https://untrusted-site.com" sandbox title="Ізольований контент"></iframe>
<!-- Дозволити лише форми та скрипти -->
<iframe src="/widget/calculator.html" sandbox="allow-forms allow-scripts" title="Калькулятор"></iframe>
<!-- Повний список значень sandbox -->
<!--
allow-downloads — завантаження файлів
allow-forms — відправка форм
allow-modals — alert(), confirm(), prompt()
allow-orientation-lock — блокування орієнтації
allow-popups — window.open(), target="_blank"
allow-same-origin — зберігати origin (НЕ рекомендовано з allow-scripts!)
allow-scripts — виконання JavaScript
allow-top-navigation — навігація верхнього рівня
-->
sandbox="allow-scripts allow-same-origin" — це фактично скасовує sandbox, бо скрипт може видалити атрибут sandbox через DOM.srcdoc — HTML напряму у фреймі
<!-- Вміст безпосередньо в атрибуті — ізольований від основної сторінки -->
<iframe
title="Пісочниця для HTML"
sandbox="allow-scripts"
srcdoc="
<!DOCTYPE html>
<html>
<body>
<h1>Hello from iframe!</h1>
<script>document.body.style.background = 'lightyellow'</script>
</body>
</html>
"
></iframe>
<canvas> — 2D та 3D графіка
<canvas> (canvas — полотно) надає растровий засіб для малювання через JavaScript. За замовчуванням прозорий, 300×150 пікселів.
- Графіка, анімація, ігри (2D через Canvas API, 3D через WebGL/WebGPU)
- Не семантичний — вміст невидимий для скринрідерів
<div class="canvas-demo">
<canvas id="myCanvas" width="400" height="150"></canvas>
<p>Малювання через Canvas 2D API</p>
</div>
.canvas-demo {
padding: 1rem;
background-color: #f1f5f9;
text-align: center;
font-family: system-ui, sans-serif;
border-radius: 8px;
}
canvas {
background: white;
border: 1px solid #cbd5e1;
border-radius: 4px;
}
p {
font-size: 0.85rem;
color: #64748b;
margin-top: 0.5rem;
}
const c = document.getElementById('myCanvas')
const ctx = c.getContext('2d')
// Прямокутник
ctx.fillStyle = '#3b82f6'
ctx.fillRect(20, 20, 100, 60)
// Коло
ctx.beginPath()
ctx.arc(200, 50, 30, 0, Math.PI * 2)
ctx.fillStyle = '#10b981'
ctx.fill()
// Текст
ctx.font = 'bold 16px system-ui'
ctx.fillStyle = '#1e293b'
ctx.fillText('Hello Canvas', 280, 55)
<svg> — векторна графіка
<svg> (Scalable Vector Graphics — масштабована векторна графіка) дозволяє вбудовувати SVG-документ безпосередньо в HTML. На відміну від <img src="icon.svg">, inline SVG:
- Доступний для CSS (ми можемо стилізувати через CSS-класи)
- Доступний для JavaScript (живий DOM)
- Підтримує ARIA-атрибути для доступності
<!-- Проста іконка "зірка" — inline SVG -->
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
aria-label="Позначено як улюблене"
role="img"
fill="currentColor"
>
<title>Зірка (улюблене)</title>
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" />
</svg>
<!-- Логотип компанії — inline SVG для доступності -->
<a href="/">
<svg
xmlns="http://www.w3.org/2000/svg"
width="160"
height="40"
viewBox="0 0 160 40"
role="img"
aria-labelledby="logo-title"
>
<title id="logo-title">TechUA — Повернутися на головну</title>
<text x="10" y="28" font-family="Inter, sans-serif" font-size="24" font-weight="700">TechUA</text>
</svg>
</a>
<div class="svg-demo">
<svg viewBox="0 0 400 120" xmlns="http://www.w3.org/2000/svg">
<!-- Стовпці -->
<rect x="20" y="40" width="60" height="60" fill="#3b82f6" rx="4" />
<rect x="100" y="20" width="60" height="80" fill="#10b981" rx="4" />
<rect x="180" y="50" width="60" height="50" fill="#f59e0b" rx="4" />
<!-- Підписи -->
<text x="50" y="115" text-anchor="middle" font-family="system-ui" font-size="12">Q1</text>
<text x="130" y="115" text-anchor="middle" font-family="system-ui" font-size="12">Q2</text>
<text x="210" y="115" text-anchor="middle" font-family="system-ui" font-size="12">Q3</text>
</svg>
</div>
.svg-demo {
padding: 1.5rem;
background-color: #f8fafc;
border-radius: 8px;
display: flex;
justify-content: center;
}
svg {
width: 100%;
max-width: 400px;
height: auto;
}
text {
fill: #64748b;
}
<embed> та <object> — застарілі плагіни
<embed> та <object> використовувались для вбудовування Flash, PDF, плагінів. У сучасному HTML їхнє використання мінімальне.
<!-- <embed> — void element, завжди одинарний тег -->
<!-- Сьогодні: PDF у деяких браузерах (але краще <iframe>) -->
<div class="object-demo">
<h3>Демонстрація <object> з Fallback</h3>
<object data="/non-existent-file.pdf" type="application/pdf">
<div class="fallback">
<p>⚠️ Ваш браузер не підтримує перегляд PDF або файл не знайдено.</p>
<a href="#">Завантажити файл</a>
</div>
</object>
</div>
.object-demo {
padding: 1.5rem;
background-color: #f8fafc;
font-family: system-ui, sans-serif;
border-radius: 8px;
text-align: center;
}
h3 {
color: #3b82f6;
margin-bottom: 1rem;
}
object {
width: 100%;
height: 200px;
border: 1px solid #e2e8f0;
border-radius: 4px;
}
.fallback {
padding: 2rem;
background: #fff1f2;
border: 1px solid #fecaca;
border-radius: 4px;
color: #991b1b;
}
.fallback a {
color: #2563eb;
font-weight: bold;
}
<iframe> або бібліотекам на кшталт PDF.js. <embed> та <object> зберегли обмежену підтримку, але <object> для Flash повністю застарів.<template> та <slot> — Web Components
<template> — HTML-шаблон
<template> (template — шаблон) містить фрагмент HTML, який не рендериться при завантаженні сторінки, але доступний через JavaScript для клонування та вставки.
- Вміст
<template>знаходиться у DocumentFragment — ізольований від основного документа - Не виконуються скрипти, не завантажуються ресурси, не застосовуються стилі
<div class="template-demo">
<button onclick="addCard()">Додати з Template</button>
<div id="grid" class="grid"></div>
<template id="card-tpl">
<div class="card">
<h4>Новий елемент</h4>
<p>Створено з шаблону.</p>
</div>
</template>
</div>
.template-demo {
padding: 1rem;
background-color: #f8fafc;
font-family: system-ui, sans-serif;
}
button {
padding: 0.5rem 1rem;
background: #10b981;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 1rem;
margin-top: 1rem;
}
.card {
padding: 1rem;
background: white;
border: 1px solid #e2e8f0;
border-radius: 6px;
}
h4 {
margin: 0 0 0.5rem 0;
color: #3b82f6;
}
p {
margin: 0;
font-size: 0.85rem;
color: #64748b;
}
function addCard() {
const tpl = document.getElementById('card-tpl')
const clone = tpl.content.cloneNode(true)
document.getElementById('grid').appendChild(clone)
}
<slot> — слот для Web Components
<slot> використовується всередині Shadow DOM для розміщення контенту з основного документа у шаблоні компонента:
<!-- Визначення customs element -->
<template id="info-card">
<style>
:host {
display: block;
border: 1px solid #e5e7eb;
border-radius: 8px;
padding: 16px;
}
::slotted(h3) {
color: #3b82f6;
}
</style>
<slot name="header"><h3>Заголовок за замовчуванням</h3></slot>
<slot><!-- Основний вміст --></slot>
<slot name="footer"></slot>
</template>
<!-- Використання компонента (після реєстрації через JS) -->
<info-card>
<h3 slot="header">Новини тижня</h3>
<p>React 19 вийшов з офіційною підтримкою Server Components...</p>
<a href="/read-more" slot="footer">Читати далі</a>
</info-card>
<script> — скрипти
<script> вставляє або підключає JavaScript. Атрибути впливають на момент виконання:
<!-- 1. Синхронний (блокує рендеринг) — застаріла практика -->
<script src="/bundle.js"></script>
<!-- 2. defer: завантажує паралельно, виконує ПІСЛЯ парсингу HTML -->
<!-- Зберігає порядок виконання скриптів -->
<script src="/app.js" defer></script>
<!-- 3. async: завантажує паралельно, виконує ОДРАЗУ після завантаження -->
<!-- НЕ гарантує порядок виконання! -->
<script src="/analytics.js" async></script>
<!-- 4. type="module" — ES-модуль (defer за замовчуванням) -->
<script type="module" src="/main.mjs"></script>
<!-- 5. Інлайн-скрипт -->
<script>
console.log('Inline script!')
</script>
<!-- 6. JSON-дані (type="application/json") — не виконується -->
<script type="application/json" id="initial-data">
{ "user": "Ivan", "theme": "dark", "lang": "uk" }
</script>
Порівняння: async vs defer
defer. Для незалежних скриптів (аналітика, реклама) — async. Для старих бібліотек без залежностей від DOM — async. defer зберігає порядок, async — ні.<noscript> — резервний вміст без JS
<noscript> відображає вміст, коли JavaScript вимкнений або не підтримується:
<div class="noscript-demo">
<noscript>
<div class="warning">⚠️ JavaScript вимкнено. Деякі функції можуть не працювати.</div>
</noscript>
<p>Це демо симулює повідомлення для користувачів без JS.</p>
</div>
.noscript-demo {
padding: 1.5rem;
background-color: #f8fafc;
font-family: system-ui, sans-serif;
border-radius: 8px;
text-align: center;
}
.warning {
padding: 1rem;
background: #fff1f2;
border: 1px solid #fecaca;
border-radius: 4px;
color: #991b1b;
margin-bottom: 1rem;
}
<link> — зв'язні ресурси
<link> у <head> визначає відносини між документом та зовнішніми ресурсами:
<head>
<!-- CSS -->
<link rel="stylesheet" href="/styles/main.css" />
<!-- Preload — завантажити ресурс з найвищим пріоритетом -->
<!-- Критичні шрифти, hero-зображення, critical JS -->
<link rel="preload" href="/fonts/Inter-var.woff2" as="font" type="font/woff2" crossorigin />
<link rel="preload" href="/images/hero.avif" as="image" fetchpriority="high" />
<!-- Prefetch — заздалегідь завантажити наступну сторінку (низький пріоритет) -->
<link rel="prefetch" href="/dashboard.html" as="document" />
<!-- DNS prefetch — заздалегідь резолвити DNS -->
<link rel="dns-prefetch" href="//fonts.googleapis.com" />
<link rel="dns-prefetch" href="//analytics.example.com" />
<!-- Preconnect — встановити з'єднання заздалегідь (DNS + TLS + TCP) -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<!-- Canonical — вказати основну URL сторінки (SEO) -->
<link rel="canonical" href="https://techua.com/articles/semantic-html" />
<!-- Alternate — версії сторінки іншими мовами (hreflang) -->
<link rel="alternate" hreflang="uk" href="https://techua.com/uk/articles/semantic-html" />
<link rel="alternate" hreflang="en" href="https://techua.com/en/articles/semantic-html" />
<link rel="alternate" hreflang="x-default" href="https://techua.com/articles/semantic-html" />
<!-- RSS/Atom feed -->
<link rel="alternate" type="application/rss+xml" title="TechUA RSS" href="/rss.xml" />
<!-- Favicon -->
<link rel="icon" href="/favicon.ico" sizes="32x32" />
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180" />
<!-- Web App Manifest (PWA) -->
<link rel="manifest" href="/manifest.webmanifest" />
<!-- Номерні сторінки (для SEO пагінації) -->
<link rel="prev" href="/blog?page=2" />
<link rel="next" href="/blog?page=4" />
</head>
<meta> — метадані документа
<head>
<!-- Кодування — ЗАВЖДИ першим тегом у <head> -->
<meta charset="UTF-8" />
<!-- Viewport — обов'язково для мобільних -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- Стандартні SEO -->
<meta name="description" content="Стислий опис сторінки, 120–160 символів." />
<meta name="keywords" content="html, css, веб-розробка" />
<!-- Ігнорується Google -->
<meta name="author" content="Іван Коваленко" />
<meta name="robots" content="index, follow" />
<!-- Дозволити індексацію -->
<meta name="robots" content="noindex, nofollow" />
<!-- Заборонити -->
<!-- Theme color — колір рядка браузера (mobile) -->
<meta name="theme-color" content="#3b82f6" />
<meta name="theme-color" content="#1e1b4b" media="(prefers-color-scheme: dark)" />
<!-- Color scheme — підтримка dark mode -->
<meta name="color-scheme" content="light dark" />
<!-- Referrer policy -->
<meta name="referrer" content="strict-origin-when-cross-origin" />
<!-- HTTP equiv (симулює HTTP-заголовки) -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<!-- Застаріло -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'" />
<meta http-equiv="refresh" content="30" />
<!-- Оновити через 30 секунд -->
</head>
Практичні завдання
Створіть HTML-сторінку освітньої платформи — сторінку уроку:
<video controls>з трьома<source>(AV1 → VP9 → H.264) +<track>субтитри (UK/EN) +poster<audio controls>з MP3 та Opus — аудіоверсія уроку в<figure>+<figcaption><iframe>з YouTube без cookies (youtube-nocookie.com) +title,loading="lazy"- Inline SVG-іконки (play, bookmark, share) з належними
aria-labelабоrole="img"+<title>
Реалізуйте динамічний каталог:
<template id="card">— HTML-шаблон картки з<figure>,<img>,<h3>,<p>,<button>- JavaScript: отримайте масив із 6 об'єктів, клонуйте template для кожного, заповніть дані, вставте у
<section aria-label="Каталог"> <canvas id="stats" width="600" height="200">— намалюйте просту bar-chart: 6 стовпців для кожного товару (кількість переглядів), кольори, підписи (використайте Canvas 2D API)<noscript>з HTML-таблицею, як резервний варіант для canvas/template
Реалізуйте лендинг з повним мультимедійним секцією:
- Hero:
<video autoplay muted loop playsinline>як фон +aria-hidden="true", поверх — текст у<div>,<picture>для постера (mobile/desktop) - Плеєр курсу:
<video>з власними кнопками (play/pause, fullscreen через JS +<button>), програгрес-бар через<progress>, поточний час через<output>, субтитри через<track> - Технологічний стек: inline SVG для логотипів (React, Vue, TypeScript) — 4 іконки з
<title>,<desc>,aria-labelledby - Stats-секція:
<canvas>для лінійного графіку (останні 7 днів реєстрацій) - Embed з Maps:
<iframe>з Google Maps +sandbox,allow, правильнийtitle <head>:preloadдля hero-відео,preconnectдля CDN,dns-prefetch,canonical,alternateдля двох мов
Комплексний приклад від А до Я
Тема: Онлайн-школа «CodeCamp UA» — сторінка відеоуроку з усіма мультимедійними елементами.
<!DOCTYPE html>
<html lang="uk">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
name="description"
content="Відеоурок «Семантичний HTML» — CodeCamp UA. Тривалість 45 хв, рівень: початковий."
/>
<meta name="author" content="Марія Коваль" />
<meta name="theme-color" content="#4f46e5" />
<title>Семантичний HTML — Урок 6 | CodeCamp UA</title>
<link rel="canonical" href="https://codecamp.ua/courses/html/lesson-6" />
<link rel="alternate" hreflang="uk" href="https://codecamp.ua/uk/courses/html/lesson-6" />
<link rel="alternate" hreflang="en" href="https://codecamp.ua/en/courses/html/lesson-6" />
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<link rel="preload" href="/videos/lesson-6-poster.avif" as="image" fetchpriority="high" />
<link rel="preconnect" href="https://cdn.codecamp.ua" />
<link rel="dns-prefetch" href="//www.youtube-nocookie.com" />
<link rel="stylesheet" href="/styles/course.css" />
</head>
<body>
<header>
<a href="/">
<!-- Inline SVG логотип -->
<svg
xmlns="http://www.w3.org/2000/svg"
width="140"
height="36"
viewBox="0 0 140 36"
role="img"
aria-labelledby="logo-label"
>
<title id="logo-label">CodeCamp UA — Повернутися на головну</title>
<rect width="140" height="36" rx="6" fill="#4f46e5" />
<text
x="70"
y="25"
text-anchor="middle"
fill="white"
font-family="Inter,sans-serif"
font-size="14"
font-weight="700"
>
CodeCamp UA
</text>
</svg>
</a>
<nav aria-label="Головне меню">
<ul>
<li><a href="/courses">Курси</a></li>
<li><a href="/tracks">Треки</a></li>
<li><a href="/community">Спільнота</a></li>
<li><a href="/pricing">Ціни</a></li>
</ul>
</nav>
</header>
<main id="main-content">
<!-- Навігаційний шлях -->
<nav aria-label="Розташування в курсі">
<ol>
<li><a href="/courses">Курси</a></li>
<li><a href="/courses/html-css">HTML і CSS для початківців</a></li>
<li aria-current="page">Урок 6: Семантичний HTML</li>
</ol>
</nav>
<article>
<header>
<hgroup>
<h1>Урок 6: Семантичний HTML</h1>
<p>Навчіться будувати структуровані, доступні та SEO-оптимізовані сторінки</p>
</hgroup>
<dl>
<dt>Інструктор</dt>
<dd>
<address>
<a href="/instructors/maria-koval" rel="author">Марія Коваль</a>
</address>
</dd>
<dt>Тривалість</dt>
<dd><time datetime="PT45M">45 хвилин</time></dd>
<dt>Рівень</dt>
<dd>Початковий</dd>
<dt>Опубліковано</dt>
<dd><time datetime="2024-11-10">10 листопада 2024</time></dd>
</dl>
</header>
<!-- ===== ВІДЕОПЛЕЄР ===== -->
<section aria-labelledby="video-section">
<h2 id="video-section">Відео уроку</h2>
<figure>
<video
id="lesson-video"
controls
preload="metadata"
width="1280"
height="720"
poster="/videos/lesson-6-poster.avif"
>
<!-- AV1: найкраще стиснення, сучасні браузери -->
<source
src="https://cdn.codecamp.ua/videos/lesson-6.av1.mp4"
type="video/mp4; codecs=av01.0.05M.08"
/>
<!-- VP9: Chrome, Firefox, Edge -->
<source
src="https://cdn.codecamp.ua/videos/lesson-6.vp9.webm"
type="video/webm; codecs=vp9"
/>
<!-- H.264: максимальна сумісність -->
<source src="https://cdn.codecamp.ua/videos/lesson-6.h264.mp4" type="video/mp4" />
<!-- Субтитри -->
<track
kind="captions"
src="/tracks/lesson-6.uk.vtt"
srclang="uk"
label="Субтитри (Українська)"
default
/>
<track
kind="subtitles"
src="/tracks/lesson-6.en.vtt"
srclang="en"
label="English subtitles"
/>
<!-- Розділи -->
<track kind="chapters" src="/tracks/lesson-6-chapters.vtt" srclang="uk" />
<p>
Ваш браузер не підтримує HTML-відео.
<a href="https://cdn.codecamp.ua/videos/lesson-6.h264.mp4" download>
Завантажити відео (MP4) </a
>.
</p>
</video>
<figcaption>
Урок 6 — Семантичний HTML. Тривалість: <time datetime="PT45M">45 хвилин</time>.
</figcaption>
</figure>
<!-- Аудіоверсія -->
<details>
<summary>🎧 Слухати аудіоверсію уроку</summary>
<figure>
<figcaption>Урок 6: Семантичний HTML — аудіо (MP3, 28 МБ)</figcaption>
<audio controls preload="metadata">
<source
src="https://cdn.codecamp.ua/audio/lesson-6.opus"
type="audio/ogg; codecs=opus"
/>
<source src="https://cdn.codecamp.ua/audio/lesson-6.mp3" type="audio/mpeg" />
<p>
<a href="https://cdn.codecamp.ua/audio/lesson-6.mp3" download> Завантажити MP3 </a>
</p>
</audio>
</figure>
</details>
</section>
<!-- ===== РЕСУРСИ ===== -->
<section aria-labelledby="resources-heading">
<h2 id="resources-heading">Матеріали до уроку</h2>
<ul>
<li>
<a href="/files/lesson-6-slides.pdf" download="semantic-html-slides.pdf">
Завантажити слайди (PDF, 2.4 МБ)
</a>
</li>
<li>
<a
href="https://html.spec.whatwg.org/multipage/sections.html"
target="_blank"
rel="noopener noreferrer external"
>
HTML Living Standard: Sections ↗
</a>
</li>
<li>
<a
href="https://developer.mozilla.org/uk/docs/Web/HTML/Element"
target="_blank"
rel="noopener noreferrer external"
>
MDN: HTML-елементи (Українська) ↗
</a>
</li>
</ul>
</section>
<!-- ===== ДОДАТКОВЕ ВІДЕО ===== -->
<section aria-labelledby="bonus-heading">
<h2 id="bonus-heading">Бонус: виступ на JSFrontend 2024</h2>
<figure>
<iframe
width="560"
height="315"
src="https://www.youtube-nocookie.com/embed/ABC123xyz"
title="Марія Коваль — Семантичний HTML у реальних проєктах (JSFrontend 2024)"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen
loading="lazy"
referrerpolicy="strict-origin-when-cross-origin"
></iframe>
<figcaption>
Виступ Марії Коваль на конференції JSFrontend 2024.
<time datetime="PT25M">25 хвилин</time>.
</figcaption>
</figure>
</section>
<!-- ===== CANVAS ГРАФІК ===== -->
<section aria-labelledby="progress-heading">
<h2 id="progress-heading">Прогрес учнів</h2>
<figure>
<canvas
id="completion-chart"
width="600"
height="200"
role="img"
aria-label="Графік завершення уроку: 2340 учнів завершили повністю, 890 наполовину, 430 тільки почали"
>
<noscript>
<table>
<caption>
Статистика завершення Уроку 6
</caption>
<thead>
<tr>
<th scope="col">Статус</th>
<th scope="col">Кількість учнів</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Завершили повністю</th>
<td>2 340</td>
</tr>
<tr>
<th scope="row">Наполовину</th>
<td>890</td>
</tr>
<tr>
<th scope="row">Тільки почали</th>
<td>430</td>
</tr>
</tbody>
</table>
</noscript>
</canvas>
<figcaption>Рис. 1. Статистика проходження Уроку 6 станом на листопад 2024.</figcaption>
</figure>
</section>
<footer>
<p>Знайшли помилку? <a href="mailto:content@codecamp.ua">Повідомте нас</a>.</p>
<p>
<small>
Матеріал публікується за ліцензією
<a
href="https://creativecommons.org/licenses/by-nc/4.0/"
rel="license"
target="_blank"
rel="noopener noreferrer"
>CC BY-NC 4.0</a
>.
</small>
</p>
</footer>
</article>
<!-- ===== ASIDE: навігація по курсу ===== -->
<aside aria-label="Навігація по курсу">
<section>
<h2>Курс: HTML і CSS для початківців</h2>
<nav aria-label="Уроки курсу">
<ol>
<li><a href="/courses/html-css/lesson-1">Урок 1: Що таке HTML</a></li>
<li><a href="/courses/html-css/lesson-2">Урок 2: Форматування тексту</a></li>
<li><a href="/courses/html-css/lesson-3">Урок 3: Посилання та зображення</a></li>
<li><a href="/courses/html-css/lesson-4">Урок 4: Списки та таблиці</a></li>
<li><a href="/courses/html-css/lesson-5">Урок 5: Форми</a></li>
<li aria-current="page"><strong>Урок 6: Семантичний HTML</strong> (поточний)</li>
<li><a href="/courses/html-css/lesson-7">Урок 7: Мультимедіа ↗</a></li>
</ol>
</nav>
</section>
<section>
<h2>Ваш прогрес</h2>
<dl>
<dt>Завершено уроків</dt>
<dd>5 з 12</dd>
<dt>Прогрес курсу</dt>
<dd>
<progress value="5" max="12" aria-label="42% курсу завершено">42%</progress>
42%
</dd>
</dl>
</section>
</aside>
</main>
<footer>
<nav aria-label="Підвал сайту">
<ul>
<li><a href="/about">Про платформу</a></li>
<li><a href="/privacy">Конфіденційність</a></li>
<li><a href="/sitemap.xml">Карта сайту</a></li>
<li>
<a href="/rss.xml" type="application/rss+xml">RSS</a>
</li>
</ul>
</nav>
<address>CodeCamp UA: <a href="mailto:hello@codecamp.ua">hello@codecamp.ua</a></address>
<p>
<small>© <time datetime="2024">2024</time> CodeCamp UA</small>
</p>
</footer>
<!-- Template для коментарів -->
<template id="comment-template">
<article class="comment">
<header>
<img data-avatar alt="" width="40" height="40" />
<p><strong data-name></strong> · <time data-time></time></p>
</header>
<p data-text></p>
</article>
</template>
<script defer src="/scripts/course-player.js"></script>
<script defer src="/scripts/canvas-chart.js"></script>
<script>
// Canvas — статистика завершення
window.addEventListener('DOMContentLoaded', () => {
const canvas = document.getElementById('completion-chart')
if (!canvas) return
const ctx = canvas.getContext('2d')
const data = [
{ label: 'Завершили', value: 2340, color: '#10b981' },
{ label: 'Наполовину', value: 890, color: '#f59e0b' },
{ label: 'Почали', value: 430, color: '#6366f1' },
]
const max = Math.max(...data.map((d) => d.value))
data.forEach((item, i) => {
const barH = (item.value / max) * 150
const x = 60 + i * 180
ctx.fillStyle = item.color
ctx.fillRect(x, 180 - barH, 80, barH)
ctx.fillStyle = '#1f2937'
ctx.font = '13px Inter, sans-serif'
ctx.textAlign = 'center'
ctx.fillText(item.label, x + 40, 198)
ctx.fillText(item.value.toLocaleString('uk-UA'), x + 40, 175 - barH)
})
})
</script>
</body>
</html>
Корисні посилання
- 📖 HTML Living Standard:
<video>та<audio> - 📖 HTML Living Standard:
<iframe> - 📖 HTML Living Standard:
<canvas> - 📖 HTML Living Standard: Scripting
- 📖 WebVTT специфікація — формат субтитрів
- 🔧 CanIUse: AV1 — підтримка кодека
- 🔧 WebVTT Validator — перевірка файлів субтитрів
- 🔧 Permissions Policy — генератор
allowдля<iframe> - 🔧 Canvas API MDN
Семантичні елементи HTML5
Повний розбір семантичних елементів HTML5 за специфікацією WHATWG: <article>, <section>, <nav>, <aside>, <header>, <footer>, <main>, <address>, <time>, <details>, <summary>, <dialog> та інші. Різниця між div і семантичними елементами, доступність та ARIA.
Мікророзмітка та SEO в HTML
Open Graph, Microdata, JSON-LD та Schema.org — як зробити сайт зрозумілим для пошукових роботів. Google Rich Results для статей, товарів, відео, подій та FAQ.