Hay un momento muy concreto en el que una web deja de parecer «una web hecha» y empieza a parecer «una web cuidada». Casi nunca es el diseño general. Es ese segundo en el que el botón te confirma que ha pasado algo. O el campo del formulario te avisa antes de que envíes un error. O el corazoncito hace un pequeño «pop» cuando le das.
Eso son las microinteracciones web, y son la diferencia entre una web correcta y una web que la gente recuerda. Aquí tienes 15 ejemplos útiles con su código para copiar, ordenados en tres bloques: formularios, navegación y scroll, y feedback de acciones. He revisado el código en octubre de 2026. Donde ya existe una versión solo con CSS para los navegadores actuales, te la indico.
Antes de empezar: útil vs decorativo
Una microinteracción web es útil cuando le dice al usuario algo que sin ella no sabría. Por ejemplo, que su clic ha funcionado, que el campo tiene un error o que algo está cargando. Es decorativa cuando solo está para hacer «wow». Las primeras ayudan a que el usuario termine lo que empezó. Las segundas, si abusas, ralentizan el flujo y molestan.
La pregunta que me hago siempre antes de meter una animación: «¿qué le estoy comunicando al usuario que sin esto no sabría?». Si la respuesta es «nada, pero queda bonito», fuera.
Bloque 1: microinteracciones en formularios (las que más conversión suben)
El formulario es donde el usuario más dudas tiene, así que es donde más se nota el feedback. Si quieres ver formularios completos bien resueltos, tienes inspiración en estos ejemplos de formularios que convierten.
1. Label flotante al hacer focus
Sigue siendo de las más elegantes. El label vive dentro del input y sube cuando el usuario hace focus o escribe. Ahorra espacio en móvil y guía al usuario sin estorbar.
Ojo con un detalle que rompe este efecto en muchos tutoriales: el input necesita un placeholder (vale con un espacio) para que :placeholder-shown funcione. Sin él, el label se queda arriba desde el principio.
<div class="form-group">
<input id="email" type="email" placeholder=" ">
<label for="email">Tu email</label>
</div>
.form-group {
position: relative;
}
.form-group input {
padding: 16px 12px 6px;
border: 1px solid #ccc;
width: 100%;
}
.form-group label {
position: absolute;
left: 12px;
top: 14px;
color: #888;
transition: top 200ms ease, font-size 200ms ease, color 200ms ease;
pointer-events: none;
}
.form-group input:focus + label,
.form-group input:not(:placeholder-shown) + label {
top: 2px;
font-size: 11px;
color: #0066cc;
}
Cuándo usarla: formularios largos donde quieres ahorrar espacio. Cuándo no: formularios de 2 campos, no aporta nada.
2. Validación en tiempo real con check verde
El usuario sabe al instante si lo está haciendo bien. Reduce la ansiedad de «¿lo estaré escribiendo mal?» y evita el momento «envío y me salta error».
Usa :user-valid y :user-invalid en lugar de :valid. Funcionan en todos los navegadores actuales y solo se activan cuando el usuario ya ha interactuado con el campo. Así no marcas en rojo un campo que todavía no ha tocado ni pones un check verde en uno opcional vacío.
input:user-valid {
border-color: #22c55e;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='%2322c55e'%3E%3Cpath d='M16.7 5.3a1 1 0 010 1.4l-7 7a1 1 0 01-1.4 0l-4-4a1 1 0 011.4-1.4L9 11.6l6.3-6.3a1 1 0 011.4 0z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 10px center;
background-size: 18px;
}
input:user-invalid {
border-color: #dc2626;
}
3. Botón submit que se transforma en spinner
Esta es de las que más impacto tiene en la conversión. El usuario hace clic, ve que pasa algo, y no vuelve a darle 5 veces pensando que no funciona (sí, pasa, y mucho).
button.loading {
pointer-events: none;
color: transparent;
position: relative;
}
button.loading::after {
content: '';
position: absolute;
width: 16px;
height: 16px;
top: 50%;
left: 50%;
margin: -8px 0 0 -8px;
border: 2px solid #fff;
border-top-color: transparent;
border-radius: 50%;
animation: spin 600ms linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
Cuando añadas la clase loading con JavaScript, pon también aria-busy="true" en el botón. Así un lector de pantalla también sabe que está cargando, porque el texto transparente no lo ve nadie.
4. Mensaje de éxito con fade-in suave
Tras enviar el formulario, una confirmación que aparece con un fade-in corto. Sutil pero firme. Evita el «¿se ha enviado o no?». Dale role="status" al contenedor para que los lectores de pantalla lo anuncien.
.success-message {
opacity: 0;
transform: translateY(8px);
animation: fadeInUp 250ms ease forwards;
}
@keyframes fadeInUp {
to { opacity: 1; transform: translateY(0); }
}
5. Autoformato de inputs (teléfono, fecha, tarjeta)
Mientras escribes «612345678» aparece «612 345 678». Es trabajo del input, no del usuario. Usa type="tel" e inputmode="numeric" para que en móvil salga el teclado numérico.
document.querySelector('#tel').addEventListener('input', (e) => {
const v = e.target.value.replace(/\D/g, '').slice(0, 9);
e.target.value = v.replace(/(\d{3})(\d{3})(\d{3})/, '$1 $2 $3').trim();
});
Bloque 2: navegación y scroll (las que más se notan)
6. Header que se encoge al hacer scroll
El header pasa de 80 px a 56 px cuando bajas. Gana espacio de lectura sin perder el menú. Va en dos bloques porque el CSS y el JavaScript van en archivos distintos.
header {
height: 80px;
transition: height 200ms ease;
}
header.scrolled {
height: 56px;
}
const header = document.querySelector('header');
window.addEventListener('scroll', () => {
header.classList.toggle('scrolled', window.scrollY > 50);
}, { passive: true });
Animar height recalcula la maquetación, pero aquí solo ocurre una vez al cruzar el umbral, así que no penaliza. Lo que no debes hacer es cambiar la altura en cada píxel de scroll.
7. Barra de progreso de scroll (sin JavaScript)
En posts largos como este, una barrita arriba que indica cuánto te queda de lectura. En 2026 ya se puede hacer solo con CSS gracias a las scroll-driven animations: funcionan en Chrome, Edge y Safari 26. Para el resto de navegadores, añade el JavaScript de abajo, que solo se ejecuta si el CSS no está soportado.
.progress {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 3px;
background: #0066cc;
transform: scaleX(0);
transform-origin: left;
z-index: 999;
}
@supports (animation-timeline: scroll()) {
.progress {
animation: progreso linear both;
animation-timeline: scroll(root);
}
@keyframes progreso {
to { transform: scaleX(1); }
}
}
if (!CSS.supports('animation-timeline: scroll()')) {
const barra = document.querySelector('.progress');
window.addEventListener('scroll', () => {
const h = document.documentElement;
const pct = h.scrollTop / (h.scrollHeight - h.clientHeight);
barra.style.transform = `scaleX(${pct})`;
}, { passive: true });
}
Fíjate en que la barra crece con transform: scaleX() y no con width. Es la regla de oro de todo este artículo: anima transform y opacity, que no recalculan la maquetación.
8. Underline animado en links del menú
Un subrayado que crece de izquierda a derecha al pasar el ratón. Lo he añadido también a :focus-visible para que quien navega con teclado vea el mismo efecto. Si quieres menús completos con más efectos, tienes cuatro ejemplos en menús animados con CSS3.
nav a {
position: relative;
text-decoration: none;
}
nav a::after {
content: '';
position: absolute;
left: 0;
bottom: -4px;
width: 100%;
height: 2px;
background: currentColor;
transform: scaleX(0);
transform-origin: left;
transition: transform 200ms ease;
}
nav a:hover::after,
nav a:focus-visible::after {
transform: scaleX(1);
}
9. Smooth scroll con offset para header fijo
El detalle que casi nadie pule: si tienes header fijo y haces smooth scroll a un ancla, el contenido te queda tapado detrás del header. Solución con CSS puro:
html { scroll-behavior: smooth; }
section[id] { scroll-margin-top: 80px; }
10. Fade-in en cascada al hacer scroll
Los elementos de una sección aparecen uno tras otro con 50 ms de retraso entre ellos. Da sensación de «vivo» sin marear. Usa IntersectionObserver, no listeners de scroll, que castigan el rendimiento. Tienes más ideas en el artículo sobre animaciones que se activan con el scroll.
.fade-up {
opacity: 0;
transform: translateY(20px);
transition: opacity 300ms ease, transform 300ms ease;
}
.fade-up.visible {
opacity: 1;
transform: translateY(0);
}
const io = new IntersectionObserver((entries) => {
entries.forEach((e, i) => {
if (e.isIntersecting) {
setTimeout(() => e.target.classList.add('visible'), i * 50);
io.unobserve(e.target);
}
});
}, { threshold: 0.1 });
document.querySelectorAll('.fade-up').forEach((el) => io.observe(el));
Si solo te importan Chrome, Edge y Safari 26, puedes hacerlo sin JavaScript con animation-timeline: view(), la hermana de la técnica del ejemplo 7.
El subrayado animado, el pulso, el foco accesible y el bloque de «reducir movimiento» están en mi pack CSS, con 38 estilos más. Te lo envío gratis al correo, con un catálogo visual para copiar cada estilo en un clic.
Bloque 3: feedback de acciones (las que más alegría dan)
11. Botón «copiar» que cambia a «copiado»
En posts con código (como este) es básico. El usuario copia, ve «Copiado ✓» durante 2 segundos, y el botón vuelve a la normalidad.
document.querySelectorAll('.copy-btn').forEach((btn) => {
btn.addEventListener('click', async () => {
await navigator.clipboard.writeText(btn.dataset.copy);
const original = btn.textContent;
btn.textContent = 'Copiado ✓';
btn.classList.add('copied');
setTimeout(() => {
btn.textContent = original;
btn.classList.remove('copied');
}, 2000);
});
});
12. Like / favorito con animación pulse
El clásico corazón que crece y vuelve. Funciona porque es satisfactorio, no porque sea necesario, pero aquí lo decorativo está justificado: la acción es emocional. Usa aria-pressed="true" en el botón activo para que el estado no dependa solo del color.
.like-btn.active {
animation: pulse 300ms ease;
color: #e11d48;
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.3); }
100% { transform: scale(1); }
}
Para interruptores tipo on/off, que son otra forma de feedback inmediato, tienes el paso a paso en botones on/off con CSS3.
13. Toast de éxito que aparece desde abajo
Notificación no intrusiva. Aparece, vive 3 segundos y se va. No bloquea la pantalla como un modal. Lo animo con transform y no con bottom, por la misma regla de rendimiento de antes.
<div class="toast" role="status" aria-live="polite"></div>
.toast {
position: fixed;
bottom: 24px;
left: 50%;
transform: translate(-50%, 150%);
opacity: 0;
background: #1f2937;
color: #fff;
padding: 12px 24px;
border-radius: 8px;
transition: transform 250ms ease, opacity 250ms ease;
}
.toast.show {
transform: translate(-50%, 0);
opacity: 1;
}
function showToast(msg) {
const t = document.querySelector('.toast');
t.textContent = msg;
t.classList.add('show');
setTimeout(() => t.classList.remove('show'), 3000);
}
14. Skeleton loading
Mientras cargan los datos, muestras la «estructura» del contenido con un brillo que la recorre. Es mejor que un spinner porque el usuario ya intuye qué viene.
.skeleton {
background: linear-gradient(90deg, #eee 0%, #f5f5f5 50%, #eee 100%);
background-size: 200% 100%;
animation: shimmer 1.2s infinite;
border-radius: 4px;
height: 16px;
}
@keyframes shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
15. Feedback háptico en móvil
Una vibración corta al confirmar una acción crítica (pagar, eliminar, enviar). Es sutil pero se nota. Funciona en Chrome para Android. En Safari para iPhone, navigator.vibrate no está soportado, así que el if evita errores y simplemente no vibra.
function hapticConfirm() {
if ('vibrate' in navigator) {
navigator.vibrate(10); // 10 ms: casi imperceptible, pero se siente
}
}
document.querySelector('#pagar').addEventListener('click', hapticConfirm);
¿No quieres montar cada microinteracción a mano? En Envato Elements tienes plantillas HTML y UI kits que ya traen hovers, loaders y transiciones pulidas, con licencia comercial para proyectos de clientes.
Las 3 reglas que aplico siempre para no pasarme
1. Ninguna transición de respuesta dura más de 300 ms. El punto dulce está entre 150 y 250 ms. Si pasa de 300, ya no es una microinteracción, es una animación, y el usuario la percibe como lenta. Los loaders en bucle (spinner, skeleton) son la excepción: duran lo que tarde la carga.
2. Máximo 3 microinteracciones simultáneas en pantalla. Si el usuario hace scroll y a la vez ve aparecer 8 elementos animándose, se marea y deja de leer. Menos es más.
3. Si te hace pensar antes de actuar, está mal calibrada. Una buena microinteracción se siente, no se piensa. Si el usuario se fija más en la animación que en lo que acaba de hacer, sobra.
El bloque que no es opcional: prefers-reduced-motion
Hay usuarios con vértigo, trastornos vestibulares o migrañas que pueden marearse de verdad con animaciones que a ti te parecen sutiles. Su sistema operativo tiene una opción de «reducir movimiento», y tu web debería respetarla.
En cuanto a normativa, WCAG 2.2 lo recoge en el criterio 2.3.3, que es de nivel AAA. La European Accessibility Act, aplicable desde junio de 2025, exige el nivel AA, así que este criterio en concreto no es obligatorio por ley. Lo que sí entra en el nivel A es poder pausar animaciones automáticas de más de 5 segundos. Respetar «reducir movimiento» es la forma más barata de cumplir con todo. Tienes el resto de requisitos en esta guía práctica de diseño web accesible.
Este bloque va al final de tu CSS:
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
No quites las animaciones del todo (puede romper layouts que dependen de transiciones). Déjalas en 0.01 ms para que sigan «ocurriendo» pero sean instantáneas.
Preguntas frecuentes
¿Las microinteracciones web afectan al rendimiento (INP, LCP)?
Las que animan transform y opacity apenas lo notan, porque el navegador las resuelve sin recalcular la maquetación. Las que tocan width, height, top o left en cada fotograma sí: fuerzan al navegador a recolocar la página. Y una librería de animación cargada entera puede sumar decenas de KB que se notan en móvil. Si usas WordPress, mira cómo medir y mejorar los Core Web Vitals.
¿CSS o JavaScript?
CSS siempre que se pueda. En 2026 cubre más que nunca: validación con :user-valid, animaciones ligadas al scroll con animation-timeline y transiciones entre páginas con View Transitions. JavaScript solo cuando necesites coordinar varias animaciones en cadena o depender del estado de la aplicación.
¿Cuántas microinteracciones son demasiadas?
Si en una pantalla hay más de 5-7 microinteracciones distintas, casi seguro sobran 3 o 4. La economía de movimiento mejora la experiencia más que la abundancia.
¿Sirven para SEO?
Directamente no. Indirectamente pueden ayudar si hacen la web más fácil de usar: formularios que se completan a la primera, menos clics repetidos. Pero una animación mal hecha empeora el INP, que sí es una métrica de Core Web Vitals. Mételas porque mejoran la experiencia, no «para SEO».
Para terminar
Las microinteracciones web son uno de esos detalles que separan una web profesional de una que solo cumple: se notan poco y suman mucho. Estas 15 cubren casi todos los casos que te vas a encontrar en una web normal. Aplícalas con criterio (útil sobre decorativo, rápido sobre lento, accesible sobre vistoso) y subirá la percepción de calidad de tus webs sin mucho más trabajo. Si estás empezando con CSS, la hoja de ruta para aprender CSS te ordena el resto.
Si solo te llevas tres cosas: 200 ms como referencia, anima solo transform y opacity, y respeta prefers-reduced-motion. Con eso ya estás por encima de la mayoría de las webs que se publican.


