<section class="demo">
<button class="demo__toggle" id="toggle" type="button">Toggle layout</button>
<div class="demo__grid is-grid" id="grid">
<div class="demo__item" data-tone="a"><span>Aurora</span></div>
<div class="demo__item" data-tone="b"><span>Basalt</span></div>
<div class="demo__item" data-tone="c"><span>Cobalt</span></div>
<div class="demo__item" data-tone="d"><span>Dune</span></div>
<div class="demo__item" data-tone="e"><span>Ember</span></div>
<div class="demo__item" data-tone="f"><span>Frost</span></div>
</div>
</section>.demo {
min-height: 100dvh;
display: flex;
flex-direction: column;
justify-content: center;
gap: 18px;
padding: 28px 24px;
background: #08080a;
color: #f4f4f2;
font-family: "Helvetica Neue", Inter, system-ui, sans-serif;
}
.demo__toggle {
align-self: flex-start;
border: 1px solid #26262c;
background: transparent;
color: #b8b8bd;
border-radius: 999px;
padding: 8px 16px;
font: inherit;
font-size: 11px;
letter-spacing: 0.16em;
text-transform: uppercase;
cursor: pointer;
transition: color 0.25s, border-color 0.25s;
}
.demo__toggle:hover { color: #f4f4f2; border-color: #4a4a54; }
.demo__grid { display: grid; gap: 10px; }
.demo__grid.is-grid { grid-template-columns: repeat(3, 1fr); }
.demo__grid.is-list { grid-template-columns: 1fr; gap: 8px; }
.demo__item {
border-radius: 14px;
border: 1px solid rgba(255, 255, 255, 0.07);
display: flex;
align-items: flex-end;
padding: 12px;
font-size: 13px;
letter-spacing: -0.01em;
}
.is-grid .demo__item { height: 84px; }
.is-list .demo__item { height: 34px; align-items: center; }
.demo__item[data-tone="a"] { background: linear-gradient(150deg, #2b2f4a, #14161f); }
.demo__item[data-tone="b"] { background: linear-gradient(150deg, #23262a, #101113); }
.demo__item[data-tone="c"] { background: linear-gradient(150deg, #1b3350, #0c1420); }
.demo__item[data-tone="d"] { background: linear-gradient(150deg, #3a3123, #17130d); }
.demo__item[data-tone="e"] { background: linear-gradient(150deg, #4a2422, #1d0f0e); }
.demo__item[data-tone="f"] { background: linear-gradient(150deg, #26404a, #0f181d); }gsap.registerPlugin(Flip);
const grid = document.querySelector("#grid");
const items = gsap.utils.toArray(".demo__item");
const toggle = document.querySelector("#toggle");
let animating = false;
function switchLayout() {
// 전환 도중 다시 누르면 인라인 스타일이 남으므로 잠급니다.
if (animating) return;
animating = true;
// 1) 현재 위치를 기록하고
const state = Flip.getState(items);
// 2) 레이아웃을 즉시 바꾼 뒤
grid.classList.toggle("is-grid");
grid.classList.toggle("is-list");
// 3) 그 차이를 FLIP이 애니메이션으로 메웁니다.
Flip.from(state, {
duration: 0.72,
ease: "power3.inOut",
stagger: 0.03,
absolute: true,
onComplete: () => { animating = false; },
});
}
toggle.addEventListener("click", switchLayout);