01切り貼りのヒーロー
背面の色紙3枚と手前の白い紙が逆方向に動き、白い紙が浮くあいだに影も一緒に広がります。
使いどころクラフト・教育・趣味系サービスLPの最初の画面
겹친 층반대 위상radius 16

<main class="stage">
<section class="heropaper">
<span class="heropaper__scrap heropaper__scrap--coral" aria-hidden="true"></span>
<span class="heropaper__scrap heropaper__scrap--butter" aria-hidden="true"></span>
<span class="heropaper__scrap heropaper__scrap--leaf" aria-hidden="true"></span>
<div class="heropaper__sheet">
<span class="heropaper__badge" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 256 256"><g fill="currentColor"><path d="M40.2 95.8a28 28 0 1 1 39.6 0a28 28 0 0 1-39.6 0m0 64.4a28 28 0 1 0 39.6 0a28 28 0 0 0-39.6 0" opacity=".2"/><path d="M157.73 113.13a8 8 0 0 1 2.09-11.13l67.66-46.3a8 8 0 0 1 9 13.21l-67.67 46.3a7.9 7.9 0 0 1-4.51 1.4a8 8 0 0 1-6.57-3.48m80.87 85.09a8 8 0 0 1-11.12 2.08L136 137.7l-42.51 29.08a36 36 0 1 1-9-13.19L121.83 128l-37.39-25.59a35.86 35.86 0 1 1 9-13.19l143 97.87a8 8 0 0 1 2.16 11.13M80 180a20 20 0 1 0-5.86 14.14A19.85 19.85 0 0 0 80 180m-5.86-89.87a20 20 0 1 0-28.28 0a19.85 19.85 0 0 0 28.28 0"/></g></svg>
</span>
<p class="heropaper__eyebrow">Cut & paste</p>
<h1 class="heropaper__title">切って貼った画面</h1>
<p class="heropaper__desc">色紙数枚でできるランディング</p>
<button class="heropaper__cta" type="button">今すぐ始める</button>
</div>
</section>
</main>@use "../../../../site/static/demo-tokens" as *;
// 페이퍼컷 팔레트 — 따뜻한 오프화이트 두 장 + 오려낸 색종이 다섯 색.
// 대비 실측(WCAG 상대휘도 직접 계산): ink/paper 14.34:1 · stone/paper 7.23:1 · sheet/coral 4.93:1
$paper-base: #fbf6ec;
$paper-sheet: #ffffff;
$paper-ink: #2a2320;
$paper-stone: #5c5048;
$paper-coral: #b97b71;
$paper-sky: #6a8db5;
$paper-leaf: #2b7d5a;
$paper-butter: #d6c9ab;
$paper-edge: #e7dccb;
$duration: $dur-loop; // 종이 한 장이 들렸다 내려앉는 한 주기
$easing: $ease-out; // 종이는 튀지 않는다. 되돌아올 때도 같은 속도
$color: $paper-coral; // 오려낸 색종이 조각의 대표색
@include stage($paper-base);
.heropaper {
position: relative;
width: clamp(216px, 74vw, 328px);
isolation: isolate;
}
// 뒤에 깔리는 색종이 조각 — 각자 다른 각도로 오려 붙인 것처럼
.heropaper__scrap {
position: absolute;
z-index: 0;
animation: scrapDrift $duration $easing infinite;
}
.heropaper__scrap--coral {
left: -20px;
top: 4px;
width: 76px;
height: 76px;
border-radius: 50%;
background: $paper-coral;
}
.heropaper__scrap--butter {
right: -16px;
top: -20px;
width: 92px;
height: 48px;
border-radius: $r-card;
background: $paper-butter;
transform: rotate(-8deg);
animation-delay: -.66s;
}
.heropaper__scrap--leaf {
right: 8px;
bottom: -24px;
width: 64px;
height: 40px;
border-radius: $r-pill;
background: $paper-leaf;
animation-delay: -1.33s;
}
// 맨 위 흰 종이 — 들어올려지면 그림자가 같이 자란다
.heropaper__sheet {
position: relative;
z-index: 1;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: $sp-2;
padding: $sp-5;
border-radius: $r-card;
background: $paper-sheet;
box-shadow: 0 10px 18px rgba($paper-ink, .14);
animation: sheetLift $duration $easing infinite;
}
.heropaper__badge {
position: absolute;
top: -14px;
right: $sp-4;
width: 34px;
aspect-ratio: 1;
display: grid;
place-items: center;
border-radius: 50%;
background: $paper-sheet;
color: $paper-coral;
font-size: 18px;
box-shadow: 0 4px 8px rgba($paper-ink, .18);
}
.heropaper__eyebrow {
margin: 0;
color: $paper-coral;
font-weight: 700; font-size: clamp(10px, 2.6vw, 12px); line-height: 1;
font-family: inherit;
letter-spacing: .1em;
text-transform: uppercase;
}
.heropaper__title {
margin: 0;
color: $paper-ink;
font-weight: 800; font-size: clamp(18px, 4.6vw, 26px); line-height: 1.2;
font-family: inherit;
}
.heropaper__desc {
margin: 0;
color: $paper-stone;
font-weight: 500; font-size: clamp(12px, 2.8vw, 14px); line-height: 1.4;
font-family: inherit;
}
.heropaper__cta {
margin-top: $sp-1;
border: 0;
border-radius: $r-control;
background: $paper-coral;
color: $paper-sheet;
padding: $sp-2 $sp-5;
font-weight: 700; font-size: clamp(12px, 2.8vw, 14px); line-height: 1;
font-family: inherit;
box-shadow: 0 4px 0 rgba($paper-ink, .2);
}
.heropaper__cta:focus-visible {
outline: 3px solid $paper-sky;
outline-offset: 2px;
}
// 데모: 흰 종이가 올라가는 동안 뒤 색종이는 반대 위상으로 내려간다 — 겹친 층이 분리되는 게 보인다
@keyframes sheetLift {
0%, 100% { transform: translateY(0); box-shadow: 0 10px 18px rgba($paper-ink, .14); }
50% { transform: translateY(-12px); box-shadow: 0 22px 28px rgba($paper-ink, .1); }
}
@keyframes scrapDrift {
0%, 100% { transform: translateY(0) rotate(-2deg); }
50% { transform: translateY(8px) rotate(3deg); }
}
@media (max-width: 340px), (max-height: 220px) {
.heropaper { width: 200px; }
.heropaper__sheet { padding: $sp-3 $sp-4; gap: $sp-1; }
.heropaper__eyebrow { display: none; }
.heropaper__title { font-size: 16px; line-height: 1.15; }
.heropaper__desc { display: none; }
.heropaper__cta { padding: $sp-1 $sp-4; margin-top: 0; }
.heropaper__badge { width: 24px; font-size: 13px; top: -10px; right: $sp-2; }
.heropaper__scrap--coral { width: 48px; height: 48px; left: -12px; }
.heropaper__scrap--butter { width: 56px; height: 32px; right: -8px; top: -12px; }
.heropaper__scrap--leaf { width: 44px; height: 26px; bottom: -14px; }
}
@media (prefers-reduced-motion: reduce) {
.heropaper__sheet, .heropaper__scrap { animation: none !important; transform: none; }
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #fbf6ec;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.heropaper {
position: relative;
width: clamp(216px, 74vw, 328px);
isolation: isolate;
}
.heropaper__scrap {
position: absolute;
z-index: 0;
animation: scrapDrift 2s ease-out infinite;
}
.heropaper__scrap--coral {
left: -20px;
top: 4px;
width: 76px;
height: 76px;
border-radius: 50%;
background: #b97b71;
}
.heropaper__scrap--butter {
right: -16px;
top: -20px;
width: 92px;
height: 48px;
border-radius: 16px;
background: #d6c9ab;
transform: rotate(-8deg);
animation-delay: -0.66s;
}
.heropaper__scrap--leaf {
right: 8px;
bottom: -24px;
width: 64px;
height: 40px;
border-radius: 999px;
background: #2b7d5a;
animation-delay: -1.33s;
}
.heropaper__sheet {
position: relative;
z-index: 1;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 8px;
padding: 20px;
border-radius: 16px;
background: #ffffff;
box-shadow: 0 10px 18px rgba(42, 35, 32, 0.14);
animation: sheetLift 2s ease-out infinite;
}
.heropaper__badge {
position: absolute;
top: -14px;
right: 16px;
width: 34px;
aspect-ratio: 1;
display: grid;
place-items: center;
border-radius: 50%;
background: #ffffff;
color: #b97b71;
font-size: 18px;
box-shadow: 0 4px 8px rgba(42, 35, 32, 0.18);
}
.heropaper__eyebrow {
margin: 0;
color: #b97b71;
font-weight: 700;
font-size: clamp(10px, 2.6vw, 12px);
line-height: 1;
font-family: inherit;
letter-spacing: 0.1em;
text-transform: uppercase;
}
.heropaper__title {
margin: 0;
color: #2a2320;
font-weight: 800;
font-size: clamp(18px, 4.6vw, 26px);
line-height: 1.2;
font-family: inherit;
}
.heropaper__desc {
margin: 0;
color: #5c5048;
font-weight: 500;
font-size: clamp(12px, 2.8vw, 14px);
line-height: 1.4;
font-family: inherit;
}
.heropaper__cta {
margin-top: 4px;
border: 0;
border-radius: 12px;
background: #b97b71;
color: #ffffff;
padding: 8px 20px;
font-weight: 700;
font-size: clamp(12px, 2.8vw, 14px);
line-height: 1;
font-family: inherit;
box-shadow: 0 4px 0 rgba(42, 35, 32, 0.2);
}
.heropaper__cta:focus-visible {
outline: 3px solid #6a8db5;
outline-offset: 2px;
}
@keyframes sheetLift {
0%, 100% {
transform: translateY(0);
box-shadow: 0 10px 18px rgba(42, 35, 32, 0.14);
}
50% {
transform: translateY(-12px);
box-shadow: 0 22px 28px rgba(42, 35, 32, 0.1);
}
}
@keyframes scrapDrift {
0%, 100% {
transform: translateY(0) rotate(-2deg);
}
50% {
transform: translateY(8px) rotate(3deg);
}
}
@media (max-width: 340px), (max-height: 220px) {
.heropaper {
width: 200px;
}
.heropaper__sheet {
padding: 12px 16px;
gap: 4px;
}
.heropaper__eyebrow {
display: none;
}
.heropaper__title {
font-size: 16px;
line-height: 1.15;
}
.heropaper__desc {
display: none;
}
.heropaper__cta {
padding: 4px 16px;
margin-top: 0;
}
.heropaper__badge {
width: 24px;
font-size: 13px;
top: -10px;
right: 8px;
}
.heropaper__scrap--coral {
width: 48px;
height: 48px;
left: -12px;
}
.heropaper__scrap--butter {
width: 56px;
height: 32px;
right: -8px;
top: -12px;
}
.heropaper__scrap--leaf {
width: 44px;
height: 26px;
bottom: -14px;
}
}
@media (prefers-reduced-motion: reduce) {
.heropaper__sheet, .heropaper__scrap {
animation: none !important;
transform: none;
}
}import type { CSSProperties } from "react";
import styles from "./HeroPaper.module.scss";
export type HeroPaperProps = {
eyebrow?: string;
title?: string;
desc?: string;
cta?: string;
/** 한 주기(기본 2000ms) */
duration?: number;
easing?: string;
color?: string;
};
type Vars = CSSProperties & { "--duration"?: string; "--easing"?: string; "--color"?: string };
export default function HeroPaper({
eyebrow = "Cut & paste",
title = "오려 붙인 화면",
desc = "색종이 몇 장이면 되는 랜딩",
cta = "바로 시작",
duration = 2000,
easing = "ease-out",
color = "#cc3d26",
}: HeroPaperProps) {
const vars: Vars = { "--duration": `${duration}ms`, "--easing": easing, "--color": color };
return (
<section className={styles.heropaper} style={vars}>
<span className={`${styles.scrap} ${styles.scrapCoral}`} aria-hidden="true" />
<span className={`${styles.scrap} ${styles.scrapButter}`} aria-hidden="true" />
<span className={`${styles.scrap} ${styles.scrapLeaf}`} aria-hidden="true" />
<div className={styles.sheet}>
<span className={styles.badge} aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 256 256"><g fill="currentColor"><path d="M40.2 95.8a28 28 0 1 1 39.6 0a28 28 0 0 1-39.6 0m0 64.4a28 28 0 1 0 39.6 0a28 28 0 0 0-39.6 0" opacity=".2"/><path d="M157.73 113.13a8 8 0 0 1 2.09-11.13l67.66-46.3a8 8 0 0 1 9 13.21l-67.67 46.3a7.9 7.9 0 0 1-4.51 1.4a8 8 0 0 1-6.57-3.48m80.87 85.09a8 8 0 0 1-11.12 2.08L136 137.7l-42.51 29.08a36 36 0 1 1-9-13.19L121.83 128l-37.39-25.59a35.86 35.86 0 1 1 9-13.19l143 97.87a8 8 0 0 1 2.16 11.13M80 180a20 20 0 1 0-5.86 14.14A19.85 19.85 0 0 0 80 180m-5.86-89.87a20 20 0 1 0-28.28 0a19.85 19.85 0 0 0 28.28 0"/></g></svg>
</span>
<p className={styles.eyebrow}>{eyebrow}</p>
<h1 className={styles.title}>{title}</h1>
<p className={styles.desc}>{desc}</p>
<button type="button" className={styles.cta}>{cta}</button>
</div>
</section>
);
}01 切り貼りのヒーロー — 計測 累積面積 14.784% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · ペーパーカット デザインのLPパーツ9選、コピペOK
このデモが属する記事
ペーパーカット デザインのLPパーツ9選、コピペOKペーパーカット デザインは、はさみで切って貼ったような面をぼかし0の影だけで立ち上げ、色は決められた5色の中から選ぶスタイルです。紙のテクスチャ画像を1枚も敷かず、影の値ひとつで紙らしさを出します。 この記事のデモをすべて見る


