Un elegante efecto de desplazamiento para tu avatar

Un elegante efecto de desplazamiento para tu avatar |  consejos CSS

 

¿Conoces este tipo de efecto en el que la cabeza de alguien pasa por un círculo o un agujero? La famosa animación de Porky Pig donde se despide mientras sale de una serie de anillos rojos es el ejemplo perfecto, y Kilian Valkhof la recreó aquí en CSS-Tricks hace un tiempo.

Tengo una idea similar pero abordada de una manera diferente y con una pizca de animación. Creo que es bastante útil y brinda un efecto de desplazamiento que puedes usar en algo como tu propio avatar.

 

¿Mira esto? Vamos a crear una animación de escala donde el avatar parece salir del círculo en el que se encuentra. ¿Guay, verdad? No mires el código y construyamos juntos esta animación paso a paso.

HTML: un solo elemento

Si no ha revisado el código de demostración y se pregunta cuánto divs tomará, luego deténgase allí, porque nuestro marcado no es más que un elemento de imagen único:

<img src="" alt="">

¡Sí, sólo un elemento! La parte difícil de este ejercicio es usar la menor cantidad de código posible. Si me has estado siguiendo por un tiempo, deberías estar acostumbrado a esto. Me esfuerzo por encontrar soluciones CSS que se puedan hacer con el código más pequeño y fácil de mantener posible.

He escrito una serie de artículos aquí sobre CSS-Tricks donde exploro diferentes efectos de desplazamiento utilizando el mismo marcado HTML de un solo elemento. Entro en gran detalle en degradados, máscaras, recortes, contornos e incluso técnicas de diseño. Recomiendo encarecidamente echarles un vistazo, ya que reutilizaré muchos consejos en este artículo.

Un archivo de imagen cuadrado con un fondo transparente funcionará mejor para lo que estamos haciendo. Aquí está el que uso si quieres empezar con eso.

por Cang

Espero ver muchos ejemplos de esto posible usando imágenes reales, así que cuando termines, comparte tu resultado final en los comentarios para que podamos crear una colección.

Antes de saltar a CSS, primero analicemos el efecto. La imagen se expande al pasar el mouse, por lo que seguramente usaremos transform: scale() ahí. Hay un círculo detrás del avatar y un degradado radial debería funcionar. Finalmente, necesitamos una forma de crear un borde en la parte inferior del círculo que cree la apariencia del avatar detrás del círculo.

¡Pongámonos a trabajar!

El efecto de escala

Comencemos agregando la transformación:

img {
  width: 280px;
  aspect-ratio: 1;
  cursor: pointer;
  transition: .5s;
}
img:hover {
  transform: scale(1.35);
}

Nada demasiado complicado por el momento, ¿verdad? Vamos a salir de aquí.

El círculo

Dijimos que el fondo sería un degradado radial. Esto es perfecto porque podemos crear paradas duras entre los colores de un degradado radial, haciendo que parezca que estamos dibujando un círculo con líneas continuas.

img {
  --b: 5px; /* border width */

  width: 280px;
  aspect-ratio: 1;
  background:
    radial-gradient(
      circle closest-side,
      #ECD078 calc(99% - var(--b)),
      #C02942 calc(100% - var(--b)) 99%,
      #0000
    );
  cursor: pointer;
  transition: .5s;
}
img:hover {
  transform: scale(1.35);
}

Tenga en cuenta la variable CSS, --b, Yo uso allí. Representa el grosor del "borde" que en realidad solo se usa para definir las paradas de color duro para la parte roja del degradado radial.

El siguiente paso es jugar con el tamaño del gradiente de desplazamiento. El círculo debe mantener su tamaño a medida que crece la imagen. Ya que aplicamos un scale() transformación, en realidad tenemos que disminuir el tamaño del círculo porque de lo contrario crece con el avatar. Entonces, a medida que la imagen crece, necesitamos que el degradado se reduzca.

Comencemos definiendo una variable CSS, --f, que establece el "factor de escala", y utilícelo para establecer el tamaño del círculo. yo suelo 1 por defecto, ya que es la escala inicial de la imagen y el círculo a partir del cual estamos transformando.

Aquí hay una demostración para ilustrar el truco. Pase el cursor para ver lo que sucede detrás de escena:

Agregué un tercer color al radial-gradient para identificar mejor el área de degradado al pasar el mouse:

radial-gradient(
  circle closest-side,
  #ECD078 calc(99% - var(--b)),
  #C02942 calc(100% - var(--b)) 99%,
  lightblue
);

Ahora debemos colocar nuestro fondo en el centro del círculo y asegurarnos de que ocupe toda la altura. Me gusta declarar todo directamente en el background propiedad acortada, por lo que podemos agregar nuestro posicionamiento de fondo y asegurarnos de que no se repita aplicando estos valores justo después de la radial-gradient():

background: radial-gradient() 50% / calc(100% / var(--f)) 100% no-repeat;

El fondo se coloca en el centro (50%), tiene un ancho igual a calc(100%/var(--f))y tiene una altura igual a 100%.

Nada cambia cuando --f es igual a 1 — de nuevo, nuestra escala inicial. Mientras tanto, el degradado ocupa todo el ancho del contenedor. cuando aumentamos --fel tamaño del elemento aumenta — gracias a la scale() transform — y el tamaño del gradiente disminuye.

Esto es lo que obtenemos cuando aplicamos todo esto a nuestra demostración:

Nos estamos acercando ! Tenemos el efecto de desbordamiento en la parte superior, pero aún necesitamos ocultar la parte inferior de la imagen, para que parezca que sale del círculo en lugar de sentarse al frente. Esa es la parte difícil de todo y eso es lo que haremos a continuación.

El borde inferior

Primero traté de resolver este problema con el border-bottom propiedad, pero no pude encontrar una manera de hacer coincidir el tamaño del borde con el tamaño del círculo. Esto es lo mejor que pude obtener y puede ver de inmediato que está mal:

La verdadera solución es usar el outline propiedad. Sí, outlineno border. En un artículo anterior, mostré cómo outline es poderoso y nos permite crear efectos de desplazamiento geniales. Combinado con outline-offsettenemos exactamente lo que necesitamos para nuestro efecto.

La idea es establecer un outline sobre la imagen y ajuste su desplazamiento para crear el borde inferior. El desplazamiento dependerá del factor de escala de la misma manera que el tamaño del degradado.

Ahora tenemos nuestro "borde" inferior (en realidad, un outline) combinado con el "borde" creado por el degradado para crear un círculo completo. Todavía tenemos que ocultar partes de la outline (desde la parte superior y los lados), a lo que llegaremos en un momento.

Aquí está nuestro código hasta el momento, incluidas algunas variables CSS adicionales que puede usar para configurar el tamaño de la imagen (--s) y el color del "borde" (--c):

img {
  --s: 280px; /* image size */
  --b: 5px; /* border thickness */
  --c: #C02942; /* border color */
  --f: 1; /* initial scale */

  width: var(--s);
  aspect-ratio: 1;
  cursor: pointer;
  border-radius: 0 0 999px 999px;
  outline: var(--b) solid var(--c);
  outline-offset: calc((1 / var(--f) - 1) * var(--s) / 2 - var(--b));
  background: 
    radial-gradient(
      circle closest-side,
      #ECD078 calc(99% - var(--b)),
      var(--c) calc(100% - var(--b)) 99%,
      #0000
    ) 50% / calc(100% / var(--f)) 100% no-repeat;
  transform: scale(var(--f));
  transition: .5s;
}
img:hover {
  --f: 1.35; /* hover scale */
}

Como necesitamos un borde inferior circular, agregamos un border-radius en la parte inferior, lo que permite outline para que coincida con la curvatura del gradiente.

El cálculo utilizado en outline-offset es mucho más simple de lo que parece. Por defecto, outline se tira afuera de la caja del artículo. Y en nuestro caso, lo necesitamos para conducir el objeto. Específicamente, necesitamos que siga el círculo creado por el degradado.

Diagrama de la transición de fondo.

Cuando cambiamos el tamaño del elemento, vemos el espacio entre el círculo y el borde. No olvidemos que la idea es mantener el círculo del mismo tamaño después de realizar la transformación de escala, lo que nos da el espacio que usaremos para definir el desplazamiento del contorno como se muestra en la figura de arriba.

No olvidemos que el segundo elemento está escalado, por lo que nuestro resultado también está escalado... lo que significa que debemos dividir el resultado por f para obtener el valor de compensación real:

Offset = ((f - 1) * S/2) / f = (1 - 1/f) * S/2

Agregamos un signo negativo porque necesitamos que el contorno vaya de afuera hacia adentro:

Offset = (1/f - 1) * S/2

Aquí hay una demostración rápida que muestra cómo el contorno sigue el degradado:

Es posible que ya vea esto, pero aún necesitamos que el contorno inferior se superponga al círculo en lugar de dejar que se desangre. Podemos hacer esto eliminando el tamaño del borde del desplazamiento:

outline-offset: calc((1 / var(--f) - 1) * var(--s) / 2) - var(--b));

Ahora tenemos que averiguar cómo eliminar la parte superior del contorno. En otras palabras, solo queremos la parte inferior de la imagen. outline.

Primero, agreguemos algo de espacio en la parte superior con algo de relleno para evitar la superposición en la parte superior:

img {
  --s: 280px; /* image size */
  --b: 5px;   /* border thickness */
  --c: #C02942; /* border color */
  --f: 1; /* initial scale */

  width: var(--s);
  aspect-ratio: 1;
  padding-block-start: calc(var(--s)/5);
  /* etc. */
}
img:hover {
  --f: 1.35; /* hover scale */
}

No hay una lógica particular para este relleno superior. La idea es asegurarse de que el contorno no toque la cabeza del avatar. Usé el tamaño del elemento para definir este espacio para tener siempre la misma proporción.

Tenga en cuenta que agregué el content-box valor en background:

background:
  radial-gradient(
    circle closest-side,
    #ECD078 calc(99% - var(--b)),
    var(--c) calc(100% - var(--b)) 99%,
    #0000
  ) 50%/calc(100%/var(--f)) 100% no-repeat content-box;

Necesitamos esto porque agregamos relleno y solo queremos que el fondo se establezca en el área de contenido, por lo que debemos decirle explícitamente al fondo que se detenga allí.

Agregue una máscara CSS a la mezcla

¡Hemos llegado a la última parte! Todo lo que tenemos que hacer es esconder algunas piezas y listo. Para ello, nos apoyaremos mask propiedad y, por supuesto, gradientes.

Aquí hay una figura para ilustrar qué ocultar o qué mostrar para ser más precisos

Mostrando cómo se aplica la máscara a la parte inferior del círculo.

La imagen de la izquierda es lo que tenemos actualmente y la de la derecha es lo que queremos. La parte verde ilustra la máscara que debemos aplicar a la imagen original para obtener el resultado final.

Podemos identificar dos partes de nuestra máscara:

  • Una parte circular en la parte inferior que tiene la misma dimensión y curvatura que el degradado radial que usamos para crear el círculo detrás del avatar.
  • Un rectángulo en la parte superior que cubre el área dentro del contorno. Observe cómo el contorno está fuera del área verde en la parte superior: esta es la parte más importante, ya que corta el contorno para que solo se vea la parte inferior.

Aquí está nuestro CSS final:

img {
  --s: 280px; /* image size */
  --b: 5px; /* border thickness */
  --c: #C02942; /* border color */
  --f: 1; /* initial scale */

  --_g: 50% / calc(100% / var(--f)) 100% no-repeat content-box;
  --_o: calc((1 / var(--f) - 1) * var(--s) / 2 - var(--b));

  width: var(--s);
  aspect-ratio: 1;
  padding-top: calc(var(--s)/5);
  cursor: pointer;
  border-radius: 0 0 999px 999px;
  outline: var(--b) solid var(--c);
  outline-offset: var(--_o);
  background: 
    radial-gradient(
      circle closest-side,
      #ECD078 calc(99% - var(--b)),
      var(--c) calc(100% - var(--b)) 99%,
      #0000) var(--_g);
  mask:
    linear-gradient(#000 0 0) no-repeat
    50% calc(-1 * var(--_o)) / calc(100% / var(--f) - 2 * var(--b)) 50%,
    radial-gradient(
      circle closest-side,
      #000 99%,
      #0000) var(--_g);
  transform: scale(var(--f));
  transition: .5s;
}
img:hover {
  --f: 1.35; /* hover scale */
}

vamos a desglosarlo mask propiedad. Para empezar, tenga en cuenta que un radial-gradient() de background la propiedad está ahí. Creé una nueva variable, --_gpara áreas comunes para hacer las cosas menos engorrosas.

--_g: 50% / calc(100% / var(--f)) 100% no-repeat content-box;

mask:
  radial-gradient(
    circle closest-side,
    #000 99%,
    #0000) var(--_g);

Entonces hay un linear-gradient() también dentro:

--_g: 50% / calc(100% / var(--f)) 100% no-repeat content-box;

mask:
  linear-gradient(#000 0 0) no-repeat
    50% calc(-1 * var(--_o)) / calc(100% / var(--f) - 2 * var(--b)) 50%,
  radial-gradient(
    circle closest-side,
    #000 99%,
    #0000) var(--_g);

Esto crea la parte rectangular de la máscara. Su ancho es igual al ancho del degradado radial menos el doble del grosor del borde:

calc(100% / var(--f) - 2 * var(--b))

La altura del rectángulo es igual a la mitad, 50%el tamaño del elemento.

También necesitamos el gradiente lineal colocado en el centro horizontal (50%) y desplazado desde la parte superior por la misma cantidad que el desplazamiento del contorno. Creé otra variable CSS, --_opara el desplazamiento definido anteriormente:

--_o: calc((1 / var(--f) - 1) * var(--s) / 2 - var(--b));

Una de las cosas confusas aquí es que necesitamos un negativo desplazamiento para el contorno (para moverlo de afuera hacia adentro) pero un positivo compensación para el gradiente (para moverse hacia arriba y hacia abajo). Entonces, si se pregunta por qué estamos multiplicando la compensación, --_opor -1¡bien ahora lo sabes!

Aquí hay una demostración para ilustrar la configuración de gradiente de máscara:

Pase el cursor sobre lo anterior y vea cómo se mueve todo junto. El cuadro central muestra la capa de máscara formada por dos degradados. Imagínelo como la parte visible de la imagen de la izquierda, ¡y obtendrá el resultado final a la derecha!

Envoltura

¡Uf, hemos terminado! Y no solo terminamos con una animación de desplazamiento suave, sino que lo hicimos todo con solo un HTML <img> elemento. ¡Solo eso y menos de 20 líneas de trucos CSS!

Por supuesto, nos basamos en algunos pequeños trucos y fórmulas matemáticas para lograr un efecto tan complejo. Pero sabíamos exactamente qué hacer ya que habíamos identificado las piezas que necesitábamos desde el principio.

¿Podríamos haber simplificado el CSS si nos hubiéramos permitido más HTML? Absolutamente. ¡Pero estamos aquí para aprender nuevos trucos de CSS! Fue un buen ejercicio para explorar gradientes CSS, enmascaramiento, outline comportamiento de propiedades, transformaciones y más. Si alguna vez te has sentido perdido, echa un vistazo a mi serie que utiliza los mismos conceptos generales. A veces ayuda ver más ejemplos y casos de uso para recalcar el punto.

Los dejo con una última demostración que usa fotos de desarrolladores populares de CSS. ¡No olvides mostrarme una demostración con tu propia imagen para que pueda agregarla a la colección!

Si quieres conocer otros artículos parecidos a Un elegante efecto de desplazamiento para tu avatar puedes visitar la categoría Estilo.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir

Esta página web utiliza cookies para analizar de forma anónima y estadística el uso que haces de la web, mejorar los contenidos y tu experiencia de navegación. Para más información accede a la Política de Cookies . Ver mas