Logotipo de Zephyrnet

Trazados de movimiento de curva Bezier de CSS puro

Fecha:

¿Eres el Curva de Bezier amante como yo?

Además de ser elegantes, las curvas de Bezier tienen buenas propiedades matemáticas debido a su definición y construcción. No es de extrañar que se utilicen ampliamente en tantas áreas:

  • Como herramienta de dibujo/diseño: a menudo se los denomina "trazados" en el software de dibujo vectorial.
  • Como formato de representación de curvas: Se utilizan en SVG, fuentes y muchos otros formatos gráficos vectoriales.
  • Como función matemática: a menudo se usa para controlar el tiempo de la animación.

Ahora, ¿qué tal usar curvas Bezier como rutas de movimiento con CSS?

Resumen rápido

Dependiendo del contexto, cuando nos referimos a una "curva de Bezier", a menudo asumimos una curva de Bezier cúbica 2D.

Tal curva está definida por cuatro puntos:

MarianSigler, Dominio público, a través de Wikimedia Commons

Nota: En este artículo, generalmente nos referimos a P0 y P3 como puntos finales, P1 y P2 como puntos de control.

La palabra "cúbica" significa que la función subyacente de la curva es un polinomio cúbico. También hay curvas de Bézier "cuadráticas", que son similares, pero con un punto de control menos.

El problema

Digamos que se le da una curva de Beizer cúbica 2D arbitraria, ¿cómo animaría un elemento con animación CSS pura, de modo que se mueva? precisamente a lo largo de la curva?

Como ejemplo, ¿cómo recrearías esta animación?

En este artículo exploraremos tres métodos con diferentes sabores. Para cada solución, presentaremos una demostración interactiva y luego explicaremos cómo funciona. Hay muchos cálculos matemáticos y pruebas detrás de escena, pero no te preocupes, no profundizaremos mucho.

¡Empecemos!

Método 1: Distorsión del tiempo

Aquí está la idea básica:

  • Preparar @keyframes para mover el elemento de un punto final de la curva al otro.
  • Distorsionar el tiempo para cada coordenada individualmente, usando animation-timing-function.

Nota: Hay muchos ejemplos y explicaciones en Artículo de Temani Afif (2021).

Usando el cubic-bezier() función con los parámetros correctos, podemos crear una trayectoria de movimiento de cualquier curva Bezier cúbica:

Esta demostración muestra una animación CSS pura. Sin embargo, se utilizan canvas y JavaScript, que tienen dos propósitos:

  • Visualice la curva de Bezier subyacente (curva roja).
  • Permitir ajustar la curva con la interfaz de usuario típica de "ruta".

Puede arrastrar los dos puntos finales (puntos negros) y los dos puntos de control (cuadrados negros). El código JavaScript actualizará la animación en consecuencia, actualizando algunas variables CSS.

Nota: Aquí hay un versión CSS pura para referencia.

Cómo funciona

Supongamos que la curva Bezier cúbica deseada está definida por cuatro puntos: p0, p1, p2y p3. Configuramos las reglas CSS de la siguiente manera:

/* pseudo CSS code */
div {
  animation-name: move-x, move-y;
  /*
    Define:
    f(x, a, b) = (x - a) / (b - a)
    qx1 = f(p1.x, p0.x, p3.x)
    qx2 = f(p2.x, p0.x, p3.x)
    qy1 = f(p1.y, p0.y, p3.y)
    qy2 = f(p2.y, p0.y, p3.y)
  */
  animation-timing-function: 
    cubic-bezier(1/3, qx1, 2/3, qx1),
    cubic-bezier(1/3, qy1, 2/3, qy2);
}

@keyframes move-x {
  from {
    left: p0.x;
  }
  to {
    left: p3.x;
  }
}

@keyframes move-y {
  from {
    top: p0.y;
  }
  to {
    top: p3.y;
  }
}

El @keyframes reglas move-x y move-y determinar las ubicaciones inicial y final del elemento. En animation-timing-function tenemos dos magicos cubic-bezier() funciones, los parámetros se calculan de tal manera que tanto top y left tener siempre los valores correctos en cualquier momento.

Me saltaré las matemáticas, pero redacté una prueba breve esta página, para sus mentes matemáticas curiosas.

discusiones

Este método debería funcionar bien en la mayoría de los casos. Incluso puede hacer una curva Bézier cúbica en 3D, introduciendo otra animación para el z .

Sin embargo, hay algunas advertencias menores:

  • No funciona cuando ambos extremos se encuentran en una línea horizontal o vertical, debido al error de división por cero.

Nota: en la práctica, solo puede agregar un pequeño desplazamiento como solución alternativa.

  • No admite curvas Bezier con un orden superior a 3.
  • Las opciones para el tiempo de animación son limitadas.
    • Utilizamos 1/3 y 2/3 anterior para lograr una temporización lineal.
    • Puede modificar ambos valores para ajustar el tiempo, pero es limitado en comparación con otros métodos. Más sobre esto más adelante.

Método 2: animaciones en competencia

Como calentamiento, imagina un elemento con dos animaciones:

div {
  animation-name: move1, move2;
}

¿Cuál es la ruta de movimiento del elemento, si las animaciones se definen de la siguiente manera:

@keyframes move1 {
  to {
    left: 256px;
  }
}

@keyframes move2 {
  to {
    top: 256px;
  }
}

Como habrás adivinado, se mueve en diagonal:

Ahora, ¿qué pasa si las animaciones se definen así?

@keyframes move1 {
  to {
    transform: translateX(256px);
  }
}

@keyframes move2 {
  to {
    transform: translateY(256px);
  }
}

"¡Ajá, no puedes engañarme!" podría decir, cuando notó que ambas animaciones están cambiando la misma propiedad, "move2 debe anular move1 como esto:"

Bueno, antes yo también lo había pensado. Pero en realidad obtenemos esto:

El truco es que move2 no tiene una from marco, lo que significa que la posición inicial está animada por move1.

En la siguiente demostración, la posición inicial de move2 se visualiza como el punto azul en movimiento:

Curvas cuadráticas de Bezier

La demostración de arriba se asemeja a la construcción de una curva Bezier cuadrática:

Bézier 2 grande
Phil Tregoning, Dominio público, a través de Wikimedia Commons

Pero se ven diferentes. La construcción tiene tres puntos que se mueven linealmente (dos verdes, uno negro), pero nuestra demostración solo tiene dos (el punto azul y el elemento de destino).

En realidad, la ruta de movimiento en la demostración. is una curva Bezier cuadrática, solo necesitamos ajustar los fotogramas clave con cuidado. voy a saltar las matemáticas y solo revela la magia:

Supongamos que una curva de Bézier cuadrática está definida por puntos p0, p1y p2. Para mover un elemento a lo largo de la curva, hacemos lo siguiente:

/* pseudo-CSS code */
div {
  animation-name: move1, move2;
}

@keyframes move1 {
  from {
    transform: translate3d(p0.x, p0.y, p0.z);
  }
  /* define q1 = (2 * p1 - p2) */
  to {
    transform: translate3d(q1.x, q1.y, q1.z);
  }
}

@keyframes move2 {
  to {
    transform: translate3d(p2.x, p2.y, p2.z);
  }
}

Similar a la demostración de Método 1, puede ver o ajustar la curva. Además, la demostración también muestra dos piezas más de información:

  • La construcción matemática (partes móviles grises)
  • Las animaciones CSS (partes azules)

Ambos se pueden alternar usando las casillas de verificación.

Curvas cúbicas de Bézier

Este método también funciona para curvas Bézier cúbicas. Si la curva está definida por puntos p0, p1, p2y p3. Las animaciones deben definirse así:

/* pseudo-CSS code */
div {
  animation-name: move1, move2, move3;
}

@keyframes move1 {
  from {
    transform: translate3d(p0.x, p0.y, p0.z);
  }
  /* define q1 = (3 * p1 - 3 * p2 + p3) */
  to {
    transform: translate3d(q1.x, q1.y, q1.z);
  }
}

@keyframes move2 {
  /* define q2 = (3 * p2 - 2 * p3) */
  to {
    transform: translate3d(q2.x, q2.y, q2.z);
  }
}

@keyframes move3 {
  to {
    transform: translate3d(p3.x, p3.y, p3.z);
  }
}

Prórrogas de tiempo para presentar declaraciones de impuestos

¿Qué pasa con las curvas 3D Bezier? En realidad, la verdad es que todos los ejemplos anteriores tuvieron Curvas 3D, simplemente nunca nos molestamos con el z valores.

¿Qué pasa con las curvas de Bezier de orden superior? Estoy 90% seguro de que el método puede extenderse naturalmente a órdenes superiores. Por favor, hágame saber si ha calculado la fórmula para las curvas de Bézier de cuarto orden, o mejor aún, una fórmula genérica para las curvas de Bézier de orden N.

Método 3: Construcción de Curva Bézier Estándar

El construcción matemática de Bezier Curves ya nos da una buena pista.

Bézier 3 grande
Phil Tregoning, Dominio público, a través de Wikimedia Commons

Paso a paso, podemos determinar las coordenadas de todos los puntos en movimiento. Primero, determinamos la ubicación del punto verde que se mueve entre p0 y p1:

@keyframes green0 {
  from {
    --green0x: var(--p0x);
    --green0y: var(--p0y);
  }
  to {
    --green0x: var(--p1x);
    --green0y: var(--p1y);
  }
}

Se pueden construir puntos verdes adicionales de manera similar.

A continuación, podemos determinar la ubicación de un punto azul como este:

@keyframes blue0 {
  from {
    --blue0x: var(--green0x);
    --blue0y: var(--green0y);
  }
  to {
    --blue0x: var(--green1x);
    --blue0y: var(--green1y);
  }
}

Enjuague y repita, eventualmente obtendremos la curva deseada.

Similar a Método 2, con este método podemos construir fácilmente una Curva Bezier 3D. También es intuitivo extender el método para curvas Bezier de orden superior.

El único inconveniente es el uso de @property, que no es compatible con todos los navegadores.

Temporización de la animación

Todos los ejemplos hasta ahora tienen el tiempo "lineal", ¿qué pasa con la aceleración u otras funciones de tiempo?

Nota: Por "lineal" queremos decir La variable t de la curva cambia linealmente de 0 a 1. En otras palabras, t es lo mismo que el progreso de la animación.

animation-timing-function nunca se usa en Método 2 y Método 3. Al igual que otras animaciones CSS, aquí podemos usar cualquier función de temporización admitida, pero debemos aplicar la misma función para todas las animaciones (move1, move2y move3) al mismo tiempo.

Aquí hay un ejemplo de animation-timing-function: cubic-bezier(1, 0.1, 0, 0.9):

Y así es como se ve con animation-timing-function: steps(18, end):

Por otra parte, Método 1 es más complicado, porque ya utiliza un cubic-bezier(u1, v1, u2, v2) función de temporización. En los ejemplos anteriores tenemos u1=1/3 y u2=2/3. De hecho, podemos ajustar el tiempo cambiando ambos parámetros. De nuevo, todas las animaciones (p. ej., move-x y move-y) debe tener los mismos valores de u1 y u2.

Así es como se ve cuando u1=1 y u2=0:

Con Método 2, podemos lograr exactamente el mismo efecto configurando animation-timing-function a cubic-bezier(1, 0.333, 0, 0.667):

De hecho, funciona de una manera más general:

Supongamos que nos dan una curva Bezier cúbica y creamos dos animaciones para la curva con Método 1 y Método 2 respectivamente. Para cualquier valor válido de u1 y u2, las siguientes dos configuraciones tienen el mismo tiempo de animación:

  • Método 1  animation-timing-function: cubic-bezier(u1, *, u2, *).
  • Método 2  animation-timing-function: cubic-bezier(u1, 1/3, u2, 2/3).

Ahora vemos por qué Método 1 es “limitado”: ​​con Método 1 nosotros solo podemos cubic-bezier() con dos parámetros, pero con Método 2 y Método 3 podemos usar cualquier CSS animation-timing-function.

Conclusiones

En este artículo, discutimos 3 métodos diferentes para mover elementos con precisión a lo largo de una curva Bezier, usando solo animaciones CSS.

Si bien los 3 métodos son más o menos prácticos, tienen sus pros y sus contras:

  • Método 1 podría ser más intuitivo para aquellos familiarizados con la función de sincronización. Pero es menos flexible con el tiempo de animación.
  • Método 2 tiene reglas CSS muy simples. Cualquier función de temporización CSS se puede aplicar directamente. Sin embargo, podría ser difícil recordar las fórmulas.
  • Método 3 tiene más sentido para aquellos familiarizados con la construcción matemática de las curvas de Bezier. El tiempo de animación también es flexible. Por otro lado, no todos los navegadores modernos son compatibles debido al uso de @property.

¡Eso es todo! Espero que encuentres este artículo interesante. ¡Por favor, hágame saber sus pensamientos!

punto_img

Información más reciente

punto_img