04黒い枠のカードグリッド
太い黒枠と張り付いた影を持つ白いカード3枚が、それぞれ違う模様の帯を頭に載せ、順番に持ち上がって元に戻ります。
使いどころ機能の3カラム紹介・サービス案内カード
box-shadowtranslateYrotate

<main class="stage">
<section class="gridm">
<article class="gridm__card">
<span class="gridm__sticker gridm__sticker--circle" aria-hidden="true"></span>
<div class="gridm__band gridm__band--dots" aria-hidden="true"></div>
<h2 class="gridm__title">パターンづくり</h2>
<p class="gridm__desc">水玉を打つように貼る設計</p>
</article>
<article class="gridm__card">
<span class="gridm__sticker gridm__sticker--half" aria-hidden="true"></span>
<div class="gridm__band gridm__band--cross" aria-hidden="true"></div>
<h2 class="gridm__title">形を重ねる</h2>
<p class="gridm__desc">半円と三角でアクセント</p>
</article>
<article class="gridm__card">
<span class="gridm__sticker gridm__sticker--tri" aria-hidden="true"></span>
<div class="gridm__band gridm__band--zig" aria-hidden="true"></div>
<h2 class="gridm__title">境界を分ける</h2>
<p class="gridm__desc">ジグザグでセクションを切る</p>
</article>
</section>
</main>@use "../../../../site/static/demo-tokens" as *;
// 멤피스 팔레트 — 01 과 같은 값
$mem-base: #fdf4ec;
$mem-sheet: #ffffff;
$mem-ink: #241f26;
$mem-stone: #5d5560;
$mem-coral: #d5aea9;
$mem-lemon: #cec29c;
$mem-sky: #82adc2;
$mem-mint: #71b9ab;
$mem-pink: #ebd6db;
$duration: $dur-loop; // 카드가 들렸다 내려앉는 한 주기
$easing: $ease-spring; // 스티커가 붙는 끝에 살짝 튕긴다
$color: $mem-ink; // 이번 편의 주역은 굵은 잉크 테두리
@include stage($mem-base);
.gridm {
box-sizing: border-box;
display: flex;
gap: $sp-3;
width: clamp(268px, 86vw, 392px);
padding-top: $sp-3;
}
// 흰 카드 — 3px 잉크 테두리 + 딱 붙은 잉크 그림자. 무늬는 머리띠에만(네오브루탈과의 차이)
.gridm__card {
position: relative;
flex: 1 1 0;
box-sizing: border-box;
padding: $sp-12 $sp-3 $sp-3;
border-radius: $r-card;
background: $mem-sheet;
border: 3px solid $mem-ink;
box-shadow: 0 6px 0 $mem-ink;
overflow: hidden;
animation: cardRise $duration $easing infinite;
}
.gridm__card:nth-child(2) { animation-delay: -.22s; }
.gridm__card:nth-child(3) { animation-delay: -.44s; }
// 무늬 머리띠 — 카드의 맨 꼭대기를 채운다(테두리 안쪽)
.gridm__band {
position: absolute;
left: 0;
right: 0;
top: 0;
height: 32px;
border-bottom: 3px solid $mem-ink;
}
.gridm__band--dots {
background-color: $mem-lemon;
background-image: radial-gradient(circle at 11px 16px, $mem-ink 0 3px, transparent 3.5px);
background-size: 22px 22px;
}
.gridm__band--cross {
background-color: $mem-sky;
background-image:
linear-gradient(to right, transparent 10px, $mem-sheet 10px 14px, transparent 14px),
linear-gradient(to bottom, transparent 14px, $mem-sheet 14px 18px, transparent 18px);
background-size: 24px 32px;
background-repeat: repeat;
}
.gridm__band--zig {
background-color: $mem-coral;
background-image: conic-gradient(from 135deg at 50% 0%, $mem-sheet 0 90deg, transparent 90deg 360deg);
background-size: 14px 9px;
background-position: 0 100%;
background-repeat: repeat-x;
}
// 귀퉁이 스티커 — 테두리를 걸터앉은 형상 하나
.gridm__sticker {
position: absolute;
z-index: 1;
top: 20px;
right: 10px;
}
.gridm__sticker--circle {
width: 24px;
height: 24px;
border-radius: 50%;
background: $mem-pink;
border: 3px solid $mem-ink;
}
.gridm__sticker--half {
width: 28px;
height: 15px;
border-radius: $r-pill $r-pill 0 0;
background: $mem-lemon;
border: 3px solid $mem-ink;
}
.gridm__sticker--tri {
width: 28px;
height: 25px;
background: $mem-mint;
clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
.gridm__title {
margin: $sp-2 0 0;
color: $mem-ink;
font-weight: 800; font-size: clamp(13px, 3vw, 16px); line-height: 1.25;
font-family: inherit;
}
.gridm__desc {
margin: $sp-1 0 0;
color: $mem-stone;
font-weight: 500; font-size: clamp(11px, 2.6vw, 12.5px); line-height: 1.45;
font-family: inherit;
}
// 세 장이 0.22초씩 어긋나 들렸다 앉는다 — 딱 붙은 그림자가 살짝 늘어난다
@keyframes cardRise {
0%, 100% { transform: translateY(0) rotate(0deg); box-shadow: 0 6px 0 $mem-ink; }
45% { transform: translateY(-12px) rotate(-1.5deg); box-shadow: 0 10px 0 $mem-ink; }
}
@media (max-width: 340px), (max-height: 220px) {
.gridm { width: 240px; gap: $sp-2; }
.gridm__card { padding: $sp-10 $sp-2 $sp-2; }
.gridm__title { font-size: 12px; }
.gridm__desc { font-size: 10.5px; }
.gridm__band { height: 26px; }
.gridm__sticker { top: 16px; right: 6px; }
}
@media (prefers-reduced-motion: reduce) {
.gridm__card { animation: none !important; transform: none; box-shadow: 0 6px 0 $mem-ink; }
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #fdf4ec;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.gridm {
box-sizing: border-box;
display: flex;
gap: 12px;
width: clamp(268px, 86vw, 392px);
padding-top: 12px;
}
.gridm__card {
position: relative;
flex: 1 1 0;
box-sizing: border-box;
padding: 48px 12px 12px;
border-radius: 16px;
background: #ffffff;
border: 3px solid #241f26;
box-shadow: 0 6px 0 #241f26;
overflow: hidden;
animation: cardRise 2s cubic-bezier(0.2, 0.8, 0.2, 1) infinite;
}
.gridm__card:nth-child(2) {
animation-delay: -0.22s;
}
.gridm__card:nth-child(3) {
animation-delay: -0.44s;
}
.gridm__band {
position: absolute;
left: 0;
right: 0;
top: 0;
height: 32px;
border-bottom: 3px solid #241f26;
}
.gridm__band--dots {
background-color: #cec29c;
background-image: radial-gradient(circle at 11px 16px, #241f26 0 3px, transparent 3.5px);
background-size: 22px 22px;
}
.gridm__band--cross {
background-color: #82adc2;
background-image: linear-gradient(to right, transparent 10px, #ffffff 10px 14px, transparent 14px), linear-gradient(to bottom, transparent 14px, #ffffff 14px 18px, transparent 18px);
background-size: 24px 32px;
background-repeat: repeat;
}
.gridm__band--zig {
background-color: #d5aea9;
background-image: conic-gradient(from 135deg at 50% 0%, #ffffff 0 90deg, transparent 90deg 360deg);
background-size: 14px 9px;
background-position: 0 100%;
background-repeat: repeat-x;
}
.gridm__sticker {
position: absolute;
z-index: 1;
top: 20px;
right: 10px;
}
.gridm__sticker--circle {
width: 24px;
height: 24px;
border-radius: 50%;
background: #ebd6db;
border: 3px solid #241f26;
}
.gridm__sticker--half {
width: 28px;
height: 15px;
border-radius: 999px 999px 0 0;
background: #cec29c;
border: 3px solid #241f26;
}
.gridm__sticker--tri {
width: 28px;
height: 25px;
background: #71b9ab;
clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
.gridm__title {
margin: 8px 0 0;
color: #241f26;
font-weight: 800;
font-size: clamp(13px, 3vw, 16px);
line-height: 1.25;
font-family: inherit;
}
.gridm__desc {
margin: 4px 0 0;
color: #5d5560;
font-weight: 500;
font-size: clamp(11px, 2.6vw, 12.5px);
line-height: 1.45;
font-family: inherit;
}
@keyframes cardRise {
0%, 100% {
transform: translateY(0) rotate(0deg);
box-shadow: 0 6px 0 #241f26;
}
45% {
transform: translateY(-12px) rotate(-1.5deg);
box-shadow: 0 10px 0 #241f26;
}
}
@media (max-width: 340px), (max-height: 220px) {
.gridm {
width: 240px;
gap: 8px;
}
.gridm__card {
padding: 40px 8px 8px;
}
.gridm__title {
font-size: 12px;
}
.gridm__desc {
font-size: 10.5px;
}
.gridm__band {
height: 26px;
}
.gridm__sticker {
top: 16px;
right: 6px;
}
}
@media (prefers-reduced-motion: reduce) {
.gridm__card {
animation: none !important;
transform: none;
box-shadow: 0 6px 0 #241f26;
}
}import type { CSSProperties } from "react";
import styles from "./CardGridMemphis.module.scss";
export type CardGridMemphisCard = { title: string; desc: string };
export type CardGridMemphisProps = {
/** 카드 3장 (스티커·머리띠 무늬는 순서대로 고정) */
cards?: CardGridMemphisCard[];
/** 한 주기(기본 2000ms) */
duration?: number;
easing?: string;
/** 이번 편의 주역 — 굵은 잉크 테두리색 */
color?: string;
};
type Vars = CSSProperties & { "--duration"?: string; "--easing"?: string; "--color"?: string };
export default function CardGridMemphis({
cards = [
{ title: "패턴 만들기", desc: "점 찍듯 붙여 넣는 설계" },
{ title: "형상 얹기", desc: "반원과 삼각으로 포인트" },
{ title: "경계 나누기", desc: "지그재그로 섹션을 절단" },
],
duration = 2000,
easing = "cubic-bezier(.2,.8,.2,1)",
color = "#241f26",
}: CardGridMemphisProps) {
const vars: Vars = { "--duration": `${duration}ms`, "--easing": easing, "--color": color };
/* 귀퉁이 스티커와 머리띠 무늬는 카드 순서대로 고정 */
const deco = [
[styles.stickerCircle, styles.bandDots],
[styles.stickerHalf, styles.bandCross],
[styles.stickerTri, styles.bandZig],
];
return (
<section className={styles.gridm} style={vars}>
{cards.map((c, i) => {
const [sticker, band] = deco[i % deco.length];
return (
<article key={c.title} className={styles.card}>
<span className={`${styles.sticker} ${sticker}`} aria-hidden="true" />
<div className={`${styles.band} ${band}`} aria-hidden="true" />
<h2 className={styles.title}>{c.title}</h2>
<p className={styles.desc}>{c.desc}</p>
</article>
);
})}
</section>
);
}04 黒い枠のカードグリッド — 計測 累積面積 24.256% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · メンフィス デザインのLPパーツ9選、コピペOK
このデモが属する記事
メンフィス デザインのLPパーツ9選、コピペOKメンフィス デザインとは、1980年代のミラノ生まれの、水玉・波線・ジグザグなどの幾何学形を明るい色の上に繰り返すスタイルです。画像を一枚も使わず、CSSグラデーションのタイルと図形だけでこのパターンを再現し、ランディングのセクション9つに この記事のデモをすべて見る


