Favicons animados en la práctica: cómo mover la pestaña del navegador (con demo en vivo)
Mientras lees este artículo seguramente notaste algo moviéndose en lo alto de esta pestaña. Eso es un favicon animado: el mismo truco que usa Gmail para los contadores de correo nuevo y Discord para sus puntos de notificación, sólo que el tuyo puede hacer básicamente cualquier cosa que puedas dibujar en un canvas.
Este artículo incluye una demo con la que puedes jugar. Pulsa un botón y mira cómo cambia la pestaña real del navegador. Sin capturas, sin vídeos embebidos: el favicon que estás viendo ahora mismo es la propia demo.
¿Por qué animar un favicon?
Siendo honestos, la mayoría de sitios no deberían. Un icono girando en cada pestaña cansa rápido y consume CPU. Pero hay un puñado de casos en los que sí merece la pena:
- Estados de carga o procesado. Subidas largas, exportaciones, builds. Los usuarios cambian de pestaña mientras esperan, y un favicon animado les dice que el trabajo sigue en marcha.
- Distintivos de notificación. Mensajes nuevos, menciones, alertas. Un punto rojo que late con suavidad llama la atención antes que uno estático.
- Datos en vivo. Cuadros de mando de trading, herramientas de monitorización, marcadores deportivos: cuando el título de la pestaña no basta.
- Momentos de marca. Un giro festivo, una celebración del día del lanzamiento. Con moderación.
Si tu caso no encaja en ninguno de estos, evita la animación. Un buen favicon SVG estático ya gana en tamaño de archivo, modo oscuro y consumo de batería.
Demo en vivo: pruébalo ahora mismo
Elige una animación. Después mira la pestaña del navegador: ese icono diminuto de arriba es lo que se está redibujando.
El favicon real mide 16×16 píxeles. A ese tamaño cuesta ver detalles, así que el cuadro de la izquierda muestra el mismo canvas a 8× con escalado de vecino más cercano.
Estado: en reposo
Todo el bucle de animación corre ahora dentro de un Web Worker, igual que en favicon_worker.js de la librería Aymkdn. Cada 20ms (50fps) el worker dibuja sobre su OffscreenCanvas, exporta el resultado con convertToBlob + FileReader y envía el data URL de vuelta a la página. El hilo principal sólo hace una cosa: asignar esa cadena a faviconLink.href. Por eso el icono ahora se mueve tan suave como en la demo de GitHub.
¿Quieres ver este patrón funcionando en un producto real? Random Picker Wheel usa un favicon animado que refleja su ruleta giratoria — una interfaz basada en la rotación es uno de los pocos casos en los que un icono en movimiento encaja de verdad con el producto. Abre la página, gira la ruleta y mira cómo el icono de la pestaña gira junto con ella.
Cómo funciona en realidad
Tres pasos. Esa es la técnica entera:
// 1. Obtener o crear el elemento link del favicon
let link = document.querySelector('link[rel~="icon"]');
if (!link) {
link = document.createElement('link');
link.rel = 'icon';
document.head.appendChild(link);
}
// 2. Dibujar un frame en un canvas oculto
const canvas = document.createElement('canvas');
canvas.width = 32;
canvas.height = 32;
const ctx = canvas.getContext('2d');
function drawFrame(t) {
const scale = 0.5 + 0.5 * Math.abs(Math.sin(t / 400));
ctx.clearRect(0, 0, 32, 32);
ctx.fillStyle = '#ef4444';
ctx.beginPath();
ctx.arc(16, 16, 14 * scale, 0, Math.PI * 2);
ctx.fill();
// 3. Exportar el canvas a data URL y asignarlo al favicon
link.href = canvas.toDataURL('image/png');
requestAnimationFrame(drawFrame);
}
requestAnimationFrame(drawFrame);
Unas 15 líneas para tener un punto rojo que late. Todo lo más vistoso es sólo dibujar formas distintas en el canvas.
La realidad de la compatibilidad entre navegadores
Aquí la cosa se pone fea. Los navegadores varían bastante en lo agresivos que son al animar el favicon:
- Firefox: lo anima con suavidad incluso con la pestaña en segundo plano. Es el listón.
- Chrome / Edge: animan mientras la pestaña está activa. Al cambiar a otra,
requestAnimationFramese limita a aproximadamente una vez por segundo, así que la animación se ralentiza o pausa. - Safari: anima mientras está en primer plano, pero a veces sólo actualiza el icono a intervalos largos. No esperes movimiento fluido.
En realidad esto no es problema para los usos habituales —puntos de notificación y estados de progreso— porque tampoco necesitan refrescarse varias veces por segundo. Los spinners suaves a 60fps son sobre todo decorativos.
El truco del Web Worker (para pestañas en segundo plano)
El botón "Volteo estilo GitHub" de arriba es una traducción directa de la animación insignia de la librería Aymkdn/animated-favicon: mantén el icono A 3 segundos, comprime su anchura con un coseno hasta cero, cambia al icono B y vuelve a expandirla. Las matemáticas vienen tal cual del favicon_worker.js de la librería: width = canvas.width * Math.abs(Math.cos(progress * Math.PI)), con la segunda imagen tomando el relevo cuando progress cruza 0.5.
La librería de Aymkdn da un paso más: ejecuta ese bucle dentro de un Web Worker. Los workers no se ralentizan cuando la pestaña está en segundo plano, así que la animación continúa, y OffscreenCanvas permite al worker dibujar sin tocar el DOM.
El patrón se ve más o menos así:
// En tu página
const worker = new Worker('favicon-worker.js');
worker.onmessage = (e) => {
if (e.data.type === 'updateFavicon') {
document.querySelector('link[rel~="icon"]').href = e.data.dataUrl;
}
};
worker.postMessage({ type: 'init', images: ['icon-a.png', 'icon-b.png'] });
// En favicon-worker.js
const canvas = new OffscreenCanvas(16, 16);
const ctx = canvas.getContext('2d');
// ...dibujar un frame...
const blob = await canvas.convertToBlob();
const reader = new FileReader();
reader.onloadend = () => self.postMessage({ type: 'updateFavicon', dataUrl: reader.result });
reader.readAsDataURL(blob);
Vale la pena si tu app es del tipo que la gente deja abierta en una pestaña secundaria —clientes de chat, paneles de build, herramientas de monitorización—. En el resto de casos la versión en hilo principal es más simple y cumple.
Algunas cosas que conviene saber
Usa 16×16 o 32×32, nada más grande. El favicon se renderiza pequeño de todas formas, y un canvas mayor implica data URLs más grandes y más CPU por frame. 32×32 con píxeles nítidos es el punto dulce.
Asigna el favicon como PNG, no como ICO. Lo único que funciona de forma fiable es canvas.toDataURL('image/png'). No intentes codificar ICO a mano.
Restaura el favicon original cuando pares. Guarda link.href antes de empezar a animar y restaúralo en beforeunload o cuando termine la operación. Las pestañas con animaciones a medio romper tras navegar parecen rotas.
No animes para siempre. Incluso un latido sutil consume batería en móvil. Detén la animación cuando termine el estado de carga, cuando el usuario lea la notificación o cuando la pestaña pierda el foco.
Sáltatelo en casos sencillos. Si sólo quieres mostrar "1 mensaje sin leer", cambia el favicon por una versión estática con un punto rojo. Sin animación. La mayoría de usos de favicons animados son exagerados.
Cuándo recurrir a esto
Los favicons animados encajan cuando:
- La animación refleja un estado real que al usuario le importa (subiendo, procesando, mensaje nuevo)
- La página es de las que viven en una pestaña en segundo plano
- Un distintivo estático o sólo cambiar el título de la pestaña no comunicaría lo mismo
No encajan cuando:
- Es pura decoración
- La animación corre todo el tiempo que la pestaña está abierta
- Tu público está en Safari o móvil, donde apenas funciona
Coge la demo de arriba, pásala a tu proyecto, cambia colores y formas por las de tu marca y publícala. El código completo está aquí en la página: ver código fuente, copiar y adaptar.
Referencias
- Aymkdn/animated-favicon en GitHub — Librería de favicon animado basada en Web Worker que sigue animando en pestañas inactivas
- The Making of an Animated Favicon — CSS-Tricks — El paseo de Chris Coyier por la técnica de canvas al favicon
- How to animate a favicon? — Stack Overflow — El hilo clásico con varios enfoques y notas de soporte por navegador
- OffscreenCanvas — MDN — La API que hace posible el patrón de animación con Web Worker
Use favicon.im to quickly check if your favicon is configured correctly. Our free tool ensures your website's favicon displays properly across all browsers and devices.
Free Public Service
Favicon.im is a completely free public service trusted by developers worldwide.