<a href="https://youtu.be/PDSWq6WaJMk" target="_blank" data-keyframers-credit style="color: #000"></a>
<script src="https://codepen.io/shshaw/pen/QmZYMG.js"></script>
<main id="app">
<div class="product">
<figure class="photo">
<img src="https://source.unsplash.com/RECZjSWMPVI/1200x900" alt="">
</figure>
<div class="title">
<h2>
<div><span>BEEF</span></div>
<div><span>WELLINGTON</span></div>
<div><span>CHAIR</span></div>
</h2>
</div>
</div>
<div class="product">
<figure class="photo">
<img src="https://source.unsplash.com/3IX-Tz_0ZN0/1200x900" alt="">
</figure>
<div class="title">
<h2>
<div><span>SO MANY</span></div>
<div><span>CHAIR</span></div>
<div><span>TABLES</span></div>
</h2>
</div>
</div>
<div class="product">
<figure class="photo">
<img src="https://source.unsplash.com/hTPUYIIvZBY/1200x900" alt="">
</figure>
<div class="title">
<h2>
<div><span>I HAVE</span></div>
<div><span>THIS IKEA</span></div>
<div><span>CHAIR</span></div>
</h2>
</div>
</div>
<div class="product">
<figure class="photo">
<img src="https://source.unsplash.com/m1JPKkCHhkc/1200x900" alt="">
</figure>
<div class="title">
<h2>
<div><span>CLOSE-UP</span></div>
<div><span>OF A</span></div>
<div><span>CHAIR</span></div>
</h2>
</div>
</div>
<div class="mouse-tracker">
</div>
</main>
@import url("https://fonts.googleapis.com/css?family=Roboto");
*,
*:before,
*:after {
box-sizing: border-box;
position: relative; // fight me
}
body,
html {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
font-family: Roboto, Helvetica, sans-serif;
font-size: 300;
background: #aaa;
}
// _+_+_+_+_+_+_+_+_+-=-=3-=-3=-=3-=3-3=-3=-
#app {
height: 100%;
width: 100%;
&:before, &:after {
position: absolute;
font-size: 3vmin;
letter-spacing: -.1vmin;
z-index: 100000;
}
&:before {
content: 'KEY FRAMERS';
position: absolute;
top: 2vh;
left: 2vw;
}
&:after {
content: attr(data-product) ' / ' attr(data-product-count);
position: absolute;
bottom: 2vh;
left: 2vw;
font-size: 6vmin;
}
}
.product {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
&:after {
content: "";
}
> .photo {
grid-column: 1 / -1;
grid-row: 1 / -1;
margin: 0;
background: #fff;
img {
opacity: 0.8;
display: block;
object-fit: cover;
width: 100%;
height: 100%;
}
}
> .title {
grid-column: 2;
grid-row: 2;
font-size: 8vmin;
line-height: 1;
display: flex;
flex-direction: column;
justify-content: flex-end;
padding: 1rem;
h2 {
margin: 0;
font-weight: 300;
letter-spacing: -0.5vmin;
line-height: 0.9;
}
span {
display: block;
white-space: nowrap;
overflow: hidden;
}
}
}
.title div {
overflow: hidden;
&:nth-child(2) {
text-align: center;
}
&:nth-child(3) {
text-align: right;
}
}
/* ---------------------------------- */
:root {
--duration: 1s;
--easing: cubic-bezier(.2, 0, .3, 1);
}
.product {
> .photo {
mask-image: radial-gradient(#000 70%, transparent 70.1%);
mask-repeat: no-repeat;
mask-position: center center;
// Thanks to JoseG
// https://cdpn.io/pen/qwxOeM
mask-position:
calc(var(--mouse-x) - 50vw + 50%)
calc(var(--mouse-y) - 50vh + 50%);
mask-size: 0vmax 0vmax;
transition: mask-size var(--duration) var(--easing);
transition-delay: 0.5s;
}
.title span {
transform: translateY(-100%);
transition: transform var(--duration) var(--easing);
}
.title div:nth-child(2) span {
transform: translateY(100%);
}
}
.product[data-active] {
z-index: 10;
> .photo {
mask-size: 300vmax 300vmax;
transition-delay: 0s;
}
.title span {
transform: none !important;
}
+ .product {
.title span {
visibility: hidden;
transform: translateY(100%);
}
.title div:nth-child(2) span {
transform: translateY(-100%);
}
}
}
/* ---------------------------------- */
:root {
--mouse-x: calc(50vw + 1px);
--mouse-y: calc(50vh + 1px);
}
.mouse-tracker {
z-index: 999;
position: fixed;
top: 0;
left: 0;
width: 10vmin;
height: 10vmin;
background: rgba(255,255,255,.2);
border-radius: 50%;
border: solid 2px #000;
opacity: 0.8;
transform:
translate(-50%, -50%)
translate(
var(--mouse-x),
var(--mouse-y)
// calc(var(--mouse-x) * 1px),
// calc(var(--mouse-y) * 1px)
);
pointer-events: none;
}
View Compiled
console.clear();
const elApp = document.querySelector("#app");
const elProducts = document.querySelectorAll(".product");
let product = 0;
elProducts[product].dataset.active = true;
elApp.dataset.product = product + 1;
elApp.dataset.productCount = elProducts.length;
app.addEventListener("click", () => {
delete elProducts[product].dataset.active;
product = (product + 1) % elProducts.length;
elApp.dataset.product = product + 1;
elProducts[product].dataset.active = true;
});
/* ---------------------------------- */
document.addEventListener("mousemove", e => {
document.documentElement.style.setProperty("--mouse-x", e.clientX +'px');
document.documentElement.style.setProperty("--mouse-y", e.clientY +'px');
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.