console
console.clear();
Splitting("h1[data-splitting]").forEach((split) => {
console.log(split);
split.chars.forEach((char) =>
char.style.setProperty("--random", Math.random())
);
});
const elApp = document.querySelector("#app");
const elButtons = Array.from(
document.querySelectorAll(".section .nav"),
(elButton) => {
elButton.addEventListener("click", (e) => {
elApp.dataset.state = "single";
const elSection = elButton.closest(".section");
flip(() => {
delete document.querySelector("[data-active]")?.dataset.active;
elSection.dataset.active = true;
}, elSection);
});
return elButton;
}
);
const elContents = Array.from(
document.querySelectorAll(".section .content"),
(elContent) => {
elContent.addEventListener("click", (e) => {
elApp.dataset.state = "grid";
const elSection = elContent.closest(".section");
flip(() => {
delete document.querySelector("[data-active]")?.dataset.active;
}, elSection);
});
return elContent;
}
);
const getRect = (el) => {
return el.getBoundingClientRect();
};
function flip(doSomething, firstEl, getLastEl = () => firstEl) {
const firstRect = getRect(firstEl);
requestAnimationFrame(() => {
doSomething();
let lastEl = getLastEl();
const lastRect = getRect(lastEl);
const dx = lastRect.x - firstRect.x;
const dy = lastRect.y - firstRect.y;
const dw = lastRect.width / firstRect.width;
const dh = lastRect.height / firstRect.height;
console.log({ dx, dy, dw, dh });
lastEl.dataset.flipping = true;
lastEl.style.setProperty("--dx", dx);
lastEl.style.setProperty("--dy", dy);
lastEl.style.setProperty("--dw", dw);
lastEl.style.setProperty("--dh", dh);
requestAnimationFrame(() => {
delete lastEl.dataset.flipping;
});
});
}
elButtons[0].click();
setTimeout(() => {
elContents[0].click();
}, 1500);
<div id="app" data-state="none">
<h1 class="title color" data-splitting>Select File</h1>
<div class="wrapper">
<div class="section">
<div class="inner">
<button class="nav">1</button>
<div class="content">1</div>
</div>
</div>
<span class="color" data-splitting>New</span>
</div>
<div class="wrapper">
<div class="section">
<div class="inner">
<button class="nav">2</button>
<div class="content">2</div>
</div>
</div>
<span class="color" data-splitting>New</span>
</div>
<div class="wrapper">
<div class="section">
<div class="inner">
<button class="nav">3</button>
<div class="content">3</div>
</div>
</div>
<span class="color" data-splitting>New</span>
</div>
<div class="wrapper">
<div class="section">
<div class="inner">
<button class="nav">4</button>
<div class="content">4</div>
</div>
</div>
<span class="color" data-splitting>New</span>
</div>
</div>
<a href="https://youtu.be/VdZKGG19vmw" target="_blank" data-keyframers-credit style="color: #000"></a>
<script src="https://codepen.io/shshaw/pen/QmZYMG.js"></script>
@import url("https://fonts.googleapis.com/css2?family=Bangers&display=swap");
$gold: #d6ac0e;
$green: #259200;
$gray: #abb1ac;
$pink: #eb87a1;
$yellow: #efbb19;
$blue: #347bdf;
*,
*::before,
*::after {
box-sizing: border-box;
position: relative;
}
html {
background: $gold;
height: 100%;
border: inset 5vmin rgba(darken($gold, 10%), 0.5);
padding: 4vmin 8vmin;
overflow: hidden;
}
body {
height: 100%;
}
#app {
height: 100%;
display: grid;
grid-template-columns: minmax(auto, 1fr) minmax(auto, 1fr);
grid-template-rows: auto 1fr 1fr 10%;
grid-gap: 2rem;
justify-items: space-around;
align-content: space-around;
> h1 {
grid-row: 1;
grid-column: 1 / -1;
text-align: center;
margin: 0;
}
}
.section {
display: grid;
z-index: 1;
align-self: stretch;
.nav {
border: outset 1em lighten($gray, 10%);
background: $gray;
transition: border-width 1s;
cursor: pointer;
}
.content {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
background: #fff;
display: flex;
justify-content: center;
align-items: center;
font-size: 5vmin;
z-index: -1;
cursor: zoom-out;
}
transition: transform 1s cubic-bezier(0.2, 0, 0.5, 1), z-index 1s linear;
transform-origin: top left;
&[data-active] {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10;
.content {
z-index: 2;
}
}
&[data-flipping] {
transition: none;
z-index: 10;
transform: translateX(calc(-1px * var(--dx)))
translateY(calc(-1px * var(--dy)))
scale(calc(1 / var(--dw)), calc(1 / var(--dh)));
.nav {
border-width: calc(1em * var(--dw));
transition: none;
}
}
> .inner {
height: 100%;
width: 100%;
transform-style: preserve-3d;
perspective: 800px;
transition: inherit;
> .nav,
> .content {
transform-style: preserve-3d;
height: 100%;
width: 100%;
backface-visibility: visible;
}
> .nav {
transform: translateZ(1px);
}
> .content {
transform: translateZ(-1px) rotateY(0.5turn);
}
}
&[data-active][data-flipping] {
> .inner {
transition: none;
transform: rotateY(0turn) rotateZ(0turn);
}
}
&:not([data-active])[data-flipping] {
> .inner {
transform: rotateY(0.5turn) rotateZ(1turn);
}
}
&[data-active]:not([data-flipping]) {
> .inner {
transform: rotateY(0.5turn) rotateZ(1turn);
}
}
}
.wrapper {
display: grid;
grid-template-columns: 50% 1fr;
align-items: center;
grid-gap: 1rem;
}
.wrapper .color {
grid-column: 2;
display: block;
}
.section:hover + .color .char {
animation: wiggle 0.3s linear alternate infinite;
animation-delay: calc(-0.6s * var(--random));
@keyframes wiggle {
to {
transform: rotate(calc((var(--random) - 0.5) * -9deg)) scale(1.2);
}
}
}
.color {
color: $yellow;
text-shadow: 1px 1px rgba(#000, 0.5), -1px -1px rgba(#fff, 0.5);
transform: scaleX(1.3) skewX(10deg);
transform-origin: 0 0;
font-size: 6vw;
letter-spacing: 0.05em;
font-family: "Bangers", cursive;
.char {
transform: rotate(calc((var(--random) - 0.5) * 9deg));
&::before {
z-index: 1;
color: transparent;
visibility: visible;
background: linear-gradient(to bottom, transparent 40%, #fff);
background-size: cover;
background-clip: text;
text-shadow: none;
}
}
.char:nth-child(3n + 2) {
color: $pink;
}
.char:nth-child(3n + 1) {
color: $green;
}
.char:nth-child(4n + 1) {
color: $blue;
}
}
.title {
transform-origin: center center;
font-size: 10vw;
}