1 elemento HTML + 5 propiedades CSS = ¡Magia!

Índice
  1. CSS-ing los rayos degradados
  2. Rayos y ondas degradados con CSS

Digamos que te dije que podemos obtener los siguientes resultados con solo un elemento HTML y cinco propiedades CSS para cada uno. Sin SVG, sin imágenes (excepto backgrounden la raíz que está ahí solo para dejar en claro que nuestro único elemento HTML tiene algunas partes transparentes), sin JavaScript. ¿Qué crees que implica eso?

Bueno, este artículo explicará cómo hacer esto y luego también mostrará cómo hacer las cosas divertidas agregando algo de animación.

CSS-ing los rayos degradados

El HTML es sólo uno div.

*/ mask: repeating-conic-gradient(#000 0% .5*$p, transparent 0% $p);}

Tenga en cuenta que, a diferencia de los gradientes lineales y radiales, las posiciones de parada para los gradientes cónicos no pueden ser sin unidades. Deben ser porcentajes o valores angulares. Esto significa que usar algo como transparent 0 $pno funciona, necesitamos transparent 0% $p(o 0degen lugar de 0%, no importa cuál elijamos, simplemente no puede ser sin unidades).

Hay algunas cosas a tener en cuenta aquí cuando se trata de soporte:

  • Edge no admite el enmascaramiento de elementos HTML en este momento, aunque esto aparece como En desarrollo y ya apareció una marca (que no hace nada por ahora) en about:flags.
  • conic-gradient()solo es compatible de forma nativa con los navegadores Blink que cuentan con la bandera de características de la Plataforma web experimental (que se puede habilitar desde chrome://flagso opera://flags). Safari también contará con soporte, pero, hasta que eso suceda, Safari aún depende del polyfill, al igual que Firefox (o Edge cuando también admita el enmascaramiento en la próxima versión). Actualización : a partir de Chrome 69, conic-gradient()ya no está detrás de una bandera; ahora funciona en cualquier navegador Blink actualizado, independientemente de que la bandera esté habilitada o no.
  • Los navegadores WebKit aún necesitan el -webkit-prefijo para masklas propiedades de los elementos HTML. Se podría pensar que eso no es un problema ya que estamos usando el polyfill que depende de -prefix-free de todos modos, por lo que, si usamos el polyfill, debemos incluir -prefix-free antes de eso de todos modos. Lamentablemente, es un poco más complicado que eso. Esto se debe a que -prefix-free funciona mediante la detección de funciones, lo que falla en este caso porque todos los navegadores admiten elementos masksin prefijo... ¡en elementos SVG! Pero aquí estamos usando maskun elemento HTML, por lo que estamos en la situación en la que los navegadores WebKit necesitan el -webkit-prefijo, pero -prefix-free no lo agregarán. Supongo que eso significa que debemos agregarlo manualmente:*/ -webkit-mask: $m; mask: $m;}

    Supongo que también podríamos usar Autoprefixer, incluso si necesitamos incluir -prefix-free de todos modos, pero usar ambos solo para esto se siente un poco como usar una escopeta para matar una mosca.

Añadiendo animación

Una de las ventajas de conic-gradient()que los navegadores Blink admitan de forma nativa es que podemos usar variables CSS en su interior (no podemos hacerlo cuando usamos polyfill). Y ahora las variables CSS también se pueden animar en los navegadores Blink con un poco de magia de Houdini (necesitamos que la bandera de características de la plataforma web experimental esté habilitada para eso, aunque ya no la necesitamos para la conic-gradient()compatibilidad nativa a partir de Chrome 69+).

Para preparar nuestro código para la animación, cambiamos nuestro gradiente de enmascaramiento para que utilice valores alfa variables:

*/ animation: a 2s linear infinite alternate;}@keyframes a { to { --a: 0 } }

Esto nos da el siguiente resultado:

Meh. No se ve muy bien. Sin embargo, podríamos hacer las cosas más interesantes usando múltiples valores alfa:

*/ animation: a 2s infinite alternate; animation-name: a0, a1, a2, a3; animation-timing-function: /* easings from easings.net */ cubic-bezier(.57, .05, .67, .19) /* easeInCubic */, cubic-bezier(.21, .61, .35, 1); /* easeOutCubic */}@for $i from 0 to 4 { @keyframes a#{$i} { to { --a#{$i}: #{floor($i/2)} } }}

Tenga en cuenta que, dado que estamos configurando valores para propiedades personalizadas, necesitamos interpolar la floor()función.

Ahora parece un poco más interesante, pero ¿seguramente podemos hacerlo mejor?

Intentemos utilizar una variable CSS para la posición de detención entre el rayo y el espacio:

*/ animation: p .5s linear infinite alternate}@keyframes p { to { --p: #{$p} } }

El resultado es más interesante en este caso:

Pero aún podemos darle un poco más de sabor volteando todo horizontalmente entre cada iteración, de modo que siempre esté volteado para las reversas. Esto significa que no se invierte cuando --pva de 0%a $py se invierte cuando --pvuelve de $pa 0%.

La forma en que volteamos un elemento horizontalmente es aplicándole un transform: scalex(-1). Como queremos que este giro se aplique al final de la primera iteración y luego se elimine al final de la segunda (inversa), lo aplicamos animationtambién en un fotograma clave, en uno con una steps()función de temporización y el doble de animation-duration.

*/ animation: p $t linear infinite alternate, s 2*$t steps(1) infinite;}@keyframes p { to { --p: #{$p} } }@keyframes s { 50% { transform: scalex(-1); } }

Ahora finalmente tenemos un resultado que realmente se ve bastante genial:

Rayos y ondas degradados con CSS

Para obtener el resultado de rayos y ondas, necesitamos agregar un segundo degradado al mask, esta vez un repeating-radial-gradient().

*/ mask: $m;}

Lamentablemente, el uso de varias posiciones de parada solo funciona en los navegadores Blink con la misma bandera de características de la Plataforma web experimentalconic-gradient() habilitada. Y si bien polyfill cubre esto para la repeating-conic-gradient()parte en los navegadores que admiten enmascaramiento CSS en elementos HTML, pero no admiten gradientes cónicos de forma nativa (Firefox, Safari, navegadores Blink sin la bandera habilitada), nada soluciona el problema para la repeating-radial-gradient()parte en estos navegadores.

Esto significa que estamos obligados a tener alguna repetición en nuestro código:

*/ mask: $m;}

Obviamente nos estamos acercando, pero aún no hemos llegado:

Para obtener el resultado que queremos, debemos usar la mask-compositepropiedad y establecerla en exclude.

mask-compositePor ahora, solo se admite en Firefox 53+, aunque los navegadores WebKit tienen un muy buen soporte (desde Chrome 1.0 y Safari 4.0) para una propiedad no estándar similar, , -webkit-mask-compositeque nos ayuda a obtener el mismo resultado para un valor de xory Edge debería unirse cuando finalmente admita el enmascaramiento CSS en elementos HTML. Sin embargo, tenga en cuenta que Edge admitirá tanto como mask-compositecon -webkit-mask-compositelos valores estándar, aunque cualquiera que use -webkit-mask-compositenavegadores WebKit probablemente lo usará con los no estándar, ya que de lo contrario ni siquiera funciona en navegadores WebKit.

*/ -webkit-mask: $lyr1, $lyr0; -webkit-mask-composite: xor; mask: $lyr1 exclude, $lyr0}

Tenga en cuenta que lo no estándar -webkit-mask-compositeno se puede utilizar en la -webkit-maskabreviatura de la misma manera que utilizamos el estándar mask-compositeen la maskabreviatura de Firefox.

Si crees que parece que los rayos y los espacios entre ellos no son iguales en los navegadores que no los admiten conic-gradient()de forma nativa, tienes razón. Esto se debe a un problema de polyfill.

Añadiendo animación

Dado que el estándar mask-compositesolo funciona en Firefox por ahora y Firefox aún no lo admite conic-gradient()de forma nativa, no podemos colocar variables CSS dentro repeating-conic-gradient()(porque Firefox todavía recurre al polyfill y el polyfill no admite el uso de variables CSS). Pero podemos ponerlos dentro repeating-radial-gradient()e incluso si no podemos animarlos con animaciones de fotogramas clave CSS, ¡podemos hacerlo con JavaScript!

Debido a que ahora estamos colocando variables CSS dentro de repeating-radial-gradient(), pero no dentro de repeating-conic-gradient()(ya que queremos una mejor compatibilidad con el navegador y Firefox no admite gradientes cónicos de forma nativa, por lo que recurre al polyfill, que no admite el uso de variables CSS), Ya no podemos usar lo mismo $stop-listpara ambas capas de degradado mask.

Pero si de todos modos tenemos que reescribir nuestro masksin un común $stop-list, podemos aprovechar esta oportunidad para usar diferentes posiciones de parada para los dos gradientes:

*/ --c0: #{rgba(#000, var(--a))}; --c1: #{rgba(#000, calc(1 - var(--a)))}; -webkit-mask: $lyr1, $lyr0; -webkit-mask-composite: xor; mask: $lyr1 exclude, $lyr0}

La variable alfa --aes la que animamos de ida y vuelta (de 0a 1y luego de 0nuevo a) con un poco de JavaScript básico. Comenzamos estableciendo un número total de fotogramas NFen los que se desarrolla la animación, un índice de fotograma actual fy una dirección de animación actual dir:

*/let rID = null;function stopAni() { cancelAnimationFrame(rID); rID = null};function update() { /* same as before */ if(!(f%NF)) { stopAni(); return } rID = requestAnimationFrame(update)};

Al hacer clic, detenemos cualquier animación que pueda estar ejecutándose, invertimos la dirección de la animación diry llamamos a la update()función:

*/function easeInOut(k) { return .5*(Math.sin((k - .5)*Math.PI) + 1)};(function update() { f += dir; document.body.style.setProperty('--p', easeInOut(f/NF).toFixed(2)); /* same as before */})();

Podemos hacer más interesante el efecto si añadimos una transparenttira antes de la opaca y también animamos el progreso de la posición de parada --p0donde pasamos de esta transparenttira a la opaca:

$lyr1: repeating-conic-gradient(#000 0% .5*$pc, transparent 0% $pc); $lyr0: repeating-radial-gradient(closest-side,            transparent, transparent calc(var(--p0)*#{$pr}),            #000, #000 calc(var(--p1)*#{$pr}),            transparent 0, transparent $pr);

En JavaScript, ahora necesitamos animar dos variables CSS: --p0y --p1. Usamos una ease-infunción de sincronización para la primera y una ease-outpara la segunda. Tampoco invertimos más la dirección de la animación:

const NF = 120,       TFN = {        'ease-in': function(k, e = 1.675) {          return Math.pow(k, e)        },         'ease-out': function(k, e = 1.675) {          return 1 - Math.pow(1 - k, e)        }      };let f = 0;(function update() {  f = (f + 1)%NF;  for(var i = 0; i  2; i++)    document.body.style.setProperty(`--p${i}`, TFN[i ? 'ease-out' : 'ease-in'](f/NF);    requestAnimationFrame(update)})();

Esto nos da un resultado bastante interesante:

SUSCRÍBETE A NUESTRO BOLETÍN 
No te pierdas de nuestro contenido ni de ninguna de nuestras guías para que puedas avanzar en los juegos que más te gustan.

Deja una respuesta

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

Subir

Este sitio web utiliza cookies para mejorar tu experiencia mientras navegas por él. Este sitio web utiliza cookies para mejorar tu experiencia de usuario. Al continuar navegando, aceptas su uso. Mas informacion