
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.
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%; }
}
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.
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
});
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:
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:
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);
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);
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} } }
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} } }
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:
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.