Actualizado 10 de julio de 2026

Estados hover y pulsado: derivarlos de la escala

El color hover de un botón no debería calcularse a partir de su color en reposo: debería ser el paso vecino en la misma escala de color. En un tema claro, el hover es un paso más oscuro que el reposo y el pulsado es un paso más oscuro todavía: un botón que reposa en brand-600 hace hover en brand-700 y se pulsa en brand-800. Tres colores reales de la rampa, no dos variantes filtradas de uno solo.

La regla suena casi demasiado pequeña como para merecer un artículo y, sin embargo, su inversa —estados hover producidos con opacidad, darken() o un filtro de brillo— está entre los defectos más comunes de las interfaces publicadas. Por qué ganan los pasos vecinos, a qué distancia deben quedar y por qué toda la regla invierte su dirección en modo oscuro se desprende de cómo se construyen las escalas de color, que es el terreno que cubre nuestra guía de escalas de color.

¿Por qué no usar opacidad o un filtro darken()?

Porque los filtros abandonan la rampa. El hover de brand-600 se convierte en un color que no existe en ningún otro lugar del sistema —sin nombre, sin probar, invisible para el pipeline de tokens— y se comporta mal de tres maneras concretas.

La opacidad se mezcla con lo que haya detrás. Un botón al 85 % de opacidad muestra un color sobre una página blanca y otro distinto sobre una tarjeta con tinte, así que el “mismo” estado hover varía por todo el producto. Peor aún, la mezcla puede chocar con el fondo: un azul translúcido sobre una superficie cálida absorbe esa calidez, y nadie eligió jamás ese resultado.

El oscurecimiento por canales deriva. darken() y sus parientes reducen los valores RGB y, en sRGB, esa operación hace algo más que oscurecer: normalmente desatura y puede desplazar el tono a medida que los canales se recortan a ritmos distintos. El hover sale más grisáceo y con el tono ligeramente desviado, percibido como sucio en lugar de más profundo.

El color filtrado nunca pasó una comprobación de contraste. El color en reposo pasó sus mínimos; la salida del filtro no pasó nada. Un texto que cumplía 4,5:1 en reposo puede fallar sin avisar al hacer hover.

La mecánica de CSS es la parte trivial — :hover intercambia una propiedad personalizada o una clase. La pregunta siempre fue únicamente qué color trae ese intercambio, y la escala ya contiene la respuesta correcta: el paso de al lado, generado por las mismas reglas, en el mismo tono, ya comprobado.

¿Qué tan grande debería ser el salto entre estados?

Un paso suele ser lo correcto, y los límites de ambos lados explican por qué.

El suelo es perceptual: un cambio por debajo de la diferencia apenas perceptible se lee como ningún cambio. Scale Composer avisa cuando dos pasos adyacentes quedan a menos de 0,02 L uno del otro, porque un salto de hover más pequeño que eso es un hover que la gente no puede ver: el botón parece muerto aunque la hoja de estilos jure que responde.

El techo es la identidad: un salto de varios pasos se lee como un color distinto en lugar de un estado distinto. El botón parece cambiar de idea sobre lo que es, y el ojo interpreta un reemplazo, no una pulsación. Entre esos límites, un paso bien construido cae con comodidad: claramente visible y, aun así, inconfundiblemente el mismo color. El pulsado toma entonces el paso siguiente al hover: la interacción se profundiza en la misma dirección en la que empezó.

¿Cómo se ve el recorrido en números?

A partir del color semilla azul #2563eboklch(0.546 0.215 262.9) — el vecindario 600/700/800 de la rampa queda así:

EstadoPasoOKLCHHex
reposo600oklch(0.52 0.134 262.9)#3E65B5
hover700oklch(0.43 0.073 262.9)#3A4F78
pulsado800oklch(0.34 0.031 262.9)#2F3848

Cada movimiento baja la luminosidad en ≈0,09 —unas cuatro veces el umbral JND de 0,02, así que inconfundible— mientras el tono se mantiene en 262,9° a lo largo de los tres pasos. Esa columna de tono es el argumento silencioso contra los filtros: un darken() en sRGB no lo habría conservado. El croma que se suaviza hacia el extremo oscuro es el propio plan de saturación de la rampa en acción, por lo que el estado pulsado se lee como el mismo azul pulsado más a fondo en vez de un color nuevo y más grisáceo. Scale Composer deriva stateNormal, stateHover y statePressed entre sus roles semánticos exactamente así: pasos vecinos en la rampa, asignados contra los mínimos de contraste de la superficie.

Abre este recorrido de tres pasos en Scale Composer: reposo, hover y pulsado resaltados como vecinos en la rampa azul, con las diferencias de luminosidad entre ellos medidas.

Los estados de reposo, hover y pulsado de un botón mostrados como tres pasos vecinos en una rampa azul en Scale Composer, cada uno un paso más oscuro que el anterior

¿Y el foco y el estado deshabilitado?

Dos estados quedan fuera de la regla del recorrido, brevemente.

El foco no es un cambio de relleno. Es un rol de anillo aparte: un contorno que debe seguir siendo visible tanto contra el botón como contra la página que hay detrás. Derivarlo como “un paso más” lo entierra; quien navega con teclado necesita que el anillo se anuncie, no que se funda con la secuencia de pulsación.

El estado deshabilitado se sale por completo de la lógica de interacción. Es la pareja de croma bajo y contraste bajo del conjunto de roles, y a propósito: un control deshabilitado comunica retrayéndose. Los mínimos de contraste no se le aplican —las pautas de accesibilidad eximen a los controles inactivos— y por eso es el único estado que se supone que debe fallar las comprobaciones que los demás pasan.

¿Por qué el modo oscuro invierte la dirección?

En las superficies oscuras, el hover va más claro, no más oscuro. La convención viene de la lógica de elevación: en los temas oscuros, las superficies más cercanas al espectador se renderizan más claras, y un control con hover está momentáneamente “elevado”. También hay una razón puramente práctica: desde un paso de reposo oscuro, ir más oscuro se dirige hacia el negro, y el cambio de estado se ahoga.

Una paleta oscura derivada consigue la inversión por construcción y no por excepción. Scale Composer deriva las paletas oscuras a partir del mismo color semilla con su propia curva de luminosidad y un aumento de croma de en torno al 20 % (el entorno oscuro atenúa el colorido percibido), de modo que los pasos de la rampa oscura son colores reales y ordenados por sí mismos, y “avanzar un paso en la dirección interactiva” simplemente apunta hacia el otro lado a lo largo de ellos. Sin trucos de hover específicos por tema; la regla sobrevive, la dirección se invierte.

Cambia el mismo botón a la paleta oscura derivada: los roles de reposo, hover y pulsado vueltos a derivar en la rampa oscura, avanzando más claro donde el tema claro avanzaba más oscuro.

Seguir leyendo

  • ¿Qué es una rampa de color (escala de color)?

    Qué es una rampa de color — un tono en diez pasos ordenados de luminosidad — más la anatomía: qué pasos hacen qué trabajos de UI, y por qué las rampas superan a elegir muestras sueltas.

  • Por qué los pasos de color se numeran de 50 a 900

    Los números de la escala de color explicados: de dónde viene el 50–900, por qué los números superan a nombres como claro y más claro, y por qué un 500 es una posición, no una medida.