En la era jQuery, el fade al pasar el ratón se hacía con .animate() o .fadeIn(). En 2026 eso sobra para estados simples de interfaz: el navegador interpola opacity directamente con CSS, con menos script, menos riesgo de layout thrashing y un efecto que respeta las preferencias del sistema cuando conectas prefers-reduced-motion.
Si buscaste un efecto hover de imagen CSS, la respuesta más corta es esta: añade transition: opacity 0.3s ease-in-out; al elemento, luego cambia opacity en :hover. Ese patrón cubre la mayoría de atenuaciones de imagen, miniaturas de tarjetas, fades de botón y revelaciones de overlay.
Como cambiar el efecto fade out al pasar el ratón con CSS
La petición más común es un cambio suave de opacity cuando el cursor entra o sale de un elemento. Este es el patrón mínimo:
.element {
opacity: 1;
transition: opacity 0.3s ease-in-out;
}
.element:hover {
opacity: 0.7;
}Esa es toda la implementación. Tres declaraciones en el estado base, una en el estado hover. La propiedad transition indica al navegador que anime el cambio de opacity durante 0.3 segundos con una curva ease-in-out.
Este patrón funciona en imágenes, botones, tarjetas, enlaces, iconos y cualquier otro elemento HTML. Ajusta la opacity objetivo (0.7 en este ejemplo) para controlar cuanto se atenúa el elemento. Valores más bajos crean un efecto fade más fuerte.
Para un efecto fade-in en hover (el elemento empieza atenuado y se vuelve completamente visible), invierte los valores:
.element {
opacity: 0.5;
transition: opacity 0.3s ease-in-out;
}
.element:hover {
opacity: 1;
}Transiciones CSS o JavaScript para efectos hover
JavaScript es la herramienta correcta cuando el estado depende de la red, de la validación de formularios o de secuencias complejas. Para “el ratón pasa sobre la imagen, atenúala un poco”, CSS es más fácil de leer y más barato de ejecutar.
Ventajas concretas en la práctica:
- No hay event listeners que limpiar en pantallas de administración con comportamiento de SPA.
- El navegador puede gestionar
opacityytransformen el hilo del compositor cuando la capa ya existe. - El mismo conjunto de reglas sirve para el ratón y para el foco de teclado si reflejas el estado con
:focus-visible. - Evitas condiciones de carrera entre
mouseenter/mouseleavey un CSS que ya está animando.
La excepción es cuando el efecto tiene que sincronizarse con una capa controlada por script (por ejemplo, una lightbox propia que define aria-hidden). Incluso entonces, CSS puede hacer el fade y JavaScript limitarse a cambiar una clase.
Efecto fade en imagen al pasar el ratón
Digamos que tienes una imagen que debería atenuarse cuando pasas el ratón sobre ella.
/* El elemento */
.hover-image {
opacity: 1;
/* La parte magica */
transition: opacity 0.3s ease-in-out;
}
/* El activador */
.hover-image:hover {
opacity: 0.7;
}Que ocurre:
- La imagen comienza con
opacity: 1(totalmente visible) - Al hover, transiciona a
opacity: 0.7(30% transparente) - Tarda 0.3 segundos con easing suave
- Vuelve a
opacity: 1cuando termina el hover
Propiedades de transition en CSS explicadas
Transition-property
Específica que propiedad CSS animar. Siempre específica propiedades concretas en lugar de all para mejor rendimiento.
/* Correcto: Propiedad específica */
transition: opacity 0.3s ease-in-out;
/* Evitar: Anima TODAS las propiedades (impacto en rendimiento) */
transition: all 0.3s ease-in-out;Propiedades animables:
opacity- Fade in/outtransform- Escalar, rotar, trasladarbackground-color- Cambios de colorborder-radius- Esquinas redondeadasbox-shadow- Efectos de sombra
Discretas (cambian de golpe en lugar de hacer fade):
display: solo transiciona contransition-behavior: allow-discrete, explicado en la sección sobre@starting-stylefont-family: solo cambio instantáneo
Transition-duration
Cuanto dura la animación. Valores comunes:
Mejores prácticas:
- 0.2-0.3s: Interacciones UI estándar (botones, enlaces)
- 0.15s: Micro-interacciones (tooltips, badges)
- 0.4-0.6s: Transiciones de página, animaciones de modal
- >1s: Evitar (se siente lento)
Transition-timing-function
Controla la curva de aceleración. Esto es lo que hace que las animaciones se sientan “naturales”.
Cuando usar cada una:
ease-out: La mayoría de elementos UI (se siente receptivo)ease-in-out: Transiciones suaves y elegantesease-in: Elementos apareciendo (menos común)linear: Barras de progreso, indicadores de cargacubic-bezier: Sensación personalizada (usa herramientas como cubic-bezier.com)
Transition-delay
El retraso es útil cuando una capa interior debe esperar a la exterior. En un fade simple de imagen, el retraso suele ser 0s; cualquier otra cosa hace que la interfaz parezca lenta.
Diferencia entre transition y animation en CSS
transition y animation no son herramientas intercambiables. Elige según qué desencadena el movimiento.
Usa transition cuando:
- Una propiedad cambia entre dos estados (hover, foco, clase abierta o cerrada).
- Quieres que el navegador interpole desde el valor actual hasta un valor nuevo.
- El efecto debe invertirse a mitad de camino si el usuario aparta el ratón.
Usa @keyframes / animation cuando:
- El movimiento debe ejecutarse sin interacción del usuario (carga, pulso discreto, introducción).
- Necesitas varios keyframes, retrasos por paso o
animation-iteration-count. - El estado no es un simple cambio de A a B.
/* Transition: guiada por un cambio de estado */
.btn {
opacity: 1;
transition: opacity 0.2s ease-out;
}
.btn:hover {
opacity: 0.85;
}
/* Animation: secuencia temporizada */
@keyframes fade-in-once {
from { opacity: 0; }
to { opacity: 1; }
}
.hero-title {
animation: fade-in-once 0.4s ease-out both;
}Un error habitual en los temas es “animar” el hover con una animation infinita y luego pelearse con animation-fill-mode. Para hover, transition es casi siempre la opción más limpia.
Sintaxis abreviada de transition en CSS
La forma abreviada es property duration timing-function delay:
.hover-image {
transition: opacity 0.3s ease-in-out 0s;
}
/* Varias propiedades */
.card-img {
transition:
opacity 0.25s ease-out,
transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}Mantén el mismo orden en todo el tema. Cuando un componente usa la forma larga y otro la abreviada con valores distintos, el lenguaje de movimiento se vuelve desordenado.
Efecto hover CSS con zoom, overlay y sombra
1. Fade + escala (efecto zoom)
Combina opacity y transform para un efecto zoom moderno:
.card-img {
opacity: 1;
transform: scale(1);
transition: opacity 0.3s ease-in-out, transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.card-img:hover {
opacity: 0.9;
transform: scale(1.05);
}2. Fade + texto overlay
Perfecto para galerías de imágenes:
.image-container {
position: relative;
overflow: hidden;
}
.image-container img {
opacity: 1;
transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out;
}
.image-container .overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.7);
opacity: 0;
transition: opacity 0.3s ease-in-out;
display: flex;
align-items: center;
justify-content: center;
color: white;
}
.image-container:hover img {
opacity: 0.7;
transform: scale(1.1);
}
.image-container:hover .overlay {
opacity: 1;
}3. Fade + cambio de color
Para botones y enlaces:
.button {
background-color: #0073aa;
color: white;
opacity: 1;
transition: opacity 0.2s ease-out, background-color 0.2s ease-out;
}
.button:hover {
opacity: 0.9;
background-color: #005177;
}
.button:active {
opacity: 0.8;
transform: scale(0.98);
}4. Fade + sombra
Añadir profundidad al hover:
.card {
opacity: 1;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
transition: opacity 0.3s ease-in-out, box-shadow 0.3s ease-in-out, transform 0.3s ease-in-out;
}
.card:hover {
opacity: 0.95;
box-shadow: 0 8px 16px rgba(0,0,0,0.2);
transform: translateY(-4px);
}Cómo hacer animaciones hover fluidas en CSS
Usar transform en lugar de posición y tamaño
Incorrecto (desencadena recalculo de layout):
.element {
left: 0;
transition: left 0.3s;
}
.element:hover {
left: 100px;
}Correcto (acelerado por GPU):
.element {
transform: translateX(0);
transition: transform 0.3s;
}
.element:hover {
transform: translateX(100px);
}Limitar propiedades animadas
/* Incorrecto */
transition: all 0.3s; /* Anima todo */
/* Correcto */
transition: opacity 0.3s ease-in-out;Usar will-change para animaciones complejas
.animated-element {
will-change: transform, opacity;
transition: transform 0.3s, opacity 0.3s;
}Ejemplos de efecto hover en tarjetas y galerías
Ejemplo 1: Tarjeta de producto
.product-card {
position: relative;
overflow: hidden;
}
.product-card img {
opacity: 1;
transform: scale(1);
transition: opacity 0.4s ease-in-out, transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.product-card:hover img {
opacity: 0.8;
transform: scale(1.1);
}
.product-card .badge {
position: absolute;
top: 10px;
right: 10px;
opacity: 0;
transition: opacity 0.3s ease-out 0.1s;
}
.product-card:hover .badge {
opacity: 1;
}Ejemplo 2: Menú de navegación
.nav-link {
border-bottom: 2px solid transparent;
transition: opacity 0.2s ease-out, border-color 0.2s ease-out;
}
.nav-link:hover {
opacity: 1;
border-bottom-color: #0073aa;
}Ejemplo 3: Galería de imágenes
.gallery-item {
position: relative;
overflow: hidden;
}
.gallery-item img {
opacity: 1;
filter: brightness(1);
transition: opacity 0.3s ease-in-out, filter 0.3s ease-in-out, transform 0.4s ease-out;
}
.gallery-item:hover img {
opacity: 0.9;
filter: brightness(0.8);
transform: scale(1.05);
}
.gallery-item .caption {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(to top, rgba(0,0,0,0.8), transparent);
color: white;
padding: 20px;
opacity: 0;
transform: translateY(20px);
transition: opacity 0.3s ease-out, transform 0.3s ease-out;
}
.gallery-item:hover .caption {
opacity: 1;
transform: translateY(0);
}Efectos hover accesibles con movimiento reducido
Respetar movimiento reducido
/* Predeterminado: animaciones habilitadas */
.animated-element {
transition: opacity 0.3s ease-in-out;
}
/* Preferencia de movimiento reducido */
@media (prefers-reduced-motion: reduce) {
.animated-element {
transition: none;
}
}Estados de focus
/* Asegurar que los efectos hover también funciónen en focus */
.interactive-element {
opacity: 1;
transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out;
}
.interactive-element:hover,
.interactive-element:focus {
opacity: 0.8;
transform: scale(1.02);
}
/* Focus visible para navegación por teclado */
.interactive-element:focus-visible {
outline: 2px solid #0073aa;
outline-offset: 2px;
}- Usa
:focus-visible, y no solo:focus, si quieres evitar el anillo de foco tras cada clic de ratón en los navegadores modernos. - Asegúrate de que el elemento puede recibir el foco de verdad (
<a>,<button>otabindex="0"con gestión de teclado). - No quites
outlinesin sustituirlo. El fade por sí solo no da contraste suficiente como indicador de foco.
Efectos hover en dispositivos táctiles
La media feature hover, de Media Queries Level 4, comprueba si el mecanismo de entrada principal puede pasar por encima de los elementos. MDN indica que devuelve none cuando la entrada principal no puede hacer hover en absoluto o no de forma cómoda, como muchos móviles que emulan el hover con una pulsación larga. Deja los estilos de foco fuera de la media query para que el foco de teclado siga obteniendo el mismo estado.
/* Habilitar efectos hover solo en dispositivos con hover */
@media (hover: hover) {
.hover-only-effect {
transition: transform 0.3s ease-in-out;
}
.hover-only-effect:hover {
transform: scale(1.05);
}
}Cómo añadir efectos hover CSS en WordPress
Cargar la hoja de estilos con wp_enqueue_style
Evita un bloque <style> suelto impreso desde wp_head o header.php siempre que puedas. Usa la API de enqueue del tema para que las dependencias, el versionado y la carga sean predecibles.
<?php
declare(strict_types=1);
add_action('wp_enqueue_scripts', static function (): void {
$theme_version = wp_get_theme()->get('Version');
$css_path = get_theme_file_path('assets/css/hover-fade.css');
$css_ver = file_exists($css_path) ? (string) filemtime($css_path) : $theme_version;
wp_enqueue_style(
'theme-hover-fade',
get_theme_file_uri('assets/css/hover-fade.css'),
[],
$css_ver
);
});Por qué este patrón:
filemtimeinvalida la caché cuando el archivo cambia, sin subir la versión a mano.- El handle
theme-hover-fadese puede quitar o sobrescribir en un tema hijo. - Evitas duplicados si un bloque o plugin intenta inyectar las mismas reglas.
En los temas de bloques (FSE) puedes seguir cargando una pequeña hoja de utilidades, o poner clases utilitarias en theme.json cuando encaje. Las reglas de hover más grandes, con media queries, siguen perteneciendo a archivos CSS. Si el efecto solo hace falta en una plantilla, condiciona el enqueue con is_singular() / is_page_template() para mantener el CSS crítico más pequeño.
Por qué el fade no funciona en bloques Gutenberg
Gutenberg cambia la estructura del DOM más que las plantillas clásicas. Un fade que “funcionaba en Classic” suele fallar por una de estas razones.
Selector incorrecto en el contenedor
Los bloques suelen envolverse en .wp-block-image, .wp-block-group o figure/figcaption. Una regla que apunta directamente a img:hover no se aplica cuando el hover ocurre en el enlace que envuelve la imagen.
/* Demasiado estrecho en muchos diseños de bloques */
.wp-block-image img:hover {
opacity: 0.7;
}
/* Más robusto */
.wp-block-image a:hover img,
.wp-block-image a:focus-visible img,
.wp-block-image figure:hover img {
opacity: 0.7;
}Estilos inline e imágenes de contenido
Los estilos de imagen definidos en el editor (style="width:...") no compiten necesariamente con opacity, pero un !important en el reset del tema o en el CSS de un plugin sí puede. Mantén la especificidad baja y coherente, y evita !important para el fade.
CSS adicional frente a hoja de estilos del bloque
El “CSS adicional” en Apariencia y Personalizar sirve para prototipos. En producción, usa un archivo propio mediante enqueue, o un estilo específico del bloque registrado con wp_enqueue_block_style, para que las reglas solo se carguen donde se usa el bloque.
Interactividad y bloques anidados
Los bloques de grupo con enlaces dentro pueden activar el hover en el padre mientras el foco está en un hijo. Prueba con el ratón y con Tab. :focus-within en el contenedor de la tarjeta resuelve muchos de estos casos.
Editor frente a frontend
El lienzo del editor no siempre carga el CSS de frontend del tema. Si el cliente “no ve el fade en el editor”, es lo esperado, salvo que también cargues los estilos con enqueue_block_assets o add_editor_style. Documenta la diferencia: el efecto aparece en el sitio publicado, no necesariamente en el lienzo.
Qué propiedades CSS son rápidas de animar
Animar propiedades que provocan layout (width, height, top, left, margin) o un paint costoso (box-shadow en superficies enormes sin capa propia) arriesga tirones en el móvil.
Mejor para fade y microinteracciones:
opacitytransform(translate, scale, rotate)
Con cuidado:
filter: blur()en imágenes grandes (puede ser costoso)- valores de
box-shadowanimados en secciones enteras de la pantalla transition: all
Rara vez necesitas will-change: opacity en cada imagen de una cuadrícula. will-change reserva memoria; úsalo de forma temporal en elementos que animan a menudo, o deja que el navegador promueva la capa durante la transición.
Mide con el panel Performance: busca frames largos durante el hover en una lista con muchas tarjetas. Si aparece layout thrashing, casi siempre se está animando la propiedad equivocada.
Por qué no se ve el fade CSS
- Comprueba que el valor inicial y el final son realmente distintos.
- Comprueba que
transitionestá en la regla base, no solo en:hover. La transición se lee del estilo al que cambia el elemento, así que sin ella falta la transición de vuelta. - Busca otras reglas que definan
transition: nonede forma global. - Revisa
prefers-reduced-motionen el sistema operativo. - En WordPress, confirma que la hoja de estilos está cargada (código fuente o pestaña Network) y que el selector coincide con el DOM del bloque renderizado.
Cómo reutilizar efectos hover con variables CSS
Las propiedades personalizadas permiten fijar duración, curva y valores de hover en un solo lugar y ajustarlos por contexto, por ejemplo en modo oscuro:
:root {
--transition-duration: 0.3s;
--transition-easing: ease-in-out;
--hover-opacity: 0.8;
--hover-scale: 1.05;
}
.hover-effect {
opacity: 1;
transition: opacity var(--transition-duration) var(--transition-easing),
transform var(--transition-duration) var(--transition-easing);
}
.hover-effect:hover {
opacity: var(--hover-opacity);
transform: scale(var(--hover-scale));
}
@media (prefers-color-scheme: dark) {
:root {
--hover-opacity: 0.9;
}
}Qué regla de transition se aplica cuando empieza y termina el hover
CSS Transitions Module Level 1 sigue siendo un W3C Working Draft, publicado por última vez el 8 de enero de 2026, no una recomendación final. La especificación dice que la duración, el retraso y la función de temporización salen del after-change style del elemento, es decir, del estilo hacia el que cambia. Cuando el puntero entra en la imagen, se aplica el transition de la regla :hover. Cuando el puntero sale, se aplica el transition de la regla base.
De ahí salen dos consecuencias prácticas:
- Si
transitionestá solo en:hover, la imagen se atenúa con fade, pero vuelve de golpe cuando el puntero sale, porque la regla base no tiene transición. - Puedes dar a la entrada y a la salida velocidades distintas a propósito, por ejemplo una respuesta rápida al entrar y una vuelta más tranquila.
.hover-image {
opacity: 1;
transition: opacity 0.3s ease-out; /* se usa a la vuelta */
}
.hover-image:hover {
opacity: 0.7;
transition-duration: 0.15s; /* se usa a la entrada */
}La especificación cubre también el caso en que el puntero sale antes de que termine el fade. La sección 3.1, sobre la inversión más rápida de transiciones interrumpidas, explica que una vuelta con la duración completa sobre una distancia más corta resulta asimétrica. Por eso la transición de vuelta se acorta con un factor propio (reversing shortening factor), y la función de temporización se sigue usando entera, sin saltar a la mitad de la curva. No necesitas JavaScript para calcular el tiempo restante. Fuente: CSS Transitions Module Level 1.
Un fade de opacity cuenta como movimiento según WCAG
El criterio de conformidad 2.3.3 Animation from Interactions de WCAG 2.2 (nivel AAA) exige que la animación de movimiento provocada por una interacción se pueda desactivar, salvo que sea esencial para la funcionalidad o para la información. El documento explicativo del W3C para 2.3.3 delimita el concepto: los cambios de color o de opacity que no alteran el tamaño, la forma o la posición percibidos no cuentan como animación de movimiento. Una errata quitó el desenfoque de esa excepción, así que filter: blur() ya no está incluido.
Un fade solo de opacity queda, por tanto, fuera de 2.3.3, mientras que transform: scale() cambia el tamaño percibido y queda dentro. Eso permite una regla de movimiento reducido más precisa que apagarlo todo:
@media (prefers-reduced-motion: reduce) {
.card-img {
transform: none;
transition: opacity 0.2s ease-out;
}
}MDN describe la misma técnica en la referencia de prefers-reduced-motion: una animación de escala se suaviza hasta una animación de disolución, que no desencadena trastornos vestibulares. El valor reduce se evalúa como verdadero, así que @media (prefers-reduced-motion) equivale a @media (prefers-reduced-motion: reduce).
Para el foco se aplica otro criterio. 2.4.7 Focus Visible (nivel AA) exige un indicador de foco visible, y MDN remite además a 1.4.11 Non-text Contrast, que pide un contraste mínimo de 3:1 para el indicador. Un cambio de opacity en una imagen rara vez lo cumple por sí solo, por eso el foco necesita su propio outline o box-shadow, como en el ejemplo de estados de focus.
Por qué opacity 0 no oculta un elemento
La referencia de MDN sobre opacity señala tres cosas que los efectos hover suelen pasar por alto:
- Un elemento con
opacity: 0es invisible, pero sigue en el DOM. Recibe eventos del puntero y, si está en el orden de tabulación, recibe el foco. Un botón de overlay oculto se puede pulsar y enfocar. Hazlo visible cuando recibe el foco, o desactiva los eventos del puntero conpointer-eventsy sácalo del orden de tabulación. - La opacity por sí sola no oculta contenido a los lectores de pantalla. Para eso se usan el atributo
hidden,visibilityodisplay. - Cualquier valor distinto de
1crea un nuevo stacking context. Un overlay conz-indexdentro de una tarjeta que pasa a0.9puede acabar en un orden de apilamiento distinto del esperado.
Si solo debe atenuarse el fondo, MDN recomienda un color de fondo con canal alfa en lugar de opacity en todo el elemento. Con texto sobre la imagen, el contraste entre texto y fondo tiene que seguir siendo suficiente después del fade.
Fade de entrada en la primera visualización con @starting-style
Una transition solo arranca cuando cambia un valor. MDN explica que, por defecto, las transiciones no se activan en la primera actualización de estilo del elemento, ni cuando display pasa de none a un valor visible. Una tarjeta insertada en el DOM con opacity: 1 no aparece, por tanto, con fade por sí sola.
@starting-style define los valores desde los que debe arrancar la transición. Para elementos que alternan con display: none, hace falta además transition-behavior: allow-discrete, porque display tiene un tipo de animación discreto. En la transición hacia none, el valor cambia al 100 % de la duración, así que el elemento sigue visible durante todo el fade.
.notice {
opacity: 1;
transition: opacity 0.3s ease-out;
transition: opacity 0.3s ease-out, display 0.3s allow-discrete;
}
.notice.is-hidden {
display: none;
opacity: 0;
}
@starting-style {
.notice {
opacity: 0;
}
}La primera línea de transition es intencionada: MDN escribe la propiedad dos veces para que los navegadores sin soporte de allow-discrete sigan animando la opacity. @starting-style tiene la misma especificidad que la regla original, así que debe ir después de ella. MDN marca ambas funciones como Baseline 2024. Los navegadores antiguos muestran el elemento sin fade, una alternativa aceptable para una transición puramente visual.
Cómo reaccionar al final del fade con transitionend
Cuando JavaScript solo cambia una clase y CSS hace el fade, el script puede escuchar transitionend para saber cuándo ha terminado la transición, por ejemplo antes de poner hidden o mover el foco. La página de MDN sobre transitionend y la especificación dan cuatro reglas sobre cuándo llega de verdad el evento:
transitionendse dispara en los dos sentidos: cuando el elemento alcanza el estado de hover y cuando ha vuelto por completo.- Si la transición se elimina antes de terminar, por ejemplo porque se quita
transition-propertyodisplaypasa anone, no haytransitionend. - Si se dispara
transitioncancel, por ejemplo porque el puntero sale a mitad del fade, no haytransitionendpara esa transición. - Si la duración y el retraso son ambos
0s, no existe transición y no se dispara ninguno de los eventos de transición.
La última regla es la que más falla en la práctica. Cuando prefers-reduced-motion pone transition: none, un script que espera transitionend para limpiar se queda esperando para siempre. Filtra por propertyName y prevé un camino alternativo cuando no hay transición en curso.
const reduce = matchMedia('(prefers-reduced-motion: reduce)').matches;
// En CSS: .is-fading-out { opacity: 0; }
function hideNotice(el) {
el.classList.add('is-fading-out');
if (reduce) {
el.hidden = true;
return;
}
el.addEventListener('transitionend', function onEnd(event) {
if (event.propertyName !== 'opacity') return;
el.removeEventListener('transitionend', onEnd);
el.hidden = true;
});
}Compatibilidad de navegadores con transition, focus-visible y prefers-reduced-motion
La tabla muestra la primera versión con soporte sin prefijo, según MDN browser-compat-data en la versión 8.1.6 (octubre de 2026).
| Función | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
transition | 26 | 16 | 9 | 12 |
:focus-within | 60 | 52 | 10.1 | 79 |
:focus-visible | 86 | 85 | 15.4 | 86 |
prefers-reduced-motion | 74 | 63 | 10.1 | 79 |
@media (hover) | 38 | 64 | 9 | 12 |
transition-behavior | 117 | 129 | 17.4 | 117 |
@starting-style | 117 | 129 | 17.5 | 117 |
Internet Explorer soporta transition desde la versión 10, pero ninguna de las demás funciones de la tabla. Safari tenía transition con el prefijo -webkit- desde la versión 3.1.
Hay una consecuencia de la tabla fácil de pasar por alto. En un navegador sin :focus-visible, como Safari anterior a 15.4, la regla .card-media:hover, .card-media:focus-visible se descarta entera, incluida la parte del hover. MDN explica en el artículo sobre listas de selectores que un solo selector no soportado invalida toda la lista. Escribe hover y foco como dos reglas separadas, o envuélvelos en :is(), que acepta una lista de selectores tolerante.
Resumen
Las transiciones CSS son la forma moderna y eficiente de crear efectos hover. Son ligeras, fáciles de mantener y, con :focus-visible y una regla de prefers-reduced-motion, accesibles.
Puntos clave:
- Usa propiedades específicas, no
all - 0.2-0.3s es el punto óptimo para interacciones UI
ease-outse siente más natural- Usa
transformen lugar de propiedades de posición/tamaño - Combina múltiples propiedades para efectos ricos
- Prueba en dispositivos reales para rendimiento
- Usa
@starting-stylecuando un elemento deba aparecer con fade en la primera visualización
En 2026, las transiciones CSS son el estándar para efectos hover. Las animaciones JavaScript solo son necesarias para animaciones complejas e interactivas que CSS no puede manejar.
Explora nuestro desarrollo profesional WordPress para llevar tu proyecto más lejos.







