WebP animado combina la compresión superior de WebP con soporte de animación, ofreciendo archivos un 30–80 % más pequeños que GIF equivalente con mejor calidad. Es el formato ideal para reemplazar GIFs en la web moderna.
WebP animado vs GIF vs AVIF animado
| Característica | GIF | WebP animado | AVIF animado |
|---|---|---|---|
| Colores máximos | 256 | Millones | Millones |
| Transparencia | 1 bit (on/off) | Alfa canal completo | Alfa canal completo |
| Compresión | Mala | Muy buena | Excelente |
| Soporte navegadores | 100 % | 96 % | 80 % |
| Soporte en emails | Sí | Limitado | No |
| Tamaño vs GIF | 100 % | 30–60 % | 20–50 % |
Recomendación: usa WebP animado para web (sustitución directa de GIF) con fallback GIF para email.
Soporte de navegadores (2024)
Chrome 32+ ✅ nativo
Firefox 65+ ✅ nativo
Safari 14+ ✅ nativo (macOS Big Sur / iOS 14)
Edge 18+ ✅ nativo
96 % de cobertura — seguro para producción sin fallback en casi todos los casos.
GIF → WebP animado con FFmpeg
# Conversión básica
ffmpeg -i animacion.gif animacion.webp
# Con control de calidad (0-100, 75 = defecto, 90+ = alta calidad)
ffmpeg -i animacion.gif -quality 85 animacion.webp
# Con loop específico (0 = bucle infinito, N = repetir N veces)
ffmpeg -i animacion.gif -loop 0 animacion.webp
# Redimensionar mientras se convierte
ffmpeg -i animacion.gif -vf "scale=400:-1" -quality 80 animacion_400.webp
# Ver información del GIF original
ffprobe -v quiet -print_format json -show_streams animacion.gif
Vídeo → WebP animado con FFmpeg
# MP4/WebM → WebP animado (recortar primeros 5 segundos)
ffmpeg -i video.mp4 -t 5 -vf "fps=15,scale=480:-1" -quality 80 clip.webp
# Con framerate específico (menos frames = archivo más pequeño)
ffmpeg -i video.mp4 -t 3 -vf "fps=10,scale=320:-1" -quality 75 clip_small.webp
# Extraer segmento específico (del segundo 10 al 15)
ffmpeg -ss 10 -i video.mp4 -t 5 -vf "fps=12,scale=400:-1" -quality 80 segmento.webp
# Conversión sin loop (reproducir una sola vez)
ffmpeg -i video.mp4 -t 3 -loop 1 -vf "fps=15" -quality 85 sinloop.webp
Crear WebP animado con Pillow (Python)
Pillow soporta WebP animado desde la versión 9.1:
from PIL import Image
# Abrir GIF y convertir a WebP animado
def gif_a_webp_pillow(gif_path, webp_path, calidad=80):
with Image.open(gif_path) as gif:
frames = []
duraciones = []
try:
while True:
frames.append(gif.copy().convert('RGBA'))
duraciones.append(gif.info.get('duration', 100))
gif.seek(gif.tell() + 1)
except EOFError:
pass
if frames:
frames[0].save(
webp_path,
format='WEBP',
save_all=True,
append_images=frames[1:],
duration=duraciones,
loop=0,
quality=calidad,
method=6, # 0=rápido, 6=mejor compresión
)
print(f"WebP animado: {webp_path} ({len(frames)} frames)")
gif_a_webp_pillow('animacion.gif', 'animacion.webp', calidad=82)
Crear WebP animado desde frames individuales
from PIL import Image
from pathlib import Path
def frames_a_webp(directorio_frames, webp_salida, fps=12, calidad=80):
"""Crea WebP animado desde un directorio de imágenes PNG/JPG."""
directorio = Path(directorio_frames)
extensiones = {'.png', '.jpg', '.jpeg', '.webp'}
rutas = sorted(f for f in directorio.iterdir() if f.suffix.lower() in extensiones)
if not rutas:
raise ValueError("No se encontraron imágenes en el directorio")
duracion_por_frame = int(1000 / fps) # ms por frame
frames = [Image.open(r).convert('RGBA') for r in rutas]
frames[0].save(
webp_salida,
format='WEBP',
save_all=True,
append_images=frames[1:],
duration=duracion_por_frame,
loop=0,
quality=calidad,
)
print(f"WebP: {webp_salida} ({len(frames)} frames, {fps} fps)")
frames_a_webp('frames/', 'animacion_custom.webp', fps=15, calidad=85)
Leer y extraer frames de un WebP animado
from PIL import Image
def extraer_frames_webp(webp_path, directorio_salida='.'):
"""Extrae todos los frames de un WebP animado."""
from pathlib import Path
Path(directorio_salida).mkdir(exist_ok=True)
with Image.open(webp_path) as webp:
n_frames = getattr(webp, 'n_frames', 1)
print(f"Frames en {webp_path}: {n_frames}")
print(f"Loop count: {webp.info.get('loop', 0)}")
for i in range(n_frames):
webp.seek(i)
duracion = webp.info.get('duration', 100)
frame = webp.copy()
frame.save(f"{directorio_salida}/frame_{i:04d}.png")
print(f" Frame {i}: {duracion}ms")
extraer_frames_webp('animacion.webp', 'frames_extraidos/')
Comparar tamaños: GIF vs WebP animado
import os
import subprocess
from pathlib import Path
def comparar_gif_webp(gif_path):
"""Convierte GIF a WebP y compara tamaños."""
gif = Path(gif_path)
webp = gif.with_suffix('.webp')
# Convertir con FFmpeg
resultado = subprocess.run(
['ffmpeg', '-i', str(gif), '-quality', '80', str(webp), '-y'],
capture_output=True
)
if resultado.returncode == 0:
tam_gif = os.path.getsize(gif)
tam_webp = os.path.getsize(webp)
ahorro = (1 - tam_webp / tam_gif) * 100
print(f"GIF: {tam_gif:,} bytes ({tam_gif//1024} KB)")
print(f"WebP: {tam_webp:,} bytes ({tam_webp//1024} KB)")
print(f"Ahorro: {ahorro:.1f}%")
else:
print("Error al convertir")
comparar_gif_webp('logo_animado.gif')
HTML con fallback GIF
<!-- WebP animado con fallback a GIF -->
<picture>
<source srcset="animacion.webp" type="image/webp">
<img src="animacion.gif" alt="Animación" width="400" height="300">
</picture>
<!-- Usando object-fit para responsive -->
<picture>
<source srcset="hero.webp" type="image/webp">
<img src="hero.gif" alt="Hero animado"
style="width:100%; max-width:800px; height:auto;">
</picture>
CSS: usar WebP animado como fondo
/* Fondo animado con fallback */
.hero {
background-image: url('fondo.gif'); /* fallback */
}
/* Con soporte WebP detectado vía JS */
.webp .hero {
background-image: url('fondo.webp');
}
Cuándo usar WebP animado
Sí usa WebP animado:
- Animaciones en sitios web (sustitución directa de GIF)
- Avatares, stickers, iconos animados
- Demos de producto o micro-interacciones
Prefiere GIF cuando:
- El contenido se comparte por email (soporte limitado de WebP en clientes de correo)
- Necesitas compatibilidad universal absoluta (100 % cobertura)
Conversiones relacionadas
Lo más habitual al trabajar con imágenes son estas direcciones de conversión: