El estado de los degradados cambiantes con transiciones y animaciones CSS | Programar Plus

En 2012, salió Internet Explorer 10 y, entre otras cosas, finalmente admitió degradados CSS y, además de eso, ¡la capacidad de animarlos solo con CSS! Ningún otro navegador admitía esto en ese momento, pero tenía esperanzas para el futuro.

Lamentablemente, han pasado seis años y nada ha cambiado en este departamento. Edge admite la animación de gradientes con CSS, al igual que IE 10 en ese entonces, pero ningún otro navegador ha agregado soporte para esto. Y mientras animaba background-size o background-position o la opacity o la rotación de un pseudo elemento superpuesto puede llevarnos un largo camino en términos de lograr efectos geniales, estas soluciones aún son limitadas.

Hay efectos que no podemos reproducir sin agregar muchos elementos adicionales o muchos gradientes adicionales, como el “efecto de las persianas” que se ve a continuación.

GIF animado que muestra una grabación del efecto de apertura y cierre de persianas.  Cuando las persianas están cerradas, solo vemos un fondo gris, cuando las persianas comienzan a abrirse, comenzamos a ver franjas verticales de color naranja (la luz que entra) que crecen horizontalmente hasta que las persianas están completamente abiertas, por lo que solo vemos un fondo naranja.  Después de eso, las persianas comienzan a cerrarse, por lo que las franjas naranjas verticales comienzan a estrecharse hasta quedar reducidas a nada cuando las persianas están completamente cerradas y solo vemos un fondo gris nuevamente.  Entonces todo el ciclo se repite.El efecto de las persianas (demostración en vivo, solo Edge/ IE 10+).

En Edge, conseguir el efecto anterior se consigue con un fotograma clave animation:

html {
  background: linear-gradient(90deg, #f90 0%, #444 0) 50%/ 5em;
  animation: blinds 1s ease-in-out infinite alternate;
}

@keyframes blinds {
  to {
    background-image: linear-gradient(90deg, #f90 100%, #444 0);
  }
}

si eso parece MOJADO, podemos SECARLO con un toque de Sass:

@function blinds($open: 0) {
  @return linear-gradient(90deg, #f90 $open*100%, #444 0);
}

html {
  background: blinds() 50%/ 5em;
  animation: blinds 1s ease-in-out infinite alternate;
}

@keyframes blinds { to { background-image: blinds(1) } }

Si bien hemos hecho que el código que escribimos y lo que necesitaremos editar más adelante sea mucho más fácil de mantener, todavía tenemos repetición en el CSS compilado y estamos limitados por el hecho de que solo podemos animar entre paradas con la misma unidad. — mientras animaba desde 0% a 100% funciona bien, tratando de usar 0 o 0px en vez de 0% da como resultado que ya no suceda ninguna animación. Sin mencionar que Chrome y Firefox simplemente cambian de naranja a gris sin una posición de parada. animation ¡en absoluto!

Afortunadamente, en estos días tenemos una opción aún mejor: ¡variables CSS!

Desde el primer momento, las variables CSS no se pueden animar, aunque podemos obtener transition (pero no animation!) efectos si la propiedad para la que los usamos es animable. Por ejemplo, cuando se usa dentro de un transform función, podemos transition el transform la propiedad.

Consideremos el ejemplo de un cuadro que se desplaza y aplasta cuando se marca una casilla de verificación. En esta caja, colocamos un transform eso depende de un factor --f que es inicialmente 1:

.box {
  /* basic styles like dimensions and background */
  --f: 1;
  transform: translate(calc((1 - var(--f))*100vw)) scalex(var(--f));
}

Cuando la casilla de verificación está :checked, cambiamos el valor de la variable CSS --f a .5:

:checked ~ .box { --f: .5 }

Establecer un transition sobre el .box hace que pase sin problemas de un estado a otro:

.box {
  /* same styles as before */
  transition: transform .3s ease-in;
}

Tenga en cuenta que esto realmente no funciona en la versión actual de Edge debido a este error.

Sin embargo, los degradados CSS son imágenes de fondo, que solo se pueden animar en Edge e IE 10+. Entonces, si bien podemos facilitarnos las cosas y reducir la cantidad de CSS generado para las transiciones (como se ve en el código a continuación), aún no estamos progresando en términos de extender el soporte.

.blinds {
  background: linear-gradient(90deg, #f90 var(--pos, 0%), #444 0) 50%/ 5em;
  transition: .3s ease-in-out;
    
  :checked ~ & { --pos: 100%; }
}

GIF animado.  El efecto de apertura de persianas ocurre al marcar una casilla de verificación de 'persianas abiertas', mientras que al desmarcarla se activa el efecto de cierre.Abre/cierra las persianas al marcar/desmarcar la casilla de verificación (demostración en vivo, solo Edge).

Ingrese a Houdini, que nos permite registrar propiedades personalizadas y luego animarlas. Actualmente, esto solo es compatible con los navegadores Blink detrás de la Características de la plataforma web experimental flag, pero todavía está extendiendo un poco el soporte solo de Edge.

Captura de pantalla que muestra el indicador de funciones de la plataforma web experimental habilitado en Chrome.El indicador de características de la plataforma web experimental está habilitado en Chrome.

Volviendo a nuestro ejemplo, registramos el --pos propiedad personalizada:

CSS.registerProperty({
  name: '--pos', 
  syntax: '<length-percentage>', 
  initialValue: '0%', 
  inherits: true
});

Tenga en cuenta que significa que acepta no sólo valores de longitud y porcentaje, sino también calc() combinaciones de ellos. Por el contrario, | solo acepta valores de longitud y porcentaje, pero no calc() combinaciones de ellos.

Tenga en cuenta que especificar explícitamente inherits ahora es obligatorio, aunque era opcional en versiones anteriores de la especificación.

Sin embargo, hacer esto no hace ninguna diferencia en Chrome, incluso con la bandera habilitada, probablemente porque, en el caso de las transiciones, lo que se transiciona es la propiedad cuyo valor depende de la variable CSS y no de la variable CSS en sí. Y dado que generalmente no podemos hacer la transición entre dos imágenes de fondo en Chrome en general, esto también falla.

Funciona en Edge, pero funcionó en Edge incluso sin registrar el --pos variable porque Edge nos permite hacer la transición entre gradientes en general.

Lo que sí funciona en los navegadores Blink con la bandera habilitada es tener un animation en vez de una transition.

html {
  background: linear-gradient(90deg, #f90 var(--pos, 0%), #444 0) 50%/ 5em;
  animation: blinds .85s ease-in-out infinite alternate;
}

@keyframes blinds { to { --pos: 100%; } }

Sin embargo, esto ya no funciona en Edge porque, si bien Edge puede animar entre fondos degradados, no puede hacer lo mismo con las propiedades personalizadas.

Entonces, debemos adoptar un enfoque alternativo para Edge aquí. Aquí es donde @supports viene muy bien, ya que todo lo que tenemos que hacer es comprobar si un -ms- Se admite la propiedad con prefijo.

@function grad($pos: 100%) {
  @return linear-gradient(90deg, #f90 $pos, #444 0);
}

html {
  /* same as before */
    
  @supports (-ms-user-select: none) {
    background-image: grad(0%);
    animation-name: blinds-alt;
  }
}

@keyframes blinds-alt { to { background-image: grad() } }

Las posiciones de parada no son lo único que podemos animar de esta manera. Podemos hacer lo mismo para el ángulo de gradiente. La idea detrás de esto es más o menos la misma, excepto que ahora nuestro animation ya no es uno alterno y usamos un easeInOutBack tipo de función de temporización.

@function grad($ang: 1turn) {
  @return linear-gradient($ang, #f90 50%, #444 0);
}

html {
  background: grad(var(--ang, 0deg));
  animation: rot 2s cubic-bezier(.68, -.57, .26, 1.65) infinite;
  
  @supports (-ms-user-select: none) {
    background-image: grad(0turn);
    animation-name: rot-alt;
  }
}

@keyframes rot { to { --ang: 1turn; } }

@keyframes rot-alt { to { background-image: grad(); } }

Recuerda que, al igual que en el caso de las posiciones de parada, solo podemos animar entre ángulos de degradado expresados ​​en la misma unidad en Edge, por lo que llamamos a nuestra función Sass con grad(0deg) en vez de grad(0turn) no funciona

Y, por supuesto, la variable CSS que usamos ahora acepta valores de ángulo en lugar de longitudes y porcentajes:

CSS.registerProperty({
  name: '--ang', 
  syntax: '<angle>', 
  initialValue: '0deg', 
  inherits: true
});

GIF animado.  Muestra un degradado de arriba a abajo con un cambio abrupto de gris a naranja al 50 %.  El ángulo de este degradado se anima mediante una función de tiempo de EaseInOutBack (que sobrepasa los valores finales en ambos extremos).Barrido (demostración en vivo, navegadores Blink con bandera y Edge solamente).

De manera similar, también podemos animar degradados radiales. Y lo realmente genial del enfoque de la variable CSS es que nos permite animar diferentes componentes del degradado de manera diferente, lo cual es algo que no es posible cuando se animan degradados como un todo como lo hace Edge (razón por la cual las siguientes demostraciones no lo hacen). funcionan también en Edge).

Digamos que tenemos lo siguiente radial-gradient():

$p: 9%;

html {
  --x: #{$p};
  --y: #{$p};
  background: radial-gradient(circle at var(--x) var(--y), #f90, #444 $p);
}

Registramos el --x y --y variables:

CSS.registerProperty({
  name: '--x', 
  syntax: '<length-percentage>', 
  initialValue: '0%', 
  inherits: true
});

CSS.registerProperty({
  name: '--y', 
  syntax: '<length-percentage>', 
  initialValue: '0%', 
  inherits: true
});

Luego agregamos las animaciones:

html {
  /* same as before */
  animation: a 0s ease-in-out -2.3s alternate infinite;
  animation-name: x, y;
  animation-duration: 4.1s, 2.9s;
}

@keyframes x { to { --x: #{100% - $p} } }
@keyframes y { to { --y: #{100% - $p} } }

El resultado que obtenemos se puede ver a continuación:

GIF animado.  Muestra una luz naranja brillante en movimiento sobre un fondo gris.  Esto se logra animando las coordenadas del punto central de un degradado radial de forma independiente con la ayuda de variables CSS y Houdini.Luz móvil (demostración en vivo, navegadores Blink con bandera únicamente).

Podemos usar esta técnica de animar las diferentes propiedades personalizadas que usamos dentro de la función de gradiente para hacer que las persianas en nuestro ejemplo inicial se cierren hacia el otro lado en lugar de retroceder. Para hacer esto, introducimos dos variables CSS más, --c0 y --c1:

$c: #f90 #444;

html {
  --c0: #{nth($c, 1)};
  --c1: #{nth($c, 2)};
  background: linear-gradient(90deg, var(--c0) var(--pos, 0%), var(--c1) 0) 50%/ 5em;
}

Registramos todas estas propiedades personalizadas:

CSS.registerProperty({
  name: '--pos', 
  syntax: '<length-percentage>', 
  initialValue: '0%', 
  inherits: true
});

CSS.registerProperty({
  name: '--c0', 
  syntax: '<color>', 
  initialValue: 'red', 
  inherits: true
});

/* same for --c1 */

Usamos la misma animación que antes para la posición de la primera parada. --pos y, además de esto, presentamos dos steps() animaciones para las otras dos variables, cambiando sus valores cada vez que una iteración de la primera animation (el que cambia el valor de --pos) esta completado:

$t: 1s;

html {
  /* same as before */
  animation: a 0s infinite;
  animation-name: c0, pos, c1;
  animation-duration: 2*$t, $t;
  animation-timing-function: steps(1), ease-in-out;
}

@keyframes pos { to { --pos: 100%; } }

@keyframes c0 { 50% { --c0: #{nth($c, 2)} } }
@keyframes c1 { 50% { --c1: #{nth($c, 1)} } }

Y obtenemos el siguiente resultado:

GIF animado.  Muestra el efecto de las persianas con las persianas cerrándose hacia el otro lado.  Una vez que las franjas naranjas verticales (aberturas) se han expandido horizontalmente de manera que cubren todo el fondo, no comienzan a contraerse nuevamente.  En cambio, las franjas verticales de color naranja grisáceo comienzan a expandirse desde la nada hasta cubrir todo el fondo.Otra versión de la animación de las persianas (demostración en vivo, navegadores Blink solo con bandera).

También podemos aplicar esto a un radial-gradient() (nada más que el background cambios de declaración):

background: radial-gradient(circle, var(--c0) var(--pos, 0%), var(--c1) 0);

GIF animado.  Comenzamos con un fondo gris y tenemos un disco naranja que crece desde la nada en el medio hasta que cubre todo.  Luego tenemos un disco gris que crece desde la nada en el medio hasta que cubre todo el fondo y estamos de regreso donde comenzamos: un fondo gris.Discos en crecimiento (demostración en vivo, navegadores Blink solo con bandera).

La misma táctica funciona exactamente para conic-gradient() también:

background: conic-gradient(var(--c0) var(--pos, 0%), var(--c1) 0);

GIF animado.  Comenzamos con un fondo gris y tenemos una rebanada de pastel de naranja (sector circular) que crece desde la nada hasta cubrir todo alrededor del punto central.  Luego tenemos una rebanada de pastel gris que crece desde la nada hasta cubrir todo alrededor del punto central y estamos de regreso donde comenzamos: un fondo gris.Cortes en crecimiento (demostración en vivo, navegadores Blink con bandera únicamente).

La repetición de degradados también es una opción que crea un efecto de onda en el caso radial:

$p: 2em;

html {
  /* same as before */
  background: repeating-radial-gradient(circle, 
    var(--c0) 0 var(--pos, 0px), var(--c1) 0 $p);
}

@keyframes pos { 90%, 100% { --pos: #{$p} } }

GIF animado.  Comenzamos con un fondo gris y tenemos círculos naranjas concéntricos que crecen hacia afuera desde muy delgados hasta que se encuentran y cubren todo, así que ahora parece que tenemos un fondo naranja.  Luego tenemos círculos grises que crecen hacia afuera desde muy delgados hasta que cubren todo el fondo y volvemos a donde empezamos: un fondo gris.Ripples (demostración en vivo, navegadores Blink con bandera únicamente).

Y un efecto hélice/rayos en el caso cónico:

$p: 5%;

html {
  /* same as before */
  background: repeating-conic-gradient(
    var(--c0) 0 var(--pos, 0%), var(--c1) 0 $p);
}

@keyframes pos { 90%, 100% { --pos: #{$p} } }

GIF animado.  Comenzamos con un fondo gris y tenemos rayos naranjas que crecen en el sentido de las agujas del reloj desde muy delgados hasta que se encuentran y cubren todo, así que ahora parece que tenemos un fondo naranja.  Luego tenemos rayos grises que crecen en el sentido de las agujas del reloj desde muy delgados hasta que cubren todo el fondo y volvemos al punto de partida: un fondo gris.Rayos en crecimiento (demostración en vivo, navegadores Blink con bandera únicamente).

También podemos agregar otra variable CSS para hacer las cosas más interesantes:

$n: 20;

html {
  /* same as before */
  background: radial-gradient(circle at var(--o, 50% 50%), 
    var(--c0) var(--pos, 0%), var(--c1) 0);
  animation: a 0s infinite;
  animation-name: c0, o, pos, c1;
  animation-duration: 2*$t, $n*$t, $t;
  animation-timing-function: steps(1), steps(1), ease-in-out;
}

@keyframes o {
  @for $i from 0 to $n {
    #{$i*100%/$n} { --o: #{random(100)*1%} #{random(100)*1%} }
  }
}

Necesitamos registrar esta variable para que todo funcione:

CSS.registerProperty({
  name: '--o', 
  syntax: '<length-percentage>', 
  initialValue: '50%', 
  inherits: true
});

¡Y eso es! El resultado se puede ver a continuación:

GIF animado.  Comenzamos con un fondo gris y tenemos un disco naranja, posicionado al azar, que crece desde la nada hasta que cubre todo, así que ahora parece que tenemos un fondo naranja.  Luego tenemos un disco gris, posicionado al azar, que crece desde la nada hasta que cubre todo el fondo y estamos de regreso donde comenzamos: un fondo gris.Discos en crecimiento colocados aleatoriamente (demostración en vivo, navegadores Blink con bandera únicamente).

Diría que el futuro de cambiar gradientes con animaciones de fotogramas clave se ve muy bien. Pero mientras tanto, para las soluciones de navegador cruzado, la forma de JavaScript sigue siendo la única válida.

(Visited 27 times, 1 visits today)