Cree efectos de imagen receptivos con degradados CSS y relación de aspecto
Publicado: 2022-03-10aspect-ratio
recientemente admitida en combinación con object-fit
proporciona un remedio a este dolor de cabeza del pasado! Aprendamos a usar estas propiedades, además de crear un efecto de imagen de degradado receptivo para un estilo adicional.Para prepararnos para nuestros futuros efectos de imagen, configuraremos un componente de tarjeta que tiene una imagen grande en la parte superior seguida de un título y una descripción. El problema común con esta configuración es que es posible que no siempre tengamos un control perfecto sobre lo que es la imagen y, lo que es más importante, para nuestro diseño, cuáles son sus dimensiones . Y aunque esto se puede resolver recortando antes de tiempo, aún podemos encontrar problemas debido a los contenedores de tamaño receptivo. Una consecuencia son las posiciones desiguales del contenido de la tarjeta que realmente se destaca cuando presenta una fila de tarjetas.
Otra solución anterior además de recortar puede haber sido cambiar de un img
en línea a un div
en blanco que solo existía para presentar la imagen a través de una imagen background-image
. Yo mismo he implementado esta solución muchas veces en el pasado. Una ventaja que esto tiene es usar un truco más antiguo para la relación de aspecto que usa un elemento de altura cero y establece un valor padding-bottom
. Establecer un valor de relleno como un porcentaje da como resultado un valor calculado final que es relativo al ancho del elemento. Es posible que también haya utilizado esta idea para mantener una proporción de 16:9 para incrustaciones de video, en cuyo caso el valor de relleno se encuentra con la fórmula: 9/16 = 0.5625 * 100% = 56.26%
. Pero vamos a explorar dos propiedades CSS modernas que no involucran matemáticas adicionales, nos brindan más flexibilidad y también permiten mantener la semántica proporcionada al usar un img
real en lugar de un div
vacío.
Primero, definamos la semántica HTML, incluido el uso de una lista desordenada como contenedor de tarjetas:
<ul class="card-wrapper"> <li class="card"> <img src="" alt=""> <h3>A Super Wonderful Headline</h3> <p>Lorem ipsum sit dolor amit</p> </li> <!-- additional cards --> </ul>
A continuación, crearemos un conjunto mínimo de estilos de línea de base para el componente .card
. Estableceremos algunos estilos visuales básicos para la tarjeta en sí, una actualización rápida del titular h3
esperado, luego estilos esenciales para comenzar a diseñar la imagen de la tarjeta.
.card { background-color: #fff; border-radius: 0.5rem; box-shadow: 0.05rem 0.1rem 0.3rem -0.03rem rgba(0, 0, 0, 0.45); padding-bottom: 1rem; } .card > :last-child { margin-bottom: 0; } .card h3 { margin-top: 1rem; font-size: 1.25rem; } img { border-radius: 0.5rem 0.5rem 0 0; width: 100%; } img ~ * { margin-left: 1rem; margin-right: 1rem; }
La última regla usa el combinador general de hermanos para agregar un margen horizontal a cualquier elemento que sigue al img
, ya que queremos que la imagen en sí esté al ras con los lados de la tarjeta.
Y nuestro progreso hasta ahora nos lleva a la siguiente aparición de cartas:
Finalmente, crearemos los estilos .card-wrapper
para un diseño de respuesta rápida usando la cuadrícula CSS. Esto también eliminará los estilos de lista predeterminados.
.card-wrapper { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(30ch, 1fr)); grid-gap: 1.5rem; }
Nota : si esta técnica de cuadrícula no le resulta familiar, revise la explicación en mi tutorial sobre soluciones modernas para la cuadrícula de 12 columnas.
Con esto aplicado y con todas las tarjetas que contienen una imagen con una ruta de origen válida, nuestros estilos .card-wrapper
nos dan el siguiente diseño:
Como se demuestra en la imagen de vista previa, estos estilos de línea de base no son suficientes para contener correctamente las imágenes dadas sus dimensiones naturales variables. Necesitamos un método para restringir estas imágenes de manera uniforme y consistente.
Habilitar tamaños de imagen uniformes con object-fit
Como se señaló anteriormente, es posible que haya realizado previamente una actualización en este escenario para cambiar las imágenes que se agregarán a través background-image
y utilizó background-size: cover
para manejar correctamente el cambio de tamaño de la imagen. O es posible que haya intentado forzar el recorte antes de tiempo (¡todavía es un objetivo digno ya que cualquier reducción del tamaño de la imagen mejorará el rendimiento!).
Ahora, tenemos disponible la propiedad object-fit
que permite que una etiqueta img
actúe como contenedor de la imagen. Y también viene con un valor de cover
que da como resultado un efecto similar al de la solución de imagen de fondo, pero con la ventaja de conservar la semántica de una imagen en línea. Vamos a aplicarlo y ver cómo funciona.
Necesitamos emparejarlo con una dimensión de height
para obtener orientación adicional sobre cómo queremos que se comporte el contenedor de la imagen (recuerde que ya habíamos agregado width: 100%
). Y vamos a usar la función max()
para seleccionar 10rem
o 30vh
según cuál sea más grande en un contexto determinado, lo que evita que la altura de la imagen se reduzca demasiado en ventanas de visualización más pequeñas o cuando el usuario ha configurado un zoom grande.
img { /* ...existing styles */ object-fit: cover; height: max(10rem, 30vh); }
Sugerencia adicional de accesibilidad : siempre debe probar sus diseños con un zoom del 200 % y del 400 % en el escritorio. Si bien actualmente no hay una consulta de medios de zoom
, funciones como max()
pueden ayudar a resolver problemas de diseño. Otro contexto en el que esta técnica es útil es el espaciado entre elementos.
Con esta actualización, definitivamente hemos mejorado las cosas, y el resultado visual es como si usáramos la técnica anterior de imagen de fondo:
Dimensionamiento de imagen coherente con capacidad de respuesta con aspect-ratio
Cuando se usa object-fit
por sí mismo, una desventaja es que todavía necesitamos establecer algunas sugerencias de dimensión.
Una próxima propiedad (actualmente disponible en los navegadores Chromium) llamada aspect-ratio
mejorará nuestra capacidad para cambiar el tamaño de las imágenes de manera consistente.
Usando esta propiedad, podemos definir una proporción para cambiar el tamaño de la imagen en lugar de establecer dimensiones explícitas. Continuaremos usándolo en combinación con object-fit
para garantizar que estas dimensiones solo afecten a la imagen como contenedor; de lo contrario, la imagen podría aparecer distorsionada.
Aquí está nuestra regla de imagen actualizada completa:
img { border-radius: 0.5rem 0.5rem 0 0; width: 100%; object-fit: cover; aspect-ratio: 4/3; }
Vamos a comenzar con una proporción de imagen de 4 ⁄ 3 para el contexto de nuestra tarjeta, pero puede elegir cualquier proporción. Por ejemplo, 1 ⁄ 1 para un cuadrado o 16 ⁄ 9 para incrustaciones de video estándar.
Aquí están las tarjetas actualizadas, aunque probablemente será difícil notar la diferencia visual en este caso en particular, ya que la relación de aspecto coincide con la apariencia que logramos al configurar la height
solo para el ajuste del object-fit
.
Establecer una "relación de aspecto" da como resultado que la proporción se mantenga a medida que los elementos crecen o se reducen, mientras que cuando solo se establece "ajuste del objeto" y "altura", la proporción de la imagen cambiará constantemente a medida que cambien las dimensiones del contenedor.
“
Adición de efectos receptivos con degradados y funciones CSS
Bien, ahora que sabemos cómo configurar imágenes de tamaño constante, ¡divirtámonos con ellas agregando un efecto de degradado!
Nuestro objetivo con este efecto es hacer que parezca que la imagen se desvanece en el contenido de la tarjeta. Es posible que tenga la tentación de envolver la imagen en su propio contenedor para agregar el degradado, pero gracias al trabajo que ya hemos hecho en el tamaño de la imagen, podemos averiguar cómo hacerlo de manera segura en la .card
principal.
El primer paso es definir un degradado . Vamos a usar una propiedad personalizada de CSS para agregar los colores degradados para permitir cambiar fácilmente el efecto degradado, comenzando con un azul a rosa. El último color del degradado siempre será blanco para mantener la transición al fondo del contenido de la tarjeta y crear el borde "desvanecido".
.card { --card-gradient: #5E9AD9, #E271AD; background-image: linear-gradient( var(--card-gradient), white max(9.5rem, 27vh) ); /* ...existing styles */ }
Pero espera, ¿es una función CSS max()
? ¿En un gradiente? ¡Sí, es posible, y es la magia lo que hace que este gradiente sea efectivo de manera receptiva!
Sin embargo, si tuviera que agregar una captura de pantalla, todavía no veríamos que el degradado tiene ningún efecto en la imagen. Para eso, necesitamos incorporar la propiedad mix-blend-mode
, y en este escenario usaremos el valor de overlay
:
img { /* ...existing styles */ mix-blend-mode: overlay; }
La propiedad mix-blend-mode
es similar a aplicar los estilos de fusión de capas disponibles en software de manipulación de fotografías como Photoshop. Y el valor de overlay
tendrá el efecto de permitir que los tonos medios de la imagen se mezclen con el degradado que hay detrás, lo que dará como resultado el siguiente resultado:
Ahora, en este punto, confiamos únicamente en el valor aspect-ratio
para cambiar el tamaño de la imagen. Y si cambiamos el tamaño del contenedor y hacemos que el diseño de la tarjeta se redistribuya, el cambio de altura de la imagen provoca inconsistencias en el lugar donde el degradado se desvanece a blanco.
Así que también agregaremos una propiedad max-height
que también usa la función max()
y contiene valores ligeramente mayores que los del degradado. El comportamiento resultante es que el degradado (casi siempre) se alineará correctamente con la parte inferior de la imagen.
img { /* ...existing styles */ max-height: max(10rem, 30vh); }
Es importante tener en cuenta que agregar una `altura máxima` altera el comportamiento de la `relación de aspecto`. En lugar de usar siempre la proporción exacta, se usará solo cuando haya suficiente espacio asignado dada la nueva restricción adicional de `max-height`.
“
Sin embargo, aspect-ratio
continuará asegurando que las imágenes cambien de tamaño de manera consistente, como lo fue el beneficio sobre solo object-fit
. Intente comentar la aspect-ratio
en la demostración final de CodePen para ver la diferencia que está haciendo en los tamaños de los contenedores.
Dado que nuestro objetivo original era habilitar dimensiones de imagen receptivas consistentes, aun así hemos dado en el blanco. Para su propio caso de uso, es posible que deba jugar con los valores de proporción y altura para lograr el efecto deseado.
Alternativo: mix-blend-mode
y agregar un filtro
El uso de la overlay
como el valor mix-blend-mode
fue la mejor opción para el efecto de fundido a blanco que buscábamos, pero probemos una opción alternativa para un efecto más dramático.
Vamos a actualizar nuestra solución para agregar una propiedad personalizada de CSS para el valor mix-blend-mode
y también actualizar los valores de color para el degradado:
.card { --card-gradient: tomato, orange; --card-blend-mode: multiply; } img { /* ...existing styles */ mix-blend-mode: var(--card-blend-mode); }
El valor de multiply
tiene un efecto de oscurecimiento en los tonos medios, pero mantiene el blanco y el negro tal cual, lo que da como resultado la siguiente apariencia:
Si bien hemos perdido el desvanecimiento y ahora tenemos un borde duro en la parte inferior de la imagen, la parte blanca de nuestro degradado sigue siendo importante para garantizar que el degradado finalice antes que el contenido de la tarjeta.
Una modificación adicional que podemos agregar es el uso del filter
y, en particular, usar la función grayscale()
para eliminar los colores de la imagen y, por lo tanto, hacer que el degradado sea la única fuente de coloración de la imagen.
img { /* ...existing styles */ filter: grayscale(100); }
El uso del valor de escala de grayscale(100)
da como resultado la eliminación completa de los colores naturales de la imagen y la transforma en blanco y negro. Aquí está la actualización para compararla con la captura de pantalla anterior de su efecto al usar nuestro degradado naranja con multiply
:
Use aspect-ratio
como una mejora progresiva
Como se mencionó anteriormente, actualmente aspect-ratio
solo es compatible con la última versión de los navegadores Chromium (Chrome y Edge). Sin embargo, todos los navegadores admiten object-fit
y eso, junto con nuestras restricciones de height
, da como resultado un resultado menos ideal pero aún aceptable, que se ve aquí para Safari:
Sin el funcionamiento de la aspect-ratio
, el resultado aquí es que, en última instancia, la altura de la imagen está limitada, pero las dimensiones naturales de cada imagen aún conducen a alguna variación entre las alturas de la imagen de la tarjeta. Es posible que desee cambiar para agregar una max-height
o utilizar la función max()
nuevamente para ayudar a que max-height
responda mejor a los diferentes tamaños de tarjeta.
Extendiendo los efectos de degradado
Dado que definimos las paradas de color del degradado como una propiedad personalizada de CSS, tenemos acceso inmediato para cambiarlas en diferentes contextos. Por ejemplo, podríamos cambiar el degradado para que presente uno de los colores con más fuerza si la tarjeta está sobrevolada o tiene uno de sus elementos secundarios enfocado.
Primero, actualizaremos cada tarjeta h3
para que contenga un enlace, como:
<h3><a href="">A Super Wonderful Headline</a></h3>
Luego, podemos usar uno de nuestros selectores disponibles más nuevos, :focus-within
, para modificar el degradado de la tarjeta cuando el enlace está enfocado. Para una cobertura adicional de posibles interacciones, combinaremos esto con :hover
. Y reutilizaremos nuestra idea de max()
para asignar un solo color para cubrir la parte de la imagen de la tarjeta. La desventaja de este efecto en particular es que las paradas de degradado y los cambios de color no se pueden animar de manera confiable, pero pronto lo serán gracias a CSS Houdini.
Para actualizar el color y agregar la nueva parada de color, solo necesitamos reasignar el valor de --card-gradient
dentro de esta nueva regla:
.card:focus-within, .card:hover { --card-gradient: #24a9d5 max(8.5rem, 20vh); }
Nuestros valores max()
son menores que los originales en uso para white
para mantener el borde difuminado. Si usáramos los mismos valores, se encontraría con el white
y crearía una separación claramente en regla.
Al crear esta demostración, originalmente probé un efecto que usaba transform
con scale
para un efecto de acercamiento. Pero descubrí que debido a que se aplicó el mix-blend-mode
, el navegador no volvía a pintar la imagen de manera consistente, lo que causaba un parpadeo desagradable. Siempre habrá compensaciones al solicitar que el navegador realice efectos y animaciones solo de CSS, y si bien es genial lo que podemos hacer, siempre es mejor verificar el impacto en el rendimiento de sus efectos.
¡Diviértete experimentando!
El CSS moderno nos ha brindado algunas herramientas increíbles para actualizar nuestros kits de herramientas de diseño web, siendo la aspect-ratio
la última incorporación. ¡Así que continúe y experimente con object-fit
, aspect-ratio
y agregue funciones como max()
en sus gradientes para obtener algunos efectos de respuesta divertidos! Solo asegúrese de verificar las cosas entre navegadores (¡por ahora!) Y en diferentes ventanas gráficas y tamaños de contenedores.
Aquí está CodePen, incluidas las características y los efectos que revisamos hoy:
¿Buscando por mas? Asegúrate de consultar nuestra Guía CSS aquí en Smashing →