03Cut-out frame card grid
Three cards are pasted at different angles and straighten to zero degrees in turn, 0.24s apart.
Best forWork grids and three-column feature cards
시차 0.24s각도 복원radius 4

<main class="stage">
<section class="ccol">
<article class="ccol__card ccol__card--coral">
<span class="ccol__photo" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 256 256" fill="currentColor"><path d="M208,64H176L160,40H96L80,64H48A16,16,0,0,0,32,80V192a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V80A16,16,0,0,0,208,64ZM128,168a36,36,0,1,1,36-36A36,36,0,0,1,128,168Z" opacity="0.2"/><path d="M208,56H180.28L166.65,35.56A8,8,0,0,0,160,32H96a8,8,0,0,0-6.65,3.56L75.71,56H48A24,24,0,0,0,24,80V192a24,24,0,0,0,24,24H208a24,24,0,0,0,24-24V80A24,24,0,0,0,208,56Zm8,136a8,8,0,0,1-8,8H48a8,8,0,0,1-8-8V80a8,8,0,0,1,8-8H80a8,8,0,0,0,6.66-3.56L100.28,48h55.43l13.63,20.44A8,8,0,0,0,176,72h32a8,8,0,0,1,8,8ZM128,88a44,44,0,1,0,44,44A44.05,44.05,0,0,0,128,88Zm0,72a28,28,0,1,1,28-28A28,28,0,0,1,128,160Z"/></svg>
</span>
<p class="ccol__no">01</p>
<p class="ccol__name">Photos</p>
</article>
<article class="ccol__card ccol__card--sky">
<span class="ccol__photo" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 256 256" fill="currentColor"><path d="M224,127.17a96.48,96.48,0,0,1-2.39,22.18A24,24,0,0,1,198.21,168H152a24,24,0,0,0-24,24,24,24,0,0,1-32,22.61C58.73,201.44,32,169.81,32,128a96,96,0,0,1,95-96C179.84,31.47,223.55,74.35,224,127.17Z" opacity="0.2"/><path d="M200.77,53.89A103.27,103.27,0,0,0,128,24h-1.07A104,104,0,0,0,24,128c0,43,26.58,79.06,69.36,94.17A32,32,0,0,0,136,192a16,16,0,0,1,16-16h46.21a31.81,31.81,0,0,0,31.2-24.88,104.43,104.43,0,0,0,2.59-24A103.28,103.28,0,0,0,200.77,53.89Zm13,93.71A15.89,15.89,0,0,1,198.21,160H152a32,32,0,0,0-32,32,16,16,0,0,1-21.31,15.07C62.49,194.3,40,164,40,128a88,88,0,0,1,87.09-88h.9a88.35,88.35,0,0,1,88,87.25A88.86,88.86,0,0,1,213.81,147.6ZM140,76a12,12,0,1,1-12-12A12,12,0,0,1,140,76ZM96,100A12,12,0,1,1,84,88,12,12,0,0,1,96,100Zm0,56a12,12,0,1,1-12-12A12,12,0,0,1,96,156Zm88-56a12,12,0,1,1-12-12A12,12,0,0,1,184,100Z"/></svg>
</span>
<p class="ccol__no">02</p>
<p class="ccol__name">Color field</p>
</article>
<article class="ccol__card ccol__card--grape">
<span class="ccol__photo" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 256 256" fill="currentColor"><path d="M128,48,68.32,70.38a8,8,0,0,0-5.08,6.17L40,216l139.45-23.24a8,8,0,0,0,6.17-5.08L208,128Zm-4,104a20,20,0,1,1,20-20A20,20,0,0,1,124,152Z" opacity="0.2"/><path d="M248,92.68a15.86,15.86,0,0,0-4.69-11.31L174.63,12.68a16,16,0,0,0-22.63,0L123.57,41.11l-58,21.77A16.06,16.06,0,0,0,55.35,75.23L32.11,214.68A8,8,0,0,0,40,224a8.4,8.4,0,0,0,1.32-.11l139.44-23.24a16,16,0,0,0,12.35-10.17l21.77-58L243.31,104A15.87,15.87,0,0,0,248,92.68Zm-69.87,92.19L63.32,204l47.37-47.37a28,28,0,1,0-11.32-11.32L52,192.7,71.13,77.86,126,57.29,198.7,130ZM112,132a12,12,0,1,1,12,12A12,12,0,0,1,112,132Zm96-15.32L139.31,48l24-24L232,92.68Z"/></svg>
</span>
<p class="ccol__no">03</p>
<p class="ccol__name">Type</p>
</article>
</section>
</main>@use "../../../../site/static/demo-tokens" as *;
// 콜라주·맥시멀 팔레트 (01 과 같은 값). 색면 위 글자는 흰색, 크림 위 글자는 ink·slate
$cg-cream: #fbf3e4;
$cg-sheet: #ffffff;
$cg-ink: #241d2e;
$cg-slate: #57506a;
$cg-coral: #bb7f74;
$cg-sky: #668cb4;
$cg-grape: #6b3fa0;
$cg-lemon: #d1c8a3;
$cg-lime: #bfce9c;
$serif: Georgia, "Nanum Myeongjo", "Times New Roman", serif;
$duration: $dur-loop; // 카드 한 장이 펴졌다 다시 기우는 한 주기
$easing: $ease-spring;
$color: $cg-coral; // 첫 카드의 색면
@include stage($cg-cream);
.ccol {
display: flex;
align-items: flex-start;
gap: $sp-3;
}
// 오려 붙인 카드 — 흰 여백이 사진 테두리 노릇을 한다
.ccol__card {
box-sizing: border-box;
width: 84px;
padding: $sp-2 $sp-2 $sp-1;
border-radius: $r-xs;
background: $cg-sheet;
box-shadow: 0 5px 0 rgba($cg-ink, .16);
animation-name: cardStraighten;
animation-duration: $duration;
animation-timing-function: $easing;
animation-iteration-count: infinite;
}
.ccol__card--coral { --rot: -7deg; }
.ccol__card--sky { --rot: 5deg; animation-delay: -.24s; }
.ccol__card--grape { --rot: -4deg; animation-delay: -.48s; }
.ccol__photo {
display: grid;
place-items: center;
height: 56px;
border-radius: $r-xs;
color: $cg-sheet;
font-size: 24px;
}
.ccol__card--coral .ccol__photo { background: linear-gradient(150deg, $cg-coral 0%, $cg-lemon 100%); }
.ccol__card--sky .ccol__photo { background: linear-gradient(150deg, $cg-sky 0%, $cg-lime 100%); }
.ccol__card--grape .ccol__photo { background: linear-gradient(150deg, $cg-grape 0%, $cg-coral 100%); }
.ccol__no {
margin: $sp-2 0 0;
color: $cg-coral;
font-family: $serif;
font-weight: 700;
font-size: 12px;
line-height: 1;
}
.ccol__name {
margin: $sp-1 0 0;
color: $cg-ink;
font-family: $serif;
font-weight: 700;
font-size: 15px;
line-height: 1;
}
// 데모: 붙인 각도에서 0도까지 펴졌다 되돌아간다 — 세 장이 0.24초씩 어긋난다
@keyframes cardStraighten {
0%, 100% { transform: rotate(var(--rot)); box-shadow: 0 5px 0 rgba($cg-ink, .16); }
45% { transform: rotate(0deg) translateY(-8px); box-shadow: 0 13px 0 rgba($cg-ink, .12); }
}
@media (max-width: 360px), (max-height: 230px) {
.ccol { gap: $sp-2; }
.ccol__card { width: 64px; padding: $sp-1; }
.ccol__photo { height: 40px; font-size: 18px; }
.ccol__name { font-size: 13px; }
}
@media (prefers-reduced-motion: reduce) {
.ccol__card { animation: none !important; transform: rotate(var(--rot)); }
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #fbf3e4;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.ccol {
display: flex;
align-items: flex-start;
gap: 12px;
}
.ccol__card {
box-sizing: border-box;
width: 84px;
padding: 8px 8px 4px;
border-radius: 4px;
background: #ffffff;
box-shadow: 0 5px 0 rgba(36, 29, 46, 0.16);
animation-name: cardStraighten;
animation-duration: 2s;
animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1);
animation-iteration-count: infinite;
}
.ccol__card--coral {
--rot: -7deg;
}
.ccol__card--sky {
--rot: 5deg;
animation-delay: -0.24s;
}
.ccol__card--grape {
--rot: -4deg;
animation-delay: -0.48s;
}
.ccol__photo {
display: grid;
place-items: center;
height: 56px;
border-radius: 4px;
color: #ffffff;
font-size: 24px;
}
.ccol__card--coral .ccol__photo {
background: linear-gradient(150deg, #bb7f74 0%, #d1c8a3 100%);
}
.ccol__card--sky .ccol__photo {
background: linear-gradient(150deg, #668cb4 0%, #bfce9c 100%);
}
.ccol__card--grape .ccol__photo {
background: linear-gradient(150deg, #6b3fa0 0%, #bb7f74 100%);
}
.ccol__no {
margin: 8px 0 0;
color: #bb7f74;
font-family: Georgia, "Nanum Myeongjo", "Times New Roman", serif;
font-weight: 700;
font-size: 12px;
line-height: 1;
}
.ccol__name {
margin: 4px 0 0;
color: #241d2e;
font-family: Georgia, "Nanum Myeongjo", "Times New Roman", serif;
font-weight: 700;
font-size: 15px;
line-height: 1;
}
@keyframes cardStraighten {
0%, 100% {
transform: rotate(var(--rot));
box-shadow: 0 5px 0 rgba(36, 29, 46, 0.16);
}
45% {
transform: rotate(0deg) translateY(-8px);
box-shadow: 0 13px 0 rgba(36, 29, 46, 0.12);
}
}
@media (max-width: 360px), (max-height: 230px) {
.ccol {
gap: 8px;
}
.ccol__card {
width: 64px;
padding: 4px;
}
.ccol__photo {
height: 40px;
font-size: 18px;
}
.ccol__name {
font-size: 13px;
}
}
@media (prefers-reduced-motion: reduce) {
.ccol__card {
animation: none !important;
transform: rotate(var(--rot));
}
}import type { CSSProperties, ReactNode } from "react";
import styles from "./CardGridCollage.module.scss";
export type CardGridCollageCard = { no: string; name: string; icon?: ReactNode };
export type CardGridCollageProps = {
cards?: CardGridCollageCard[];
/** 카드끼리 어긋나는 간격(ms) */
stagger?: number;
duration?: number;
easing?: string;
color?: string;
};
type Vars = CSSProperties & { "--duration"?: string; "--easing"?: string; "--color"?: string };
type CardVars = CSSProperties & { "--rot"?: string; animationDelay?: string };
const defaultCards: CardGridCollageCard[] = [
{ no: "01", name: "화보" },
{ no: "02", name: "색면" },
{ no: "03", name: "활자" },
];
const angles = ["-7deg", "5deg", "-4deg"];
const colorFills = [
"linear-gradient(150deg, #d93a1e 0%, #ffd93d 100%)",
"linear-gradient(150deg, #2d6fb5 0%, #b6e34f 100%)",
"linear-gradient(150deg, #6b3fa0 0%, #d93a1e 100%)",
];
export default function CardGridCollage({
cards = defaultCards,
stagger = 240,
duration = 2000,
easing = "cubic-bezier(.2, .8, .2, 1)",
color = "#d93a1e",
}: CardGridCollageProps) {
const vars: Vars = { "--duration": `${duration}ms`, "--easing": easing, "--color": color };
return (
<section className={styles.ccol} style={vars}>
{cards.map((c, i) => {
const cv: CardVars = { "--rot": angles[i % angles.length], animationDelay: `${-stagger * i}ms` };
return (
<article key={c.no} className={styles.card} style={cv}>
<span className={styles.photo} style={{ background: colorFills[i % colorFills.length] }} aria-hidden="true">
{c.icon}
</span>
<p className={styles.no}>{c.no}</p>
<p className={styles.name}>{c.name}</p>
</article>
);
})}
</section>
);
}03 Cut-out frame card grid — Measured area 9.509% · moving frames 23/23Original by GODRICH · SCSS and React ship in the zip · Maximalist Web Design: 9 Collage Landing Sections
The post this demo lives in
Maximalist Web Design: 9 Collage Landing SectionsMaximalist web design fills the screen instead of emptying it, stacking color fields, oversized type, and stickers until See all demos in this post


