Recrear animaciones de Google Géminis para Gmail
Siempre veo este botón Google Gemini en la esquina de Gmail. Cuando se desplaza sobre él, realiza esta animación genial donde los giros de las estrellas de cuatro puntos y las formas externas también variaron entre varias formas diferentes, que también están girando.

Me desafío a recrear el botón usando nuevo CSS shape() La función es animarla para acercar las cosas. Déjame llevarte a través de él.
Hacer formas de dibujar
Para desglosarlo, necesitamos cinco formas en total:
- Estrellas de cuatro puntas
- Cosas floridas (sí, ese es el término técnico)
- Cosas similares a cilindros (también el término técnico correcto)
- Hexágono redondo
- Círculo
He dibujado estas formas en un programa de edición gráfica (me gusta Diseñador de afinidadPero cualquier aplicación que le permita dibujar formas vectoriales debería funcionar), transmitirla a SVG y luego usar una herramienta como Generadores con AFIFpara traducir la ruta SVG generada por el programa a CSS shape() sintaxis.
Ahora, antes de salir de la forma del diseñador de afinidad, me aseguro de que las flores, los hexágonos, los círculos y los cilindros tengan el mismo número de puntos de anclaje. Si no tienen el mismo número, la forma saltará de una forma a la siguiente sin deformarse. Entonces, usemos un número consistente de puntos de anclaje en cada forma (incluso círculos) que podemos observar que estas formas se deforman entre sí.
Establecí doce puntos de anclaje en cada forma porque esa es la cantidad más alta utilizada (el hexágono tiene dos puntos cerca de cada ángulo curvo).
Lo relacionado (que puede ser difícil de resolver, dependiendo de su programa gráfico) es que algunas de mis formas se torcen cuando se animan entre formas. Por ejemplo, muchas formas se hacen más pequeñas y giran antes de que comiencen a girar a la siguiente forma, mientras que otras son más perfectas. Terminé descubriendo que la interpolación coincidía con el punto de partida de cada forma y seguí coincidiendo con los puntos a medida que se siguió la forma.
El resultado es que los puntos de juego se mueven entre formas, por lo que si el punto de partida de una forma está en el otro lado del punto de partida de la segunda forma, se requiere mucho movimiento para pasar desde el punto de partida de una forma al punto de partida de la siguiente.

Afortunadamente, el círculo es la única forma que me da problemas, por lo que pude rotarlo (probado y errado) hasta que su punto de partida coincida más con el otro punto de partida.
Otro problema que he encontrado es que la forma del cilindro tiene dos líneas rectas separadas shape() y line Comandos en lugar de usar curve Orden. Esto evita que la animación se convierta en la siguiente forma. Inmediatamente captura la siguiente imagen en el caso sin animar la transición, saltar a la siguiente forma (cuando ambos ingresan al cilindro y salen de él).
Regresé a Affinity Designer y agregué curvas a ambas líneas y me deformé perfectamente. Inicialmente pensé que era shape() Quirk, pero lo mismo sucede cuando trato de usar animación path() Función, lo que indica que es más un límite de interpolación, en lugar de shape() limitación.
Una vez que agregué el mío shape() Valor, definí una variable CSS para cada forma. Esto hace que cada shape() Más legible, sin mencionar que es más fácil de mantener. Para doce líneas de cada forma, el código es la longitud de la apestosa (término técnico), por lo que lo colocamos detrás del menú de acordeón.
Ver el código de forma
:root {
--hexagon: shape(
evenodd from 6.47% 67.001%,
curve by 0% -34.002% with -1.1735% -7.7% / -1.1735% -26.302%,
curve by 7.0415% -12.1965% with 0.7075% -4.641% / 3.3765% -9.2635%,
curve by 29.447% -17.001% with 6.0815% -4.8665% / 22.192% -14.1675%,
curve by 14.083% 0% with 4.3725% -1.708% / 9.7105% -1.708%,
curve by 29.447% 17.001% with 7.255% 2.8335% / 23.3655% 12.1345%,
curve by 7.0415% 12.1965% with 3.665% 2.933% / 6.334% 7.5555%,
curve by 0% 34.002% with 1.1735% 7.7% / 1.1735% 26.302%,
curve by -7.0415% 12.1965% with -0.7075% 4.641% / -3.3765% 9.2635%,
curve by -29.447% 17.001% with -6.0815% 4.8665% / -22.192% 14.1675%,
curve by -14.083% 0% with -4.3725% 1.708% / -9.7105% 1.708%,
curve by -29.447% -17.001% with -7.255% -2.8335% / -23.3655% -12.1345%,
curve by -7.0415% -12.1965% with -3.665% -2.933% / -6.334% -7.5555%,
close
);
--flower: shape(
evenodd from 17.9665% 82.0335%,
curve by -12.349% -32.0335% with -13.239% -5.129% / -18.021% -15.402%,
curve by -0.0275% -22.203% with -3.1825% -9.331% / -3.074% -16.6605%,
curve by 12.3765% -9.8305% with 2.3835% -4.3365% / 6.565% -7.579%,
curve by 32.0335% -12.349% with 5.129% -13.239% / 15.402% -18.021%,
curve by 20.4535% -0.8665% with 8.3805% -2.858% / 15.1465% -3.062%,
curve by 11.58% 13.2155% with 5.225% 2.161% / 9.0355% 6.6475%,
curve by 12.349% 32.0335% with 13.239% 5.129% / 18.021% 15.402%,
curve by 0.5715% 21.1275% with 2.9805% 8.7395% / 3.0745% 15.723%,
curve by -12.9205% 10.906% with -2.26% 4.88% / -6.638% 8.472%,
curve by -32.0335% 12.349% with -5.129% 13.239% / -15.402% 18.021%,
curve by -21.1215% 0.5745% with -8.736% 2.9795% / -15.718% 3.0745%,
curve by -10.912% -12.9235% with -4.883% -2.2595% / -8.477% -6.6385%,
close
);
--cylinder: shape(
evenodd from 10.5845% 59.7305%,
curve by 0% -19.461% with -0.113% -1.7525% / -0.11% -18.14%,
curve by 10.098% -26.213% with 0.837% -10.0375% / 3.821% -19.2625%,
curve by 29.3175% -13.0215% with 7.2175% -7.992% / 17.682% -13.0215%,
curve by 19.5845% 5.185% with 7.1265% 0% / 13.8135% 1.887%,
curve by 9.8595% 7.9775% with 3.7065% 2.1185% / 7.035% 4.8195%,
curve by 9.9715% 26.072% with 6.2015% 6.933% / 9.4345% 16.082%,
curve by 0% 19.461% with 0.074% 1.384% / 0.0745% 17.7715%,
curve by -13.0065% 29.1155% with -0.511% 11.5345% / -5.021% 21.933%,
curve by -26.409% 10.119% with -6.991% 6.288% / -16.254% 10.119%,
curve by -20.945% -5.9995% with -7.6935% 0% / -14.8755% -2.199%,
curve by -8.713% -7.404% with -3.255% -2.0385% / -6.1905% -4.537%,
curve by -9.7575% -25.831% with -6.074% -6.9035% / -9.1205% -15.963%,
close
);
--star: shape(
evenodd from 50% 24.787%,
curve by 7.143% 18.016% with 0% 0% / 2.9725% 13.814%,
curve by 17.882% 7.197% with 4.171% 4.2025% / 17.882% 7.197%,
curve by -17.882% 8.6765% with 0% 0% / -13.711% 4.474%,
curve by -7.143% 16.5365% with -4.1705% 4.202% / -7.143% 16.5365%,
curve by -8.6115% -16.5365% with 0% 0% / -4.441% -12.3345%,
curve by -16.4135% -8.6765% with -4.171% -4.2025% / -16.4135% -8.6765%,
curve by 16.4135% -7.197% with 0% 0% / 12.2425% -2.9945%,
curve by 8.6115% -18.016% with 4.1705% -4.202% / 8.6115% -18.016%,
close
);
--circle: shape(
evenodd from 13.482% 79.505%,
curve by -7.1945% -12.47% with -1.4985% -1.8575% / -6.328% -10.225%,
curve by 0.0985% -33.8965% with -4.1645% -10.7945% / -4.1685% -23.0235%,
curve by 6.9955% -12.101% with 1.72% -4.3825% / 4.0845% -8.458%,
curve by 30.125% -17.119% with 7.339% -9.1825% / 18.4775% -15.5135%,
curve by 13.4165% 0.095% with 4.432% -0.6105% / 8.9505% -0.5855%,
curve by 29.364% 16.9% with 11.6215% 1.77% / 22.102% 7.9015%,
curve by 7.176% 12.4145% with 3.002% 3.7195% / 5.453% 7.968%,
curve by -0.0475% 33.8925% with 4.168% 10.756% / 4.2305% 22.942%,
curve by -7.1135% 12.2825% with -1.74% 4.4535% / -4.1455% 8.592%,
curve by -29.404% 16.9075% with -7.202% 8.954% / -18.019% 15.137%,
curve by -14.19% -0.018% with -4.6635% 0.7255% / -9.4575% 0.7205%,
curve by -29.226% -16.8875% with -11.573% -1.8065% / -21.9955% -7.9235%,
close
);
}
Si todo esto parece Gobbledygook para ti, también funciona mucho para mí (lo escribí shape() Entrada del anuario). Como dije anteriormente, los convierto de lo que dibujo a shape()Use herramientas. Si puede identificar formas en los nombres de propiedades personalizadas, necesitará saber todo lo que necesita seguir siguiendo.
Animación de descomposición
Después de mirar las animaciones de Gmail más de lo que quería admitir, pude reconocer seis etapas diferentes:
Primero, flotante:
- La estrella de cuatro puntos gira hacia la derecha y cambia su color.
- La exquisita forma azul se extiende desde debajo de la estrella.
- Al girar, la exquisita forma azul se convierte en otra forma.
- Los colores morados se limpian en formas azules elegantes.
Luego, después de flotar:
- Un hermoso contrato de forma azul (básicamente lo opuesto a la etapa 2).
- La estrella de cuatro puntos gira hacia la izquierda y devuelve su color inicial (básicamente lo opuesto a la etapa 1).
¡Ese es el reloj en el que estamos trabajando! Escribiremos CSS para todo, pero primero quiero configurar la estructura HTML que estamos atrayendo.
Html
Siempre quise ser uno de los frentes para hacer arte asombroso de CSS div (Eso es lo que alguien hace el comentario sobre CodePen). Pero, a, decidí que necesitaba dos divS para lograr este desafío, agradezco que veas mi sentido de la vergüenza. Para aquellos que levantan la nariz y dejan de leer después de la admisión: puedo llamarlo con seguridad Flooplegerp y nunca lo sabrán.
(En realidad no sé qué es Flooplegerp para las personas que todavía están conmigo. Pero estoy seguro de que es malo).
Dado que las animaciones necesitan extender formas azules desde debajo de las estrellas, deben ser dos formas separadas. Y no podemos reducir o sujetar los elementos principales para hacer esto porque eso enmascara las estrellas.
Entonces, sí, por eso alcanzo un segundo div: Maneje formas elegantes y cómo se mueve e interactúa con formas de estrellas.
<div id="geminianimation">
<div></div>
</div>
Estilo CSS básico
Cada forma se define básicamente con las mismas dimensiones y espaciado de margen.
#geminianimation {
width: 200px;
aspect-ratio: 1/1;
margin: 50px auto;
position: relative;
}
Podemos usar pseudo-elementos para recortar cajas a formas específicas. Por ejemplo, usemos la variable CSS para sujetar la estrella (--star) Lo definimos y establecemos el color de fondo:
#geminianimation {
width: 200px;
aspect-ratio: 1;
margin: 50px auto;
position: relative;
&::before {
content: "";
clip-path: var(--star);
width: 100%;
height: 100%;
position: absolute;
background-color: #494949;
}
}
Podemos conectarnos al recipiente para los niños div Y úselo para crear la forma inicial de la animación, es decir, flores (usando nuestro --flower Cambiable):
#geminianimation div {
width: 100%;
height: 100%;
clip-path: var(--flower);
background: linear-gradient(135deg, #217bfe, #078efb, #ac87eb, #217bfe);
}
Lo que obtenemos es la forma de la estrella apilada en la parte superior de la forma de la flor. Nuestro CSS inicial está casi listo, pero para recrear las toallitas de color animado necesitamos una superficie más grande para que podamos «cambiar» el color moviendo la posición del gradiente de fondo. Mueva el gradiente para que se declare en el pseudo elemento en lugar del niño divY pasar 400% Danos un espacio de respiración adicional.
#geminianimation div {
width: 100%;
height: 100%;
clip-path: var(--flower);
&::after {
content: "";
background: linear-gradient(135deg, #217bfe, #078efb, #ac87eb, #217bfe);
width: 400%;
height: 400%;
position: absolute;
}
}
Ahora podemos ver claramente cómo se colocan las formas en relación entre sí:
Fases de animación 1 y 6
Ahora, admito que con mi propia arrogancia, soy humilde transition La propiedad es porque mi mente suele ser Las transiciones son excelentes para comenzar en animación y rápido, pero Real La animación se realiza utilizando un marco de teclas CSS.
(Tal vez yo también soy Flooplegerp).
Pero ahora veo el error en mi camino. Podría escribir un conjunto de fotogramas clave para rotar los 180 grados Star, convertirlo en blanco (ish) y mantenerlo así mientras el elemento se ronde. Lo que no puedo hacer es volver a la animación Star a un elemento que no está en poder del elemento.
Pero puedo usar transition propiedad. Para este fin, agregamos transition: 1s ease-in-out; existir ::beforeagregue el nuevo color de fondo y gire las cosas en :hover existir #geminianimation recipiente. Esto ilustra la primera y sexta etapas de la animación que describimos anteriormente.
#geminianimation {
&::before {
/* Existing styles */
transition: 1s ease-in-out;
}
&:hover {
&::before {
transform: rotate(180deg);
background-color: #FAFBFE;
}
}
}
Animación Fase 2 y Fase 5
En la segunda y quinta etapas de la animación, podemos hacer cosas similares porque son espejos el uno del otro. Recuerde que durante estas etapas nos estamos extendiendo y reduciendo las hermosas formas azules.
Podemos comenzar reduciendo nuestros corazones div‘ scale Inicialmente cero, luego expandelo de nuevo al tamaño original (scale: 1) existir :hover (Use la transición nuevamente):
#geminianimation {
div {
scale: 0;
transition: 1s ease-in-out;
}
&:hover {
div {
scale: 1;
}
}
Etapa de animación 3
Ahora estamos bien Poder Usar uno transition Es como si hiciéramos los dos últimos sets, pero podríamos No debería ser Haciendo esto … es decir, a menos que quieras llorar lágrimas dolorosas y maldecir el día en que escuchaste por primera vez sobre CSS … no es que sepa por experiencias personales ni nada … jaja … jaja.
Los fotogramas clave CSS son más adecuados aquí, ya que hay múltiples estados entre ellos que requieren varias transiciones diferentes para definir y orquestar. Los marcos clave son mejores para resolver múltiples rifles.
Lo que básicamente hacemos es animar entre diferentes formas de la variable CSS que se ha definido como una forma sujetada. El navegador manejará la interpolación entre formas, por lo que todo lo que necesitamos es decirle al CSS qué forma queremos cortar en cada etapa (o «parte») de esta combinación:
@keyframes shapeshift {
0% { clip-path: var(--circle); }
25% { clip-path: var(--flower); }
50% { clip-path: var(--cylinder); }
75% { clip-path: var(--hexagon); }
100% { clip-path: var(--circle); }
}
Sí, podemos combinar el primer y último marco clave (0% y 100%) Vaya a un paso, pero necesitamos separarlos en un segundo, porque también queremos animar las rotaciones al mismo tiempo. Establecimos la rotación inicial en 0turn Rotación final 1turn Mientras la animación continúe, puede seguir girando sin problemas:
@keyframes shapeshift {
0% {
clip-path: var(--circle);
rotate: 0turn;
}
25% {
clip-path: var(--flower);
}
50% {
clip-path: var(--cylinder);
}
75% {
clip-path: var(--hexagon);
}
100% {
clip-path: var(--circle);
rotate: 1turn;
}
}
Notas: Sí, turn De hecho es uno Unidad CSSaunque a menudo se pasa por alto.
Queremos que la animación permanezca suave cuando se interpola entre formas. Entonces, estoy configurando la función de tiempo de la animación ease-in-out. Desafortunadamente, esto también reduce la rotación al comienzo y al final de la rotación. Sin embargo, dado que ambos comenzamos y terminamos con la forma de un círculo, la rotación se ralentiza al 0% y se ralentiza nuevamente porque entra al 100% no es obvio: el círculo parece un círculo independientemente de su rotación. Si terminamos en diferentes formas, podemos ver sueltos, usaré dos conjuntos separados de cuadros de teclas (uno para el cambio de forma y otro para la rotación) y luego los llamaré a ambos #geminianimation niño div .
#geminianimation:hover {
div {
animation: shapeshift 5s ease-in-out infinite forwards;
}
}
Etapa de animación 4
Es decir, todavía necesitamos otro conjunto de marcos clave, especialmente para cambiar el color de la forma. Recuerde cómo establecemos un gradiente lineal en el contenedor del contenedor principal ::after Pseudo, y luego también agregamos pseudo width y height? Este es el código nuevamente:
#geminianimation div {
width: 100%;
height: 100%;
clip-path: var(--flower);
&::after {
content: "";
background: linear-gradient(135deg, #217bfe, #078efb, #ac87eb, #217bfe);
width: 400%;
height: 400%;
position: absolute;
}
}
El gradiente es muy grande porque solo mostramos una parte de él a la vez. Esto significa que podemos translate El gradiente mueve la posición del gradiente sobre algunos marcos clave. 400% Se puede dividir en cuartos bien, por lo que podemos mover el gradiente por tres cuartos de su tamaño. Desde sus padres #geminianimation divya girando, no necesitamos ningún movimiento exquisito para que se sienta como si el color proviene de diferentes direcciones. Solo somos translate Es lineal y la rotación agrega cierta variabilidad a la dirección del borde del color.
@keyframes gradientMove {
0% {
translate: 0 0;
}
100% {
translate: -75% -75%;
}
}
La elaboración final
Cambiémoslo a un círculo en lugar de la flor como la forma predeterminada. Esto suaviza las cosas cuando la interacción flotante hace que la animación se detenga y vuelva a su posición inicial.
Ahí tienes:
Resumir
¡Lo hicimos! ¿Es así como Google hace lo mismo? Probablemente no. Honestamente, nunca revisé el código de animación porque quería procesarlo desde limpieza y descubrir cómo lo haría puramente en CSS.
Aquí está lo divertido de un desafío como este: hay diferentes formas de lograr lo mismo (o algo similar) y su enfoque puede ser diferente del mío. Es interesante ver varios métodos.
Esto me lleva a preguntar: ¿Cómo te acercará a la animación de botones de Géminis? ¿Considerarías que no pensé en eso?