Hoy aprenderemos a animar máscaras css, apoyándonos en la posición del cursor para crear un efecto único para tu próximo proyecto web.
Demo
https://css-mask-effect.netlify.app/
Github
https://github.com/JairDev/css-mask-effect
El enmascaramiento en css, nos permite “cortar” (enmascarar ) un elemento, ya sea a través de una imagen, un svg o un degradado pudiendo establecer que parte serán o no visibles de ese elemento de acuerdo a la transparencia en la imagen, svg o degradado.
Como podemos ver en este ejemplo, nuestra imagen que servirá de máscara es el logo de apple, es totalmente negra con un fondo transparente y nuestro elemento a enmascarar tiene un fondo de color rosa.
*La imagen se aplica como máscara al elemento rosa, lo ilustré de esta manera para ver como actúa el fondo transparente de la imagen, solo serían dos elementos, mas adelante lo veremos.
Máscara aplicada
La parte mas oscura de nuestra imagen, svg o degradado hacen visible el elemento mientras que la parte mas trasparente ocultan el elemento.
Propiedad css mask:
La propiedad css mask es un shorthand para mask-image, mask-repeat, mask-position entre otras propiedades, https://developer.mozilla.org/es/docs/Web/CSS/mask.
.element {
mask-image: url("image-link");
mask-repeat: no-repeat;
mask-position: center;
...
}
Funciona parecido a la propiedad background de css, podemos establecer una imagen mediante una url, si queremos que se repita o no la máscara, de esta manera tenemos mas control sobre los efectos de nuestra máscara.
Ahora a ensuciarnos las manos ... 😎
Para nuestro efecto vamos a duplicar nuestro elemento .hero
.
<div class="container">
<div class="hero">
<div class="contain-name">
<h1>Hi, I am Kim,</h1>
<span>I am a</span>
<span>web developer.</span>
</div>
...
</div>
<div class="hero copy" aria-hidden="true">
<div class="contain-name">
<p>Hi, I am Kim,</p>
<span>I am a</span>
<span class="span web-developer">web developer.</span>
</div>
...
</div>
</container
Para mejorar la accesibilidad de nuestro contenido, hemos establecido el elemento duplicado en aria-hidden="true"
para evitar que sea mencionado dos veces por lectores de pantalla.
Enmascaramiento del elemento duplicado.
.hero.copy {
--mask: radial-gradient(
circle at 15% 50%,
black 25%,
transparent 0%
);
-webkit-mask: var(--mask);
mask: var(--mask);
}
Estilos
.container {
background: #18191c;
}
.hero {
opacity: 0.6;
}
.hero.copy {
background: #7f8189af;
filter: brightness(1.5);
opacity: 1;
}
.span.web-developer {
color: #ff03a0;
}
En el elemento .container
utilizamos un fondo oscuro y en nuestro elemento base .hero
establecemos una opacidad de 0.6 para dar una sensación de oscuridad.
Para la máscara utilizaremos un radial gradient, estableciendo el circulo que vemos a continuación, el fondo será de un color grisáceo para dar el efecto de un foco de luz blanca, aumentaremos un poco el brillo y resaltaremos el texto web developer con un color intenso.
Como puedes ver, la máscara que es un circulo se está aplicando a nuestro elemento, vamos a difuminar un poco el circulo asignando un 4% al inicio del gradiente y un 25% al final.
.hero.copy {
--mask: radial-gradient(
circle at 15% 50%,
black 4%,
transparent 25%
);
-webkit-mask: var(--mask);
mask: var(--mask);
}
El resultado ...
Rastrear la posición del cursor
Para lograr nuestro efecto de "movimiento de la luz", necesitamos rastrear el cursor de acuerdo al movimiento del usuario, JavaScript al rescate 💪
Primero definamos unas propiedades personalizadas "--x", "--y", y establezcamos una posición inicial para la máscara, 15% y 50% respectivamente.
--mask: radial-gradient(
circle at var(--x, 15%) var(--y, 50%),
black 4%,
transparent 25%
)
En nuestro archivo JS llamamos al evento "mousemove", obtenemos la posición del mouse y hacemos el cálculo para luego asignar ese valor porcentual a nuestras propiedades personalizadas --x y --y.
const hero = document.querySelector(".hero.copy");
window.addEventListener("mousemove", (e) => {
const x = Math.round((e.clientX / window.innerWidth) * 100);
const y = Math.round((e.clientY / window.innerHeight) * 100);
hero.style.setProperty("--x", `${x}%` )
hero.style.setProperty("--y", `${y}%`)
});
Al movimiento de nuestro "foco de luz" le falta un poco de suavidad para que no se sienta tenso. Para lograr esto utilizaré una biblioteca js de animaciones llamada gsap https://greensock.com/docs/, esta biblioteca nos permite establecer una transición de manera sencilla a nuestra máscara ya que estamos utilizando propiedades personalizadas.
npm install gsap
import gsap from "gsap";
const hero = document.querySelector(".hero.copy");
window.addEventListener("mousemove", (e) => {
const x = Math.round((e.clientX / window.innerWidth) * 100);
const y = Math.round((e.clientY / window.innerHeight) * 100);
gsap.to(hero, {
"--x": `${x}%`,
"--y": `${y}%`,
duration: 0.4,
ease: "sine.out",
});
});
Ahora nuestro movimiento se siente mas natural 😁
¡Espero este post haya sido de tu agrado!
Te invito a que juegues con las máscaras css y me enseñes ese próximo proyecto donde incluyas grandiosos efectos con esta propiedad.
Tu feedback es de mucha ayuda para mi 🙏
Conectemos 😎
https://twitter.com/JairDevep
https://www.linkedin.com/in/alfredo-moscoso-desarrollador-frontend/
¡Nos vemos pronto! 👊
Top comments (3)
Interesante! Buen artículo Alfredo.
Hola Leví gracias por tu comentario, si, es interesante las cosas que se pueden hacer con css y un poco de JavaScript, haz utilizado las máscaras de css para algún proyecto ?
Bastante interesante, aún no pero con esto quizás pueda aplicar algunas ideas, así que gracias por el artículo!