Multimedia & Gráficos
La web moderna es mucho más que texto y links. Video, audio, imágenes adaptativas, gráficos generados dinámicamente y gráficos vectoriales son parte fundamental de la experiencia web. HTML5 trajo etiquetas nativas para todo esto, eliminando la dependencia de plugins como Flash que dominaban la web a principios de los 2000. Hoy, multimedia es nativo, accesible y performántico.
<video> — Video nativo
La etiqueta <video> permite incrustar video directamente en tu página sin plugins. Antes de HTML5, la única forma de reproducir video era con Flash (<embed>), lo que significaba que los usuarios de iPhone y iPad (que no soportaban Flash) simplemente no podían ver el video. Hoy, <video> funciona en todos los dispositivos y navegadores de forma nativa. Soporta múltiples formatos a través de <source> y tiene atributos de control granular sobre la reproducción.
Los atributos clave son: controls muestra los controles de reproducción nativos (play, pause, volumen, barra de progreso, fullscreen), autoplay reproduce automáticamente (con restricciones: la mayoría de navegadores bloquean autoplay con audio, así que necesitas agregar muted para que funcione), loop repite el video indefinidamente, poster muestra una imagen de portada antes de reproducir, y preload controla cuánto del video se descarga antes de que el usuario dé play.
<!-- Video basico con controles -->
<video src="presentacion.mp4"
controls
poster="portada-video.jpg"
width="1280" height="720">
Tu navegador no soporta video HTML5.
</video>
<!-- Video con multiples formatos (mejor compatibilidad) -->
<video controls preload="metadata" width="1280" height="720">
<source src="video.mp4" type="video/mp4">
<source src="video.webm" type="video/webm">
<source src="video.ogg" type="video/ogg">
<p>Tu navegador no soporta video HTML5.
<a href="video.mp4">Descargar el video</a>.</p>
</video>
<!-- Video de fondo (autoplay, muted, loop, sin controles) -->
<video autoplay muted loop playsinline
poster="bg-poster.jpg">
<source src="fondo.mp4" type="video/mp4">
</video>
<!-- Video con subtítulos -->
<video controls>
<source src="tutorial.mp4" type="video/mp4">
<track kind="subtitles" src="subs/es.vtt" srclang="es"
label="Español" default>
<track kind="subtitles" src="subs/en.vtt" srclang="en"
label="English">
</video>
| Atributo | Función | Nota |
|---|---|---|
controls |
Muestra controles de reproducción | Siempre agregar para contenido que el usuario controla |
autoplay |
Reproducción automática | Mayoría de navegadores lo bloquean sin muted |
muted |
Silencia el video | Permite autoplay + crea backgrounds visuales |
loop |
Repetir indefinidamente | Ideal para fondos o animaciones cortas |
playsinline |
Reproduce dentro del layout (no fullscreen en iOS) | Casi obligatorio para autoplay en móvil |
poster |
Imagen de portada antes de reproducir | Mejora UX: el usuario ve qué hay antes de darle play |
preload |
none | metadata | auto | metadata es el balance ideal entre velocidad y UX |
width / height |
Tamaño del reproductor | Siempre especificar para evitar reflow al cargar |
Autoplay está fuertemente restringido
Los navegadores modernos (Chrome, Firefox, Safari) bloquean autoplay con audio. La combinación autoplay muted playsinline es la única que funciona confiablemente. Para video que el usuario elige ver, usa controls sin autoplay. Para fondos visuales (hero sections), usa autoplay muted. Nunca fuerces autoplay con sonido porque genera una experiencia negativa y los navegadores lo bloquean de todas formas.
<audio> — Audio nativo
<audio> funciona igual que <video> pero sin la visualización de imagen. Es la forma nativa de incrustar sonido: podcasts, música, efectos de sonido, o cualquier contenido de audio. Comparte los mismos atributos de <video> (controls, autoplay, loop, preload, muted) y también usa <source> para múltiples formatos. La diferencia principal es que <audio> no tiene atributos de dimensiones visuales ni poster.
Los formatos de audio más comunes son MP3 (compatibilidad universal, menor calidad a igual bitrate), Ogg Vorbis (open source, buena calidad) y AAC (mejor calidad que MP3 a igual bitrate, estándar en MPEG-4). Para la mayoría de los casos, ofrecer MP3 y Ogg es suficiente para cubrir todos los navegadores. En producción, es aún más común alojar audio en plataformas como Spotify, SoundCloud o YouTube y embeber con un <iframe> en lugar de autoalojar los archivos.
<!-- Audio basico -->
<audio controls>
<source src="podcast.mp3" type="audio/mpeg">
<source src="podcast.ogg" type="audio/ogg">
Tu navegador no soporta audio HTML5.
</audio>
<!-- Audio con autoplay (muted para que funcione) -->
<audio autoplay muted loop>
<source src="ambiental.mp3" type="audio/mpeg">
</audio>
Audio streaming vs autoalojado
Autoalojar audio (<audio> directo) es útil para clips cortos o efectos de sonido. Para contenido largo (podcasts, música), es mejor usar plataformas de streaming (Spotify Embeds, SoundCloud, YouTube) y embeberlas con un <iframe>. Así evitas consumir ancho de banda de tu servidor y obtienes controles más ricos (playlists, compartibilidad, métricas).
<picture> — Imágenes adaptativas
<picture> es la etiqueta que resuelve uno de los problemas más importantes del desarrollo web: servir la imagen correcta según el contexto del usuario. No es solo resoluciones diferentes (una foto más grande para una pantalla más grande), sino también art direction: imágenes distintas en recorte y composición para distintos breakpoints. Piensa en un hero de una página: en desktop querés una foto panorámica horizontal, en mobile querés un recorte vertical que enfoque en el sujeto. <picture> te permite hacer exactamente eso.
Dentro de <picture> usas <source> con el atributo media para definir qué imagen mostrar en qué condición (igual que media queries en CSS), y una <img> al final como fallback y como la imagen que se muestra si ninguna condición coincide. El <img> es obligatorio: es lo que ven los navegadores que no soportan <picture> (prácticamente ninguno hoy, pero sigue siendo la especificación).
<!-- Art direction: imagen distinta por breakpoint -->
<picture>
<!-- Pantallas grandes: panoramica horizontal -->
<source media="(min-width: 1024px)"
srcset="hero-wide.webp" type="image/webp">
<!-- Pantallas medianas: recorte cuadrado -->
<source media="(min-width: 768px)"
srcset="hero-medium.webp" type="image/webp">
<!-- Mobile: recorte vertical del sujeto -->
<source media="(min-width: 320px)"
srcset="hero-mobile.webp" type="image/webp">
<!-- Fallback: imagen default -->
<img src="hero-default.webp"
alt="Persona trabajando en un proyecto web">
</picture>
<!-- srcset + sizes: diferentes resoluciones del mismo recorte -->
<img src="foto-400.webp"
srcset="foto-400.webp 400w,
foto-800.webp 800w,
foto-1200.webp 1200w,
foto-1600.webp 1600w"
sizes="(max-width: 767px) 100vw,
(max-width: 1024px) 50vw,
33vw"
alt="Captura de pantalla del proyecto">
Formatos modernos de imagen
Los formatos WebP y AVIF son el estándar moderno que reemplaza a JPEG y PNG. WebP ofrece entre un 25-35% menos de peso que JPEG con calidad equivalente, y también soporta transparencia (alpha) como PNG. AVIF va un paso más allá: puede ser hasta un 50% más pequeño que JPEG con calidad superior, y soporta animaciones, transparencia y profundidad de color HDR. La estrategia recomendada es servir AVIF cuando es posible, con WebP como fallback, y JPEG/PNG como fallback final.
| Formato | Ventaja | Soporte | Cuándo usarlo |
|---|---|---|---|
| AVIF | Menor tamaño, mejor calidad, HDR | Chrome, Firefox, Edge, Safari 16.4+ | Fotos de alta calidad, HDR |
| WebP | Menor tamaño que JPEG, soporta alpha | Todos los navegadores modernos | Uso general, reemplaza JPEG y PNG |
| JPEG | Compatibilidad universal | 100% | Fallback máximo |
| PNG | Transparencia (alpha), sin pérdida | 100% | Iconos, screenshots, logos con alpha |
| SVG | Vectorial, escalable, liviano | 100% | Logos, iconos, ilustraciones simples |
srcset + sizes: el navegador elige
Con srcset le das al navegador una lista de imágenes con sus anchos (400w, 800w) y con sizes le dices cuánto espacio va a ocupar la imagen en cada breakpoint (100vw, 50vw). El navegador calcula automáticamente cuál descargar basándose en el ancho de la pantalla y la densidad de pixeles del dispositivo. Es más eficiente que media queries porque el navegador sabe cosas que CSS no: conexión del usuario, memoria disponible y densidad del display.
<canvas> — Gráficos dinámicos
<canvas> es un lienzo en blanco donde dibujás gráficos mediante JavaScript usando la Canvas 2D API (o WebGL para gráficos 3D). A diferencia de SVG, el contenido del canvas es pixel-based (rasterizado), no vectorial. Una vez que dibujas algo, se convierte en píxeles y no podés manipular elementos individuales como en SVG. Canvas es ideal para gráficos de alta frecuencia (animaciones de videojuegos, visualizaciones de datos en tiempo real, procesamiento de imágenes) donde el rendimiento es prioritario.
Los pasos básicos son: obtener el contexto 2D con canvas.getContext('2d'), definir coordenadas (0,0 es la esquina superior izquierda), y usar los métodos de dibujo como fillRect(), arc(), fillText(), drawImage(), y beginPath() para formas personalizadas. Los atributos width y height del <canvas> definen la resolución del lienzo en píxeles (no confundir con el tamaño CSS, que solo escala visualmente).
// Obtener el canvas y su contexto
const canvas = document.getElementById('mi-canvas');
const ctx = canvas.getContext('2d');
// Rectangulo relleno: fillRect(x, y, ancho, alto)
ctx.fillStyle = '#58a6ff';
ctx.fillRect(20, 20, 150, 100);
// Rectangulo con borde: strokeRect(x, y, ancho, alto)
ctx.strokeStyle = '#39d2c0';
ctx.lineWidth = 3;
ctx.strokeRect(50, 50, 150, 100);
// Circulo: arc(x, y, radio, startAngle, endAngle)
ctx.beginPath();
ctx.arc(300, 100, 50, 0, Math.PI * 2);
ctx.fillStyle = '#ff6b6b';
ctx.fill();
// Texto
ctx.font = '24px Space Grotesk';
ctx.fillStyle = '#e6edf3';
ctx.fillText('WebForge', 20, 200);
// Limpiar el canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
Canvas
Pixel-based, renderizado rápido. Ideal para animaciones de alta frecuencia, juegos, procesamiento de imágenes. No accesible para lectores de pantalla (no hay elementos DOM dentro del canvas).
SVG
Vector-based, escalable infinitamente. Ideal para logos, iconos, ilustraciones, gráficos interactivos. Accesible (cada forma es un elemento DOM que los lectores pueden navegar).
width/height del canvas NO es lo mismo que CSS
Los atributos width y height del <canvas> definen la resolución del lienzo (cuántos píxeles tiene para dibujar). Si CSS escala el canvas a un tamaño diferente, el contenido se estira o se comprime. Para pantallas de alta densidad (Retina), es común duplicar la resolución del canvas y escalarlo con CSS a la mitad para mantener nitidez: canvas.width = 800 + CSS width: 400px.
<svg> — Gráficos vectoriales
SVG (Scalable Vector Graphics) es un formato de imagen vectorial basado en XML. A diferencia de PNG o JPEG que están compuestos por píxeles, los gráficos SVG están compuestos por formas matemáticas (puntos, líneas, curvas, rectángulos). Esto significa que escalan a cualquier tamaño sin perder calidad, pesan muchísimo menos que un PNG equivalente (especialmente para iconos), se pueden manipular con CSS y JavaScript, y son accesibles porque cada forma es un elemento del DOM.
La forma más común de usar SVG en la web es como <img src="icono.svg">, pero esto no permite manipular los estilos internos del SVG. La alternativa más poderosa es SVG inline: pegar el código SVG directamente en el HTML. Esto te permite cambiar colores con CSS, animar partes del SVG con JavaScript, agregar clases a elementos internos, y es lo que hacemos en WebForge con los iconos Lucide. El atributo viewBox es fundamental: define el sistema de coordenadas interno del SVG y permite que escale sin deformarse.
<!-- SVG inline: icono editable con CSS -->
<svg xmlns="http://www.w3.org/2000/svg"
width="24" height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round">
<circle cx="12" cy="12" r="10"/>
<path d="M12 16v-4"/>
<path d="M12 8h.01"/>
</svg>
<!-- SVG como imagen (no editable con CSS) -->
<img src="logo.svg" alt="Logo del sitio" width="120">
<!-- SVG con formas básicas -->
<svg width="200" height="200" viewBox="0 0 200 200">
<!-- Rectangulo -->
<rect x="10" y="10" width="80" height="60"
rx="8" fill="#58a6ff"/>
<!-- Circulo -->
<circle cx="150" cy="40" r="30" fill="#39d2c0"/>
<!-- Linea -->
<line x1="10" y1="120" x2="190" y2="120"
stroke="#ff6b6b" stroke-width="3"/>
<!-- Path personalizado -->
<path d="M100 150 L130 190 L70 190 Z"
fill="#bc8cff"/>
<!-- Texto dentro del SVG -->
<text x="100" y="195"
text-anchor="middle" fill="#e6edf3"
font-size="12">WebForge</text>
</svg>
Formas básicas de SVG
| Elemento | Qué dibuja | Atributos clave |
|---|---|---|
<rect> |
Rectángulo | x, y, width, height, rx, ry |
<circle> |
Círculo | cx, cy, r |
<ellipse> |
Elipse | cx, cy, rx, ry |
<line> |
Línea recta | x1, y1, x2, y2 |
<polyline> |
Línea con múltiples puntos | points="x1,y1 x2,y2 ..." |
<polygon> |
Polígono cerrado | points="x1,y1 x2,y2 ..." |
<path> |
Forma libre | d="M L C Z ..." (comandos de dibujo) |
viewBox: el secreto de SVG
El atributo viewBox="0 0 24 24" define el sistema de coordenadas interno del SVG (origen en 0,0, ancho 24, alto 24). Permite que el SVG escale a cualquier tama&ntute;o manteniendo las proporciones, sin importar el width y height que le des en CSS o en los atributos. Es análogo a decirle al SVG: "todo lo que dibujes, ajustalo automáticamente al tamaño del contenedor". Siempre inclúyelo.
<iframe> — Contenido embebido
<iframe> (inline frame) embebe otra página HTML dentro de la tuya. Es la forma estándar de integrar contenido externo: videos de YouTube, mapas de Google Maps, widgets de Twitter, codepens interactivos, o cualquier contenido que venga de otro dominio. El iframe crea un contexto de navegación independiente: su propio documento HTML, sus propios estilos, su propio JavaScript. Es como una "ventana" dentro de tu página que muestra otra página completa.
Sin embargo, los iframes tienen implicaciones importantes. Consumen recursos (cada iframe es como una pestaña adicional del navegador), pueden afectar la performance de tu página, y tienen restricciones de seguridad (Same-Origin Policy) que impiden que tu página interactúe con el contenido del iframe si viene de otro dominio. El atributo loading="lazy" es fundamental: retrasa la carga del iframe hasta que esté cerca del viewport, ahorrando ancho de banda. El atributo sandbox restringe lo que el iframe puede hacer (ejecutar scripts, enviar formularios, navegar), mejorando la seguridad.
<!-- YouTube embebido con aspect-ratio responsivo -->
<div style="position: relative; padding-bottom: 56.25%;
height: 0; overflow: hidden;">
<iframe src="https://www.youtube.com/embed/dQw4w9WgXcQ"
title="Video tutorial de HTML"
style="position: absolute; top: 0; left: 0;
width: 100%; height: 100%;"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write;
encrypted-media; gyroscope; picture-in-picture"
allowfullscreen
loading="lazy">
</iframe>
</div>
<!-- Google Maps embebido -->
<iframe src="https://www.google.com/maps/embed?pb=..."
title="Ubicación de la oficina"
width="600" height="450"
style="border:0;"
allowfullscreen
loading="lazy"
referrerpolicy="no-referrer-when-downgrade">
</iframe>
<!-- CodePen embebido -->
<iframe src="https://codepen.io/usuario/embed/penId?default-tab=html"
title="Ejemplo de CSS Grid"
loading="lazy"
sandbox="allow-scripts"
style="width:100%; height:300px;">
</iframe>
Siempre usa title en iframes
El atributo title en <iframe> es obligatorio para la accesibilidad. Los lectores de pantalla lo anuncian para que el usuario sepa qué contiene el iframe antes de entrar en él. Sin un title descriptivo, el lector solo dice "frame" o "iframe" sin contexto, dejando al usuario a ciegas sobre el contenido embebido. También evita usar iframes para contenido principal de tu página: los usuarios no pueden buscar dentro de un iframe con Ctrl+F del navegador, ni bookmark el contenido interno.
Probá en MiniDevTools
Si querés experimentar con lo que vimos en esta sección, probá Image Cropper, Image Resizer, Image to Base64, Favicon Generator o Image to Pixel Art.