El levantamiento al pasar el ratón: la microinteracción que delata a la IA
Veinte caracteres de Tailwind que aparecen en todas las landings generadas por IA: la misma tarjeta que sube 4 píxeles y echa sombra. Te enseño a verlo, por qué penaliza el rendimiento y qué poner en su lugar.
Abre la consola del navegador en las últimas seis landings hechas con IA que hayas visto. Pasa el ratón por encima de una tarjeta de precios. Se eleva. Pásalo por una tarjeta de características. Se eleva exactamente lo mismo. Pásalo por un testimonio, por el teaser de un artículo, por la foto de un miembro del equipo, por el logo del pie de página que desde luego no debería ser un botón, y todos suben justo 4 píxeles y les crece una sombra. El movimiento es idéntico porque el marcado es idéntico:
<div class="rounded-2xl border bg-card p-6 shadow-sm
transition-all hover:-translate-y-1 hover:shadow-xl">hover:-translate-y-1 hover:shadow-xl. Veinte caracteres de Tailwind. Es la microinteracción más desplegada de la era de las webs hechas con IA, y en cuanto aprendes a verla ya no puedes dejar de verla. Es el equivalente en diseño a la animación de scroll fade-in-up: un valor por defecto aplicado con tanta uniformidad que deja de ser una decisión y se convierte en una huella dactilar.
Qué hacen en realidad las dos clases
-translate-y-1 es transform: translateY(-0.25rem), un desplazamiento de 4px hacia arriba. shadow-xl cambia la box-shadow por defecto de Tailwind por otra más grande y difusa:
/* shadow-sm (en reposo) */
box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
/* shadow-xl (al pasar el ratón) */
box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1),
0 8px 10px -6px rgb(0 0 0 / 0.1);Y transition-all ata ambas cosas durante 150ms con la curva de aceleración por defecto de Tailwind, cubic-bezier(0.4, 0, 0.2, 1). La tarjeta flota hacia arriba, proyecta una sombra más profunda y el cerebro lee "esto se puede levantar, puedes hacer clic".
Aislado, no está mal. Es una pista de uso real y legible, con raíces anteriores a Tailwind: el sistema de elevación de Material Design hacía exactamente lo mismo con z-depth en 2014. El problema no es el gesto. El problema es que ahora se aplica a *todo*, con *cero* variación en distancia, aceleración o sombra, y sobre elementos que ni siquiera son interactivos.
Por qué los generadores recurren a esto por reflejo
Pídele a Cursor, v0, Lovable o Bolt "una rejilla de características" y te dará el levantamiento al pasar el ratón sin que lo hayas pedido. Nadie escribió "añade una animación de hover". Llega como valor por defecto ambiental, y hay tres razones.
Es el centro estadístico de los datos de entrenamiento. Cada ejemplo de tarjeta de shadcn/ui, cada bloque de marketing de Tailwind UI, cada repo de "las 100 mejores landing pages" que acabó scrapeado usa alguna variante del levantamiento al pasar el ratón. Cuando el modelo predice "qué viene después de rounded-2xl border", hover:-translate-y-1 hover:shadow-xl es la continuación con mayor probabilidad. Es regresión a la media disfrazada de diseño. El monocultivo de shadcn no termina en el componente Card: se extiende hasta cómo se comporta esa tarjeta.
Es una señal de "acabado" gratis. Los LLM están ajustados para parecer útiles. Una tarjeta estática parece sin terminar; una tarjeta que reacciona parece "interactiva" y "moderna". El modelo recurre al gesto más barato que se lee como esfuerzo. transition-all hover:-translate-y-1 es el equivalente en diseño de movimiento a adornar un plato con una ramita de perejil: no cuesta nada y transmite "alguien pensó en esto", aunque nadie lo hiciera.
transition-all es la agrupación perezosa. Un desarrollador cuidadoso solo hace transición de las propiedades que cambian: transition-[transform,box-shadow]. El generador escribe transition-all porque no sabe, o no se molesta en razonar, qué propiedades se van a animar. Así que anima el universo entero, y volveremos a esto, porque tiene un coste real.
Por qué un levantamiento uniforme se lee como hecho a máquina
Los estados hover diseñados por personas tienen *intención*: difieren según para qué sirve el elemento. Un CTA principal podría rellenarse de izquierda a derecha. Una tarjeta de precios podría subir su borde al color de acento y resaltar un número. Una miniatura podría hacer zoom sobre la imagen dentro de un marco fijo. Un enlace de navegación podría deslizar un subrayado. Cada gesto responde a la pregunta "¿qué significa interactuar con esto?".
El valor por defecto de la IA no responde nada. Aplica el mismo levantamiento de 4px a una tarjeta de $0/forever y a una de $499/year, a un teaser de blog clicable y a un bloque de estadísticas no clicable, a un botón y a un icono decorativo. Cuando *todos* los elementos comparten *un* solo comportamiento hover, el comportamiento deja de comunicar. Un estado hover que significa "todo" no significa nada: es solo textura.
Esta es exactamente la señal que se describe en leer el CSS para auditar si una web es IA: abre las DevTools, pasa el ratón por tres elementos estructuralmente distintos y comprueba si la regla :hover es byte por byte idéntica. En una web hecha por una persona, un CTA y una tarjeta de blog hacen hover de forma distinta porque alguien decidió que debían hacerlo. En una web hecha con IA encontrarás el mismo translateY(-0.25rem) y la misma shadow-xl en los tres. La uniformidad *es* la firma: la misma energía que el degradado azul a morado apareciendo en cada hero sin importar la marca.
Hay una segunda señal escondida en la curva de aceleración. El cubic-bezier(0.4, 0, 0.2, 1) por defecto sobre 150ms está bien para un solo elemento. Pero cuando doce tarjetas de una rejilla se levantan con la misma curva y la misma duración, pasar el ratón por la rejilla produce una ondulación mecánica: cada tarjeta saltando y cayendo con una monotonía de metrónomo. El movimiento diseñado tiene ritmo y variación; esto no tiene ninguno. Es el primo espacial de la coreografía uniforme de fade-in-up al hacer scroll, donde cada sección entra con el mismo desplazamiento y desvanecido con la misma temporización.
El coste de rendimiento y de tirones que nadie mide
Aquí es donde el valor por defecto deja de ser meramente aburrido y empieza a ser activamente malo.
transition-all anima box-shadow, que es caro. Animar box-shadow obliga al navegador a repintar el elemento en cada fotograma: no puede delegarse en el compositor de la GPU como sí ocurre con transform y opacity. En una sola tarjeta no lo notarás. En una rejilla de 12 tarjetas donde el usuario barre el ratón por todas, estás disparando repintados sobre una región de sombra grande y difusa doce veces seguidas. En un móvil Android de gama media o en un portátil barato, ahí es donde se consume el presupuesto de fotogramas y el levantamiento empieza a tartamudear.
transition-all también anima cosas que no pretendías. Como es all, cualquier propiedad que cambie por casualidad (un cambio de color heredado de un padre, un empujón de layout, un re-render que intercambia una clase) también se anima, produciendo a veces un retardo visible donde querías un cambio instantáneo. Es un tiro al pie precisamente porque es indiscriminado.
El levantamiento puede provocar layout thrash si la tarjeta tiene vecinos. translateY en sí mismo es amigable con el compositor y no fuerza reflow. Pero los generadores suelen acompañar el levantamiento con un hover:scale-105, y escalar una tarjeta dentro de un CSS grid apretado puede hacer que se solape o colisione visualmente con sus hermanas, y en algunos layouts empuje el contenido de alrededor. El gesto de "acabado" crea un fallo.
El arreglo para la parte de rendimiento es una línea:
<!-- Por defecto de la IA -->
<div class="transition-all hover:-translate-y-1 hover:shadow-xl">
<!-- Versión honesta: nombra las propiedades, acorta el salto de sombra -->
<div class="transition-[transform,box-shadow] duration-200 ease-out
hover:-translate-y-0.5 hover:shadow-lg
will-change-transform">Nombra las propiedades para no animar el universo entero. Dale una pista al compositor con will-change-transform si el levantamiento es el movimiento principal. Y recorta el salto de sombra: pasar de shadow-sm a shadow-lg en lugar de a shadow-xl repinta una región más pequeña y hace que la tarjeta parezca menos asustada.
Alternativas de hover que de verdad significan algo
El objetivo no es prohibir los estados hover. Es hacer que cada uno *responda a una pregunta* sobre el elemento en el que está. Aquí van gestos con intención, por tipo de elemento.
Un CTA principal: rellena, no flotes
Un botón es lo que más quieres que se pulse de toda la página. Dale un relleno direccional para que el hover refuerce "esta es la acción" y no "esto es una tarjeta que da la casualidad de ser un botón".
.cta {
background: #0a0a0a;
background-image: linear-gradient(90deg, #f43f5e 0%, #f43f5e 100%);
background-size: 0% 100%;
background-repeat: no-repeat;
transition: background-size 220ms ease-out;
}
.cta:hover { background-size: 100% 100%; }El acento (#f43f5e, un rosa de verdad, no el azul de Tailwind; mira cómo elegir un acento que no sea el de fábrica) entra barriendo desde la izquierda. Es direccional, es específico de un botón y es barato para la GPU porque aquí background-size no repinta una sombra difusa.
Una tarjeta de precios: cambia de estado, no de altitud
El trabajo de una tarjeta de precios es la comparación. El hover interesante no es "elevarse", es "comprometerse". Sube el borde al color de acento y eleva el CTA de dentro, dejando la tarjeta plantada en su sitio:
<div class="group rounded-2xl border-2 border-zinc-200
transition-colors duration-200 hover:border-rose-500">
<span class="text-4xl font-semibold tabular-nums">$24</span>
<button class="mt-6 w-full rounded-lg bg-zinc-900 py-2
transition-transform group-hover:-translate-y-0.5">
Start
</button>
</div>La tarjeta no se mueve; responden el *borde* y el *botón interior*. Eso se lee como "te estás fijando en este plan", que es para lo que sirve una tarjeta de precios. Usa group-hover para que el gesto apunte al hijo que importa, no al bloque entero.
Una miniatura de contenido: zoom dentro del marco
Para el teaser de un artículo o una imagen de portafolio, el levantamiento no te dice nada. Haz zoom sobre la imagen *dentro* de un marco con overflow fijo, de modo que la huella de la tarjeta nunca se mueva y nada haga reflow:
<a class="block overflow-hidden rounded-xl">
<img class="aspect-video w-full object-cover
transition-transform duration-500 ease-out
hover:scale-105" />
</a>El marco es estable, la imagen respira, el movimiento es lento (500ms) y cinematográfico en lugar de un salto nervioso de 150ms. Aceleración más lenta en las imágenes, más rápida en los botones: esa variación por sí sola rompe la uniformidad estampada a máquina.
Un enlace de navegación: un subrayado que se dibuja
.nav-link {
background-image: linear-gradient(currentColor, currentColor);
background-size: 0% 1px;
background-position: 0 100%;
background-repeat: no-repeat;
transition: background-size 180ms ease;
}
.nav-link:hover { background-size: 100% 1px; }Un subrayado que se dibuja de izquierda a derecha. Es un enlace, se comporta como un enlace y no comparte ni un gen con el levantamiento de la tarjeta.
El bloque de estadísticas no interactivo: nada de hover
La alternativa más infravalorada. Si un bloque de estadísticas, un logo o un encabezado de sección no es clicable, no le pongas *ningún* estado hover. Lo más humano que puedes hacer es dejar inertes los elementos no interactivos. Parte de la señal del valor por defecto de la IA es que hace que las cosas decorativas parezcan levantables: la contención invierte la huella al instante.
La auditoría de una línea y la cura
Para comprobar si tu propia web tiene la señal, pega esto en la consola y pasa el ratón por ahí:
[...document.querySelectorAll('*')]
.map(el => getComputedStyle(el, ':hover')) // ilustrativo
// En la práctica: pasa el ratón por 3 elementos distintos en las DevTools,
// inspecciona la regla :hover, compara transform + box-shadow.Si un botón, una tarjeta y un no-enlace resuelven todos a translateY(-0.25rem) + shadow-xl, has desplegado el valor por defecto. La cura no es más animación, es animación *diferenciada* más una inercia deliberada. Tres o cuatro gestos hover distintos, cada uno emparejado con lo que hace su elemento, más un "nada de hover" firme en todo lo decorativo. Esa es la diferencia entre el movimiento que comunica y el movimiento que es solo el modelo adornando el plato.
El levantamiento al pasar el ratón no es malvado. Es una pista de uso perfectamente razonable que se convirtió en huella dactilar por pura repetición, igual que cada web generada por IA recurre al mismo puñado de recursos. El arreglo es el de siempre: deja de aceptar la continuación más probable como si fuera una decisión de diseño. Los estados hover son baratos. Los estados hover con *intención* son el trabajo entero.
SHIP CODE THAT LOOKS INTENTIONAL
Scan your frontend for AI patterns. Generate a unique design system. Stop shipping the same blue gradient as everyone else.