Magic Flip Cards: Resolviendo un problema común de tamaño
Publicado: 2022-03-10¿Cuáles son las posibilidades de que su próximo cliente use la palabra interactivo al presentar su proyecto? Según mi experiencia, la respuesta es 100 % , por lo que siempre busco técnicas sólidas de CSS que me ayuden a ofrecer las diversas funciones y efectos que surgen cuando se habla de este objetivo.
Una pequeña pieza de interactividad que me piden que implemente una y otra vez son las tarjetas invertidas: bloques de contenido que giran cuando se mueven o se tocan para revelar contenido en su reverso. Es un efecto limpio que fomenta la navegación divertida y otra forma de mostrar más información sin salir de la página. Pero el método estándar tiene un problema cuando se trata de acomodar diferentes longitudes de contenido de tarjeta.
En este tutorial, vamos a crear una cuadrícula de tarjeta invertida que resuelve ese problema con algunos conceptos básicos de CSS: transformaciones, flexibilidad y cuadrícula. Deberá estar familiarizado con estos, y le ayudará tener una buena comprensión de las técnicas de posicionamiento de CSS. Cubriremos:
- Cómo se implementan normalmente las tarjetas invertidas mediante el posicionamiento absoluto;
- El problema de tamaño que introduce el posicionamiento absoluto; y
- Una solución general para el dimensionamiento automático del contenido superpuesto.
Creación de una tarjeta invertida básica
Con un buen soporte de navegador moderno para transformaciones tridimensionales, crear una tarjeta invertida básica es relativamente sencillo. El método habitual es colocar las caras delantera y trasera de la tarjeta en un contenedor principal, y posicionar absolutamente la cara trasera para que coincida con el tamaño de la cara delantera. Agregue una transformación del eje x a la cara posterior para que parezca invertida, agregue otra a la tarjeta al pasar el mouse y estamos en el negocio.
.cards { display: grid; } .card { perspective: 40rem; } .card-body { transform-style: preserve-3d; transition: var(--time) transform; .card:hover & { transform: rotateX(-180deg); } } .card-front, .card-back { backface-visibility: hidden; } .card-back { position: absolute; top: 0; right: 0; bottom: 0; left: 0; transform: rotateX(-180deg); }
¿Qué puede salir mal?
Sin embargo, nuestra solución estándar tiene un gran problema: no funciona cuando la cara posterior necesita más espacio del que proporciona la cara frontal. Darle a la tarjeta un tamaño grande y fijo es una solución, pero también se garantiza que ese enfoque fallará en algún momento para algunos conjuntos de tamaños de pantalla.
Las composiciones de diseño cuentan naturalmente con cuadros de aspecto pulcro con texto que encaja a la perfección. Pero al comenzar el desarrollo, puede ser difícil obtener un diseño de página y tarjeta que funcione para el contenido real. Y al mostrar contenido dinámico desde un CMS, ¡puede ser imposible! Incluso con límites de palabras o caracteres, a menudo no existe una solución que funcione de manera confiable en todos los dispositivos.
Siempre debemos esforzarnos por crear implementaciones de diseño que toleren una amplia gama de longitudes de contenido. ¡Pero no es fácil! A menudo he tenido la oportunidad de recurrir al uso de tamaños y posiciones fijos, ya sea por limitaciones de tiempo, compatibilidad insuficiente con el navegador, un diseño de referencia débil o simplemente mi propia inexperiencia.
A lo largo de los años, aprendí que un buen proceso iterativo y un diálogo saludable con el diseñador pueden ser de gran ayuda al resolver estos problemas y, a menudo, pueden encontrarse en algún punto intermedio para obtener un diseño sólido con algo de interactividad. Pero volviendo a la tarea en cuestión: ¿se puede hacer?
Pensar más allá
De hecho, es posible cambiar el tamaño de las tarjetas según el contenido del anverso y el reverso, y no es tan difícil como parece al principio. ¡Solo necesitamos ser metódicos y persistentes!
Restricción del problema
Comencemos por hacer una lista de los requisitos de nuestro diseño. Tratar de escribir con precisión lo que desea puede parecer una tarea ardua, pero es una excelente manera de descubrir restricciones que se pueden simplificar para resolver un problema. Digamos:
- Queremos ver una o más tarjetas rectangulares, dispuestas en una cuadrícula de una o varias columnas;
- Queremos que las tarjetas se den la vuelta al pasar el mouse por encima o tocar para revelar un segundo conjunto de contenido en la cara posterior;
- Queremos que las tarjetas sean siempre lo suficientemente grandes para mostrar todo el contenido del anverso y el reverso, independientemente de la longitud o el estilo del contenido; y
- En el caso de varias columnas, idealmente, queremos que todas las tarjetas tengan el mismo tamaño para que las filas se alineen bien.
Pensando en estos requisitos, podemos notar un par de cosas que simplifican el problema:
- Si las tarjetas se van a presentar en una cuadrícula, tenemos una restricción en su ancho, es decir, sus anchos son funciones de la ventana gráfica o del contenedor de la cuadrícula en lugar de su propio contenido;
- Dado que conocemos el ancho de una tarjeta (como un porcentaje de su padre, al menos), hemos resuelto la dimensión horizontal y solo necesitamos que la altura de la tarjeta se expanda para que se ajuste a la más alta de su cara frontal o trasera; y
- Si podemos hacer eso y cada tarjeta tiene su propio tamaño vertical, podemos usar
grid-auto-rows
de CSS Grid para hacer que todas las filas de tarjetas sean tan altas como la tarjeta más alta.
Averiguar el truco de las cartas
Entonces, ¿cómo ajustamos el tamaño de las tarjetas? Ahora que hemos simplificado nuestro problema, estamos al alcance de la solución.
Olvídese, por un momento, de la idea de poner contenido encima de otro contenido y concéntrese en nuestro nuevo requisito: un padre que sea tan alto como su hijo más alto. ¡Eso es fácil! Usando columnas, podemos hacer que un padre se expanda a la altura de su hijo más alto. Luego, solo necesitamos emplear un poco de prestidigitación para alinear a los niños:
- Establecer que los niños tengan el mismo ancho que su padre
- Permita que el segundo niño se desborde a la derecha
- Transfórmalo hacia la izquierda de nuevo en su lugar apropiado
.cards { display: grid; } .card-body { display: flex; } .card-front, .card-back { min-width: 100%; mix-blend-mode: multiply; // Preview both faces } .card-back { transform: translate(-100%, 0); }
Si este enfoque parece obvio, tenga la seguridad de que pasé muchas horas analizando algunas ideas realmente terribles antes de pensar en ello. Al principio, había planeado imprimir una versión duplicada oculta del texto de la cara posterior dentro de la cara frontal para expandir la tarjeta al tamaño correcto. Y cuando pensé en usar el desbordamiento de columna, originalmente estaba recortando la columna de la derecha usando overflow:hidden
y transformándola solo en el último momento cuando comenzó el desplazamiento, ya que aún no me había dado cuenta de que podía mantenerla transformada. desde el principio y use otro método, como la opacity
o backface-visibility
para activarlo y desactivarlo según sea necesario.
En otras palabras, ¡las soluciones obvias son el resultado del trabajo duro! Si siente que ha estado golpeándose la cabeza contra su escritorio durante horas por un problema de diseño, es importante dar un paso atrás y decidir si está usando el tiempo de su cliente sabiamente: si sugerirle que modifique el diseño y si para buscar la solución en su propio tiempo como un ejercicio de aprendizaje cuando no hay presión. Pero cuando encuentre métodos simples, nunca se sienta estúpido porque tomó mucho tiempo . Ahora, revisemos nuestra solución completa.
.cards { display: grid; } .card { perspective: 40rem; } .card-body { display: flex; transform-style: preserve-3d; transition: var(--time) transform; .card:hover & { transform: rotateX(-180deg); } } .card-front, .card-back { backface-visibility: hidden; min-width: 100%; } .card-back { transform: rotateX(-180deg) translate(-100%, 0); }
¿Hay alguna advertencia?
La solución funciona bien en general, con solo algunas advertencias menores a tener en cuenta:
- Las tarjetas deben estar presentes en un diseño de cuadrícula o en algún otro contexto donde sus anchos no dependan del contenido.
- Las tarjetas requieren una envoltura de contenido de algún tipo (nuestro
card-body
) para que el área flotante no cambie durante las animaciones. Si la tarjeta en sí está animada, verá algunas fallas a medida que la animación se detiene y reinicia rápidamente. - Los estilos, como los fondos y las sombras de los recuadros, se colocan mejor directamente en las caras delantera y trasera, ya que los efectos de la tarjeta en sí no se animarán. Tenga cuidado con el estilo, como las sombras de los cuadros en el cuerpo de la tarjeta, ya que, naturalmente, se voltearán al revés.
- El anverso y el reverso de las tarjetas necesitan que su propiedad
box-sizing
se establezca enborder-box
si tienen su propio relleno, debido a su requisitomin-width
, de lo contrario, se desbordarán. - Safari aún requiere
-webkit-backface-visibility
, en su forma prefijada por el proveedor.
Agregar algo de esmalte
Ahora que hemos resuelto el problema difícil, veamos un par de ajustes que podemos hacer para que toda la interacción funcione de la mejor manera posible.
Primero, verifique si las cartas se superponen al voltearlas. Esto dependerá de si está utilizando varias columnas, el ancho de la medianil de la columna, la orientación del giro y el valor de perspectiva de la tarjeta, pero es probable que suceda. Puede aumentar la duración de la animación para ver las cosas con mayor claridad. Al pasar el mouse, parece poco natural que la tarjeta sobrevolada se voltee debajo de sus vecinos posteriores, por lo que debemos colocarla en la parte superior usando z-index
. Bastante fácil, pero ¡cuidado! Necesitamos esperar hasta que se complete la animación saliente antes de restaurar el z-index
. Ingrese transition-delay
:
.card { transition: z-index; transition-delay: var(--time); z-index: 0; &:hover { transition-delay: 0s; z-index: 1; } }
A continuación, considere crear un estado activo para las tarjetas. Por lo general, trato de hacer que las tarjetas como estas se vinculen a algún lugar relevante, incluso si no lo especifica el diseñador, ya que los elementos con efectos de desplazamiento como este se sienten muy táctiles, por lo que es bueno proporcionar un destino para los lectores que prueban suerte. Me gusta una transformación de escala corta y sutil, ya que funciona razonablemente bien ya sea que la segunda mitad de la animación se corte o no al cargar la página de destino (aunque me encantaría que los navegadores completaran las animaciones en vuelo limpiamente antes de la navegación). Estoy seguro de que sería mucho más difícil de implementar en la práctica de lo que parece).
Esta es también una gran oportunidad para pensar qué tan accesible es el contenido del reverso de nuestras tarjetas. Nuestro marcado es conciso y está bien ordenado, por lo que cubrimos lectores de pantalla y otros casos de uso que ignoran el estilo, pero ¿qué pasa con los usuarios de teclado? Si vamos a hacer que las tarjetas en sí sean anclas, recibirán el foco a medida que los usuarios del teclado tabulan a través de la página. Reutilicemos el estado de desplazamiento de la tarjeta como estado de enfoque, y el contenido posterior aparecerá de forma natural durante la exploración del teclado.
.card { transition: z-index, transform calc(var(--time) / 4); transition-delay: var(--time), 0s; z-index: 0; &:hover { transition-delay: 0s; z-index: 1; } &:active { transform: scale(0.975); } } .card-body { .card:hover &, .card:focus & { transform: rotateX(-180deg); } }
Finalmente, no olvide que ahora la tarjeta se escala automáticamente para adaptarse a su contenido, puede usar prácticamente cualquier técnica de alineación y espaciado que desee dentro de los contenedores frontal y posterior. Use la alineación flexible para centrar títulos, agregue relleno e incluso coloque otra cuadrícula dentro de la tarjeta. Esta es la belleza de las buenas soluciones de diseño que escalan con su contenido: acoplamiento reducido de niños a padres y la modularidad que le permite concentrarse en una cosa a la vez.
.card-front, .card-back { display: flex; align-items: center; background-color: white; box-shadow: 0 5px 10px black; border-radius: 0.25rem; padding: 1.5rem; }
Terminando
¡Espero que encuentres útil esta técnica CSS! ¿Por qué no probar algunas variaciones en la animación, como un efecto de escala o un simple fundido cruzado? La técnica tampoco se limita al factor de forma de las tarjetas. Se puede utilizar en cualquier lugar donde la responsabilidad del dimensionamiento vertical recaiga en más de un elemento. Imagine el sitio web de una revista con fotografías grandes con subtítulos superpuestos: puede usarlo para acomodar tanto imágenes con relaciones de aspecto altas como texto largo y dinámico.
Sobre todo, recuerde los beneficios de tomarse un tiempo para pensar detenidamente si existe una forma de implementar un diseño que parezca que solo funcionaría con un tamaño y una posición fijos. A menudo, lo hay, y no importa cuán complicado pueda parecer el problema al principio, escribir todos sus requisitos, reservar algo de tiempo para crear un caso de prueba mínimo y recorrerlo metódicamente es siempre la mejor opción.