Multimedia y Embeds
Aprendé a incorporar video, audio, mapas, videos de YouTube y otros contenidos externos directamente en tu página, usando las herramientas nativas de HTML5 y la etiqueta <iframe>.
Video nativo con <video>
HTML5 introdujo la etiqueta <video> para reproducir videos
directamente en el navegador, sin necesidad de Flash ni plugins externos.
A diferencia de <img>, <video> sí tiene etiqueta de cierre
y puede contener elementos hijos.
El atributo más importante es src, pero lo recomendable es usar
etiquetas <source> internas para ofrecer el mismo video en
distintos formatos — así el navegador elige el primero que puede reproducir.
<video width="640" height="360" controls>
<source src="video.mp4" type="video/mp4">
<source src="video.webm" type="video/webm">
<source src="video.ogv" type="video/ogg">
<!-- Este texto solo aparece si el navegador no soporta <video> -->
Tu navegador no soporta reproducción de video.
</video>
Atributos de control y comportamiento
La etiqueta <video> tiene una serie de atributos que controlan
cómo se comporta el reproductor. Algunos son booleanos — basta con escribirlos,
no necesitan un valor:
| Atributo | Tipo | Qué hace |
|---|---|---|
controls | booleano | Muestra los controles nativos del navegador (play, volumen, barra de progreso) |
autoplay | booleano | Inicia la reproducción automáticamente al cargar. En móviles solo funciona combinado con muted |
muted | booleano | Inicia sin sonido. Requerido para autoplay en la mayoría de los navegadores |
loop | booleano | Repite el video indefinidamente al terminar |
poster | URL | Imagen que se muestra antes de reproducir. Si no se especifica, se muestra el primer fotograma |
preload | none / metadata / auto | Controla cuánto se precarga. metadata carga solo duración y dimensiones sin descargar el video completo |
width / height | número | Dimensiones en píxeles. Siempre definirlas para evitar saltos de layout |
playsinline | booleano | En iOS fuerza la reproducción dentro de la página en vez de pantalla completa |
<!-- Video de fondo: silencioso, automático, en loop -->
<video autoplay muted loop playsinline poster="preview.jpg">
<source src="hero-bg.mp4" type="video/mp4">
</video>
<!-- Video con controles y poster -->
<video controls poster="thumbnail.jpg" preload="metadata"
width="800" height="450">
<source src="tutorial.mp4" type="video/mp4">
<source src="tutorial.webm" type="video/webm">
</video>
MP4 (H.264) es el formato con soporte más amplio — funciona en todos los navegadores modernos. WebM (VP9) tiene mejor compresión y es el preferido en Chrome y Firefox. Ofrecer ambos cubre prácticamente el 100% de los navegadores actuales.
Subtítulos y pistas de texto con <track>
La etiqueta <track> añade subtítulos, descripciones de audio o capítulos
al video. Se escribe dentro de <video> y apunta a un archivo en formato
WebVTT (.vtt), que es un archivo de texto con marcas de tiempo.
<video controls width="800" height="450">
<source src="tutorial.mp4" type="video/mp4">
<!-- subtítulos en español (idioma del video) -->
<track src="subtitulos-es.vtt" kind="subtitles"
srclang="es" label="Español" default>
<!-- subtítulos en inglés -->
<track src="subtitulos-en.vtt" kind="subtitles"
srclang="en" label="English">
<!-- descripción de audio para usuarios ciegos -->
<track src="descripcion.vtt" kind="descriptions"
srclang="es" label="Descripción de audio">
</video>
Un archivo .vtt básico tiene este formato:
WEBVTT
00:00:00.000 --> 00:00:03.500
Bienvenido al tutorial de HTML.
00:00:03.500 --> 00:00:07.000
En este video vas a aprender sobre multimedia.
| Valor de kind | Para qué sirve |
|---|---|
subtitles | Subtítulos del diálogo (para personas que no escuchan el audio) |
captions | Subtítulos cerrados: incluyen efectos de sonido y música además del diálogo |
descriptions | Descripción visual del video para usuarios ciegos |
chapters | Marcadores de capítulos para navegar el video |
metadata | Datos para scripts, no se muestran al usuario |
Las pautas WCAG (Web Content Accessibility Guidelines) requieren subtítulos en todo contenido de video con audio. No es solo una buena práctica — en muchos países es un requisito legal para sitios públicos.
Audio nativo con <audio>
La etiqueta <audio> funciona exactamente igual que
<video> pero sin dimensiones visuales. También acepta
múltiples <source> para compatibilidad entre navegadores,
y la mayoría de sus atributos son los mismos.
<audio controls>
<source src="podcast.mp3" type="audio/mpeg">
<source src="podcast.ogg" type="audio/ogg">
<source src="podcast.wav" type="audio/wav">
Tu navegador no soporta reproducción de audio.
</audio>
<!-- Audio en loop automático (útil para música de fondo) -->
<audio autoplay muted loop>
<source src="ambiente.mp3" type="audio/mpeg">
</audio>
MP3 es el estándar universal — lo reproduce cualquier navegador moderno. OGG (Vorbis) tiene mejor calidad a menor tamaño y es preferido en Firefox. AAC es el estándar de Apple (Safari). Para máxima compatibilidad, ofrecé MP3 como principal y OGG como alternativa.
Embeds con <iframe>
La etiqueta <iframe> (inline frame) incrusta otra página web
dentro de la tuya. Es la forma estándar de integrar videos de YouTube, mapas de
Google, formularios externos, widgets de redes sociales y cualquier otro contenido
de terceros.
A diferencia de <video>, que descarga y reproduce el archivo
en tu página, el <iframe> carga el sitio web externo completo —
con su propio HTML, CSS y JavaScript — dentro de un recuadro. El contenido interno
está completamente aislado del resto de tu página.
Atributos importantes
| Atributo | Qué hace |
|---|---|
src | URL de la página a embeber |
width / height | Dimensiones en píxeles o porcentaje |
title | Descripción del contenido para lectores de pantalla. Obligatorio para accesibilidad |
allowfullscreen | Permite que el contenido interno entre a pantalla completa (necesario para YouTube) |
loading="lazy"` | Carga el iframe solo cuando está cerca del viewport. Mejora el rendimiento |
sandbox | Restringe lo que puede hacer el contenido interno (ver abajo) |
allow | Controla qué APIs del navegador puede usar el contenido (cámara, micrófono, etc.) |
YouTube
YouTube genera automáticamente el código embed para cada video. En el video, hacés clic en "Compartir" → "Insertar" y copiás el iframe. El resultado tiene esta forma:
<iframe
width="560"
height="315"
src="https://www.youtube.com/embed/VIDEO_ID"
title="Título descriptivo del video"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media;
gyroscope; picture-in-picture; web-share"
allowfullscreen
loading="lazy">
</iframe>
El VIDEO_ID es la parte que ves en la URL de YouTube después de
v=. Por ejemplo, en youtube.com/watch?v=dQw4w9WgXcQ
el ID es dQw4w9WgXcQ.
Podés agregar parámetros a la URL del embed para personalizar el comportamiento:
<!-- Empieza desde el segundo 30 -->
src="https://www.youtube.com/embed/VIDEO_ID?start=30"
<!-- Empieza automáticamente (sin sonido por política del navegador) -->
src="https://www.youtube.com/embed/VIDEO_ID?autoplay=1&mute=1"
<!-- Oculta los controles -->
src="https://www.youtube.com/embed/VIDEO_ID?controls=0"
<!-- Sin sugerencias de otros videos al terminar -->
src="https://www.youtube.com/embed/VIDEO_ID?rel=0"
<!-- Combinando varios -->
src="https://www.youtube.com/embed/VIDEO_ID?start=30&rel=0&controls=1"
Google Maps
Para embeber un mapa de Google Maps, buscás el lugar en maps.google.com, hacés clic en "Compartir" → "Insertar un mapa" y copiás el código.
<iframe
src="https://www.google.com/maps/embed?pb=CÓDIGO_GENERADO_POR_GOOGLE"
width="600"
height="450"
style="border: 0;"
allowfullscreen
loading="lazy"
referrerpolicy="no-referrer-when-downgrade"
title="Mapa de nuestra ubicación">
</iframe>
Sin title, los lectores de pantalla no pueden describir el contenido del iframe al usuario. Siempre ponés algo descriptivo: title="Video tutorial de HTML" o title="Mapa con nuestra dirección".
El atributo sandbox — seguridad
Cuando incluís contenido de terceros, podés limitar lo que puede hacer ese
contenido dentro del iframe usando el atributo sandbox. Sin
ningún valor, bloquea casi todo. Podés ir habilitando lo que necesitás:
<!-- Sin sandbox: el contenido puede hacer casi cualquier cosa -->
<iframe src="https://externo.com"></iframe>
<!-- Con sandbox vacío: bloquea scripts, formularios, pop-ups, etc. -->
<iframe src="https://externo.com" sandbox></iframe>
<!-- Habilitando solo lo necesario -->
<iframe src="https://externo.com"
sandbox="allow-scripts allow-same-origin">
</iframe>
| Valor de sandbox | Habilita |
|---|---|
allow-scripts | Ejecución de JavaScript |
allow-forms | Envío de formularios |
allow-same-origin | Acceso a cookies y almacenamiento local |
allow-popups | Abrir ventanas emergentes |
allow-top-navigation | Redirigir la ventana principal (cuidado con esto) |
allow-fullscreen | Modo pantalla completa |
Imágenes responsivas — srcset, sizes y <picture>
Una imagen fija de 1200px de ancho se descarga completa incluso en un celular con pantalla de 375px — desperdicia datos y ralentiza la página. HTML5 ofrece herramientas para servir la imagen correcta según el dispositivo.
srcset — múltiples resoluciones
El atributo srcset le ofrece al navegador varias versiones de la
misma imagen. El navegador elige cuál descargar según el tamaño de pantalla y la
densidad de píxeles del dispositivo. Vos solo las ofrecés — la decisión final es
del navegador.
<!-- Con descriptores de anchura (w) -->
<img
src="imagen-800.jpg"
srcset="imagen-400.jpg 400w,
imagen-800.jpg 800w,
imagen-1200.jpg 1200w"
sizes="(max-width: 600px) 100vw,
(max-width: 1200px) 50vw,
800px"
alt="Descripción de la imagen"
>
El atributo sizes le dice al navegador qué tan grande va a aparecer
la imagen en pantalla para cada condición. Es necesario para que pueda calcular
cuál versión de srcset descargar antes de que el CSS se haya cargado.
(max-width: 600px) 100vw significa "si la pantalla tiene menos de 600px,
la imagen ocupa el 100% del viewport".
<picture> — control total del arte
Cuando no solo querés cambiar el tamaño sino también el recorte o el formato
de la imagen según el dispositivo, usás <picture>.
Es especialmente útil para imágenes de hero que se ven distintas en mobile
y desktop, o para servir WebP a los navegadores que lo soportan con un
fallback a JPG.
<picture>
<!-- Navegadores que soportan WebP —mejor compresión -->
<source srcset="imagen.webp" type="image/webp">
<!-- Navegadores que soportan AVIF —compresión aún mejor -->
<source srcset="imagen.avif" type="image/avif">
<!-- Fallback para cualquier navegador -->
<img src="imagen.jpg" alt="Descripción de la imagen">
</picture>
<!-- Arte adaptado: imagen recortada diferente según tamaño -->
<picture>
<!-- En pantallas anchas: imagen horizontal con contexto -->
<source media="(min-width: 800px)" srcset="hero-desktop.jpg">
<!-- En pantallas angostas: recorte vertical centrado en el sujeto -->
<source media="(max-width: 799px)" srcset="hero-mobile.jpg">
<!-- Siempre incluir <img> como fallback dentro de <picture> -->
<img src="hero-desktop.jpg" alt="Equipo de trabajo en la oficina">
</picture>
Usá srcset con sizes cuando la imagen es la misma pero en distintos tamaños. Usá <picture> cuando necesitás cambiar el recorte (art direction) o servir formatos modernos con fallback.
Canvas — dibujo con JavaScript
La etiqueta <canvas> define un área de dibujo en la página.
Por sí sola no hace nada — es solo un lienzo en blanco. Todo el contenido
se dibuja con JavaScript usando la Canvas API.
A diferencia de SVG (que trabaja con formas vectoriales y nodos del DOM), Canvas trabaja a nivel de píxeles: cada vez que dibujás algo, los píxeles cambian y no hay ningún objeto que puedas seleccionar ni modificar después. Es ideal para animaciones, juegos, visualizaciones de datos en tiempo real y edición de imágenes.
<!-- El canvas en HTML es solo el contenedor -->
<canvas id="miCanvas" width="400" height="200">
<!-- Fallback para navegadores sin soporte (muy raro hoy en día) -->
Tu navegador no soporta Canvas.
</canvas>
// Todo el dibujo ocurre en JavaScript
const canvas = document.getElementById("miCanvas");
const ctx = canvas.getContext("2d"); // contexto de renderizado
// Rectángulo relleno
ctx.fillStyle = "#264DE4";
ctx.fillRect(10, 10, 150, 80);
// Rectángulo solo con borde
ctx.strokeStyle = "#E34F26";
ctx.lineWidth = 3;
ctx.strokeRect(200, 10, 150, 80);
// Texto
ctx.fillStyle = "#333";
ctx.font = "24px Arial";
ctx.fillText("Hola Canvas", 10, 150);
// Círculo
ctx.beginPath();
ctx.arc(100, 100, 50, 0, Math.PI * 2);
ctx.fillStyle = "#F7DF1E";
ctx.fill();
ctx.strokeStyle = "#333";
ctx.stroke();
Si definís el tamaño del canvas solo con CSS, estás escalando el lienzo — el canvas interno sigue siendo 300×150px (el valor por defecto) y las imágenes quedan distorsionadas o pixeladas. Siempre definí width y height como atributos HTML.
Buenas Prácticas
- Siempre ofrecé múltiples formatos de video: MP4 como principal, WebM como alternativa para mejor compresión en Chrome y Firefox
- Subtítulos en todo video con audio: es un requisito de accesibilidad, no un extra — usá archivos
.vttcon<track kind="subtitles"> - Autoplay con muted siempre: los navegadores bloquean el autoplay con sonido — si necesitás reproducción automática, combinala siempre con
muted - loading="lazy" en iframes: especialmente en videos de YouTube, donde el script del embed es pesado — diferir la carga hasta que el usuario se acerque mejora mucho el rendimiento inicial
- title en todo iframe: sin
titlelos lectores de pantalla no pueden describir el contenido al usuario - No hostees videos propios sin CDN: servir video desde tu propio servidor consume mucho ancho de banda. Para videos propios, usá Cloudflare Stream, Vimeo o Mux; para videos de YouTube simplemente embebelos
- srcset para imágenes grandes: cualquier imagen que ocupe más de 200px de ancho debería tener al menos dos versiones: una para mobile y una para desktop
- WebP sobre JPG cuando sea posible: WebP da calidad equivalente con un 25-35% menos de tamaño. Usá
<picture>para servir WebP con fallback a JPG - sandbox en iframes de terceros: si no tenés control sobre el contenido que embebés, limitalo con
sandboxpara reducir el riesgo de seguridad