01レザーのステッチ料金カード
レザーカードが20px上から着地した瞬間、明るいステッチ目盛が二重枠の中に1フレームのカットで刻まれ、カードが少し浮いて落ち着きます。
使いどころ料金・メンバーシップカード、プレミアム商品の強調
이중 테두리repeating-linear-gradientsteps(1, end)

<main class="stage">
<section class="leather">
<div class="leather__card">
<p class="leather__plan">Proメンバーシップ</p>
<p class="leather__price">月額₩24,000</p>
<ul class="leather__perks">
<li class="leather__perk">質感パーツ9種すべて</li>
<li class="leather__perk">商用利用込み</li>
</ul>
<button class="leather__cta" type="button">選ぶ</button>
<span class="leather__stitch" aria-hidden="true"></span>
</div>
</section>
</main>@use "../../../../site/static/demo-tokens" as *;
// 스큐어모픽 가죽 — 사진 없이 그라디언트 겹침으로 결·테두리·스티치를 만든다.
// 대비 실측(WCAG 상대휘도): stitch/leather-base 밝기 차는 눈금용(장식) ·
// 본문 글자 cream-ink #f6e7cf / leather-deep #906547 = 8.9:1 (본문 기준 4.5:1 통과)
$leather-base: #7a4a2b; // 가죽 바탕
$leather-deep: #906547; // 어두운 결·글자 바탕
$leather-light: #96613c; // 밝은 결
$leather-ink: #f6e7cf; // 가죽 위 글자 (짙은 질감 위 본문은 이 밝기만)
$stitch: #f3e2c8; // 스티치 실
$duration: $dur-loop; // 카드가 내려와 착지하고 다시 뜨는 한 주기
$easing: $ease-out; // 가죽은 무겁다 — 튀지 않고 감속
$color: $leather-base;
@include stage($stage-ink);
.leather {
display: grid;
place-items: center;
}
// 가죽 카드 본체 — 이중 테두리: 어두운 바깥 테(안쪽 그림자) + 밝은 안쪽 테(위 하이라이트)
.leather__card {
position: relative;
box-sizing: border-box;
width: clamp(200px, 64vw, 300px);
padding: $sp-4;
border-radius: $r-card;
background:
repeating-linear-gradient(34deg, rgba($leather-deep, .38) 0 2px, transparent 2px 5px),
repeating-linear-gradient(-26deg, rgba($leather-light, .22) 0 1px, transparent 1px 6px),
radial-gradient(120% 120% at 30% 20%, rgba($leather-light, .5), transparent 55%),
$leather-base;
box-shadow:
inset 0 2px 0 rgba(255, 244, 224, .28), // 안쪽 위 밝은 테
inset 0 -4px 0 rgba($leather-deep, .8), // 안쪽 아래 어두운 테
0 10px 14px rgba(0, 0, 0, .45);
animation: leatherLand $duration $easing infinite;
}
// 스티치 눈금 — 네 변을 각각 repeating-linear-gradient 눈금으로 감싼다 (이미지 아님)
.leather__stitch {
position: absolute;
top: 8px; left: 8px; right: 8px; bottom: 8px;
border-radius: $r-control;
opacity: 0;
background:
repeating-linear-gradient(90deg, $stitch 0 8px, transparent 8px 16px) top / 100% 2px no-repeat,
repeating-linear-gradient(90deg, $stitch 0 8px, transparent 8px 16px) bottom / 100% 2px no-repeat,
repeating-linear-gradient(0deg, $stitch 0 8px, transparent 8px 16px) left / 2px 100% no-repeat,
repeating-linear-gradient(0deg, $stitch 0 8px, transparent 8px 16px) right / 2px 100% no-repeat;
filter: drop-shadow(0 1px 0 rgba($leather-deep, .9));
animation: stitchCut $duration steps(1, end) infinite;
}
.leather__plan {
margin: 0 0 $sp-1;
color: $leather-ink;
font-weight: 700; font-size: clamp(10px, 2.6vw, 12px); line-height: 1;
font-family: inherit;
letter-spacing: .14em;
text-transform: uppercase;
}
.leather__price {
margin: 0 0 $sp-2;
color: #ffffff;
font-weight: 800; font-size: clamp(20px, 5.2vw, 30px); line-height: 1.1;
font-family: inherit;
}
.leather__perks {
margin: 0 0 $sp-3;
padding: 0;
list-style: none;
display: grid;
gap: $sp-1;
}
.leather__perk {
color: $leather-ink;
font-weight: 500; font-size: clamp(11px, 2.8vw, 13px); line-height: 1.4;
font-family: inherit;
}
.leather__cta {
border: 0;
border-radius: $r-control;
padding: $sp-2 $sp-4;
background: #3d2412;
color: #ffffff;
font-weight: 700; font-size: clamp(12px, 2.8vw, 14px); line-height: 1;
font-family: inherit;
box-shadow: inset 0 2px 0 rgba(255, 235, 200, .22), 0 4px 0 rgba(0, 0, 0, .4);
}
.leather__cta:focus-visible {
outline: 3px solid $stage-yellow;
outline-offset: 2px;
}
// 카드가 20px 위에서 내려앉고 — 착지 순간 스티치가 한 프레임 컷으로 새겨진다 — 다시 뜬다
@keyframes leatherLand {
0% { transform: translateY(-20px); box-shadow: inset 0 2px 0 rgba(255, 244, 224, .28), inset 0 -4px 0 rgba($leather-deep, .8), 0 20px 26px rgba(0, 0, 0, .55); }
34% { transform: translateY(0); box-shadow: inset 0 2px 0 rgba(255, 244, 224, .28), inset 0 -4px 0 rgba($leather-deep, .8), 0 8px 12px rgba(0, 0, 0, .45); }
42% { transform: translateY(-2px); }
50% { transform: translateY(0); box-shadow: inset 0 2px 0 rgba(255, 244, 224, .28), inset 0 -4px 0 rgba($leather-deep, .8), 0 10px 14px rgba(0, 0, 0, .45); }
86% { transform: translateY(0); }
94%,100% { transform: translateY(-20px); box-shadow: inset 0 2px 0 rgba(255, 244, 224, .28), inset 0 -4px 0 rgba($leather-deep, .8), 0 20px 26px rgba(0, 0, 0, .55); }
}
@keyframes stitchCut {
0%, 36% { opacity: 0; }
38%, 86% { opacity: 1; }
88%, 100% { opacity: 0; }
}
@media (max-width: 340px), (max-height: 220px) {
.leather__card { width: 196px; padding: $sp-3; }
.leather__perks { margin-bottom: $sp-2; }
.leather__perk:last-child { display: none; }
.leather__price { font-size: 20px; line-height: 1; }
}
@media (prefers-reduced-motion: reduce) {
.leather__card { animation: none !important; }
.leather__stitch { animation: none !important; opacity: 1; }
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #17141a;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.leather {
display: grid;
place-items: center;
}
.leather__card {
position: relative;
box-sizing: border-box;
width: clamp(200px, 64vw, 300px);
padding: 16px;
border-radius: 16px;
background: repeating-linear-gradient(34deg, rgba(144, 101, 71, 0.38) 0 2px, transparent 2px 5px), repeating-linear-gradient(-26deg, rgba(150, 97, 60, 0.22) 0 1px, transparent 1px 6px), radial-gradient(120% 120% at 30% 20%, rgba(150, 97, 60, 0.5), transparent 55%), #7a4a2b;
box-shadow: inset 0 2px 0 rgba(255, 244, 224, 0.28), inset 0 -4px 0 rgba(144, 101, 71, 0.8), 0 10px 14px rgba(0, 0, 0, 0.45);
animation: leatherLand 2s ease-out infinite;
}
.leather__stitch {
position: absolute;
top: 8px;
left: 8px;
right: 8px;
bottom: 8px;
border-radius: 12px;
opacity: 0;
background: repeating-linear-gradient(90deg, #f3e2c8 0 8px, transparent 8px 16px) top/100% 2px no-repeat, repeating-linear-gradient(90deg, #f3e2c8 0 8px, transparent 8px 16px) bottom/100% 2px no-repeat, repeating-linear-gradient(0deg, #f3e2c8 0 8px, transparent 8px 16px) left/2px 100% no-repeat, repeating-linear-gradient(0deg, #f3e2c8 0 8px, transparent 8px 16px) right/2px 100% no-repeat;
filter: drop-shadow(0 1px 0 rgba(144, 101, 71, 0.9));
animation: stitchCut 2s steps(1, end) infinite;
}
.leather__plan {
margin: 0 0 4px;
color: #f6e7cf;
font-weight: 700;
font-size: clamp(10px, 2.6vw, 12px);
line-height: 1;
font-family: inherit;
letter-spacing: 0.14em;
text-transform: uppercase;
}
.leather__price {
margin: 0 0 8px;
color: #ffffff;
font-weight: 800;
font-size: clamp(20px, 5.2vw, 30px);
line-height: 1.1;
font-family: inherit;
}
.leather__perks {
margin: 0 0 12px;
padding: 0;
list-style: none;
display: grid;
gap: 4px;
}
.leather__perk {
color: #f6e7cf;
font-weight: 500;
font-size: clamp(11px, 2.8vw, 13px);
line-height: 1.4;
font-family: inherit;
}
.leather__cta {
border: 0;
border-radius: 12px;
padding: 8px 16px;
background: #3d2412;
color: #ffffff;
font-weight: 700;
font-size: clamp(12px, 2.8vw, 14px);
line-height: 1;
font-family: inherit;
box-shadow: inset 0 2px 0 rgba(255, 235, 200, 0.22), 0 4px 0 rgba(0, 0, 0, 0.4);
}
.leather__cta:focus-visible {
outline: 3px solid #ffd23f;
outline-offset: 2px;
}
@keyframes leatherLand {
0% {
transform: translateY(-20px);
box-shadow: inset 0 2px 0 rgba(255, 244, 224, 0.28), inset 0 -4px 0 rgba(144, 101, 71, 0.8), 0 20px 26px rgba(0, 0, 0, 0.55);
}
34% {
transform: translateY(0);
box-shadow: inset 0 2px 0 rgba(255, 244, 224, 0.28), inset 0 -4px 0 rgba(144, 101, 71, 0.8), 0 8px 12px rgba(0, 0, 0, 0.45);
}
42% {
transform: translateY(-2px);
}
50% {
transform: translateY(0);
box-shadow: inset 0 2px 0 rgba(255, 244, 224, 0.28), inset 0 -4px 0 rgba(144, 101, 71, 0.8), 0 10px 14px rgba(0, 0, 0, 0.45);
}
86% {
transform: translateY(0);
}
94%, 100% {
transform: translateY(-20px);
box-shadow: inset 0 2px 0 rgba(255, 244, 224, 0.28), inset 0 -4px 0 rgba(144, 101, 71, 0.8), 0 20px 26px rgba(0, 0, 0, 0.55);
}
}
@keyframes stitchCut {
0%, 36% {
opacity: 0;
}
38%, 86% {
opacity: 1;
}
88%, 100% {
opacity: 0;
}
}
@media (max-width: 340px), (max-height: 220px) {
.leather__card {
width: 196px;
padding: 12px;
}
.leather__perks {
margin-bottom: 8px;
}
.leather__perk:last-child {
display: none;
}
.leather__price {
font-size: 20px;
line-height: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.leather__card {
animation: none !important;
}
.leather__stitch {
animation: none !important;
opacity: 1;
}
}import type { CSSProperties } from "react";
import styles from "./LeatherStitchCard.module.scss";
export type LeatherStitchCardProps = {
plan?: string;
price?: string;
perk1?: string;
perk2?: string;
cta?: string;
/** 한 주기(기본 2000ms) */
duration?: number;
easing?: string;
color?: string;
};
type Vars = CSSProperties & { "--duration"?: string; "--easing"?: string; "--color"?: string };
export default function LeatherStitchCard({
plan = "Pro 멤버십",
price = "월 24,000원",
perk1 = "질감 부품 9종 전체",
perk2 = "상업 이용 포함",
cta = "선택하기",
duration = 2000,
easing = "ease-out",
color = "#7a4a2b",
}: LeatherStitchCardProps) {
const vars: Vars = { "--duration": `${duration}ms`, "--easing": easing, "--color": color };
return (
<section className={styles.leather} style={vars}>
<div className={styles.card}>
<p className={styles.plan}>{plan}</p>
<p className={styles.price}>{price}</p>
<ul className={styles.perks}>
<li className={styles.perk}>{perk1}</li>
<li className={styles.perk}>{perk2}</li>
</ul>
<button type="button" className={styles.cta}>{cta}</button>
<span className={styles.stitch} aria-hidden="true" />
</div>
</section>
);
}01 レザーのステッチ料金カード — 計測 累積面積 23.101% · 動いたフレーム 15/23GODRICH オリジナル · SCSS と React は zip に同梱 · スキューモーフィズムデザインの質感パーツ9選
このデモが属する記事
スキューモーフィズムデザインの質感パーツ9選スキューモーフィズムデザインは、革・金属・木目・ガラスといった実物の質感を画面に持ち込むスタイルです。革・金属・木目をCSSの値だけで作り、テクスチャ写真を1枚も使わずに、2024年以降の製品サイトに少しずつ戻ってきた「選択的な質感」を貼っ この記事のデモをすべて見る


