Spotlight Glowing Cards
You can use these as standard cards and ass icons, heading, buttons and more but I used these to call attention to my three website design ideals that govern every project.
Here is the finished result of my implementation:
Now for the code to get this running on your website.
First the HTML:
<div class="container">
<main class="flow main">
<div class="cards">
<div class="cards_inner">
<div class="card">
<h2 class="card_heading">
User experience is key to fostering conversions & improving efficiency
</h2>
</div>
<div class="card">
<h2 class="card_heading">
Usability & intuitive function create the backbone to good design
</h2>
</div>
<div class="card">
<h2 class="card_heading">
Focus on delivering the best possible result & giving more than expected
</h2>
</div>
</div>
<div class="cards_inner overlay"></div>
</div>
</main>
</div>
The CSS:
@import url(https://fonts.googleapis.com/css2?family=Rubik:wght@300;400;500&display=swap);
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
overflow: hidden;
background-color: #121212;
}
.container {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.main {
padding: 2rem;
display: flex;
align-items: center;
justify-content: center;
}
.cards {
position: relative;
}
.cards_inner {
display: flex;
flex-wrap: wrap;
gap: 2.5rem;
}
.card {
--flow-space: 0.5em;
--hsl: var(--hue), var(--saturation), var(--lightness);
flex: 1 1 14rem;
padding: 1rem 1rem;
display: grid;
align-items: center;
gap: 1.25rem;
color: #fff;
background-color: #292929;
border: 1px solid #eceff133;
border-radius: 15px;
}
.card:nth-child(1) {
--hue: 0;
--saturation: 70%;
--lightness: 50%;
}
.card:nth-child(2) {
--hue: 135;
--saturation: 100%;
--lightness: 100%;
}
.card:nth-child(3) {
--hue: 0.69;
--saturation: 85%;
--lightness: 70.04%;
}
.card_heading {
font-family: "Rubik", sans-serif;
font-size: 1.5rem;
line-height: normal;
font-weight: 400;
}
.flow > * + * {
margin-top: var(--flow-space, 1.25em);
}
.overlay {
position: absolute;
inset: 0;
pointer-events: none;
user-select: none;
opacity: var(--opacity, 0);
-webkit-mask: radial-gradient(
25rem 25rem at var(--x) var(--y),
#000 1%,
transparent 50%
);
mask: radial-gradient(
25rem 25rem at var(--x) var(--y),
#000 1%,
transparent 50%
);
transition: 400ms mask ease;
will-change: mask;
}
.overlay .card {
background-color: hsla(var(--hsl), 0.15);
border-color: hsla(var(--hsl), 1);
box-shadow: 0 0 0 1px inset hsl(var(--hsl));
}
:not(.overlay) > .card {
transition: 400ms background ease;
will-change: background;
}
:not(.overlay) > .card:hover {
--lightness: 95%;
background: hsla(var(--hsl), 0.1);
}
And last, the Javascript:
const cardsContainer = document.querySelector(".cards");
const cardsContainerInner = document.querySelector(".cards_inner");
const cards = Array.from(document.querySelectorAll(".card"));
const overlay = document.querySelector(".overlay");
const applyOverlayMask = (e) => {
const overlayEl = e.currentTarget;
const x =
e.clientX - cardsContainer.getBoundingClientRect().left + window.scrollX;
const y =
e.clientY - cardsContainer.getBoundingClientRect().top + window.scrollY;
overlayEl.style = `--opacity: 1; --x: ${x}px; --y:${y}px;`;
};
const createOverlayCta = (overlayCard, ctaEl) => {
const overlayCta = document.createElement("div");
overlayCta.setAttribute("aria-hidden", true);
overlayCard.append(overlayCta);
};
const observer = new ResizeObserver((entries) => {
entries.forEach((entry) => {
const cardIndex = cards.indexOf(entry.target);
let width = entry.borderBoxSize[0].inlineSize;
let height = entry.borderBoxSize[0].blockSize;
if (cardIndex >= 0) {
overlay.children[cardIndex].style.width = `${width}px`;
overlay.children[cardIndex].style.height = `${height}px`;
}
});
});
const initOverlayCard = (cardEl) => {
const overlayCard = document.createElement("div");
overlayCard.classList.add("card");
createOverlayCta(overlayCard, cardEl.lastElementChild);
overlay.append(overlayCard);
observer.observe(cardEl);
};
cards.forEach(initOverlayCard);
document.body.addEventListener("pointermove", applyOverlayMask);
You can check this out for yourself and be able to edit the code on CodePen