03반복 패턴 밴드
점·물결·십자 세 판이 나란히 서고, 각 판의 무늬 바닥이 잘린 이음매 없이 옆으로 흐르며 세 판이 0.22초씩 어긋나 들렸다 내려앉습니다.
쓰임섹션 배경 띠, 소개 페이지 중간 밴드
background-sizetranslateXanimation-delay

<main class="stage">
<section class="bandm">
<article class="bandm__panel bandm__panel--dots">
<div class="bandm__fill bandm__fill--dots" aria-hidden="true"></div>
<span class="bandm__name">점</span>
</article>
<article class="bandm__panel bandm__panel--wave">
<div class="bandm__fill bandm__fill--wave" aria-hidden="true"></div>
<span class="bandm__name">물결</span>
</article>
<article class="bandm__panel bandm__panel--cross">
<div class="bandm__fill bandm__fill--cross" aria-hidden="true"></div>
<span class="bandm__name">십자</span>
</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: linear; // 흐름은 일정 속도 — 이음매가 보이지 않는다
$color: $mem-mint; // 무대(민트)
@include stage($mem-mint);
.bandm {
box-sizing: border-box;
display: flex;
gap: $sp-3;
width: clamp(252px, 82vw, 372px);
}
// 무늬 판 — 흰 테두리판 안에 무늬 바닥이 들어 있다
.bandm__panel {
position: relative;
flex: 1 1 0;
height: clamp(148px, 46vh, 208px);
border-radius: $r-card;
background: $mem-lemon;
border: 3px solid $mem-ink;
box-shadow: 0 6px 0 $mem-ink;
overflow: hidden;
animation: panelLift $duration $ease-out infinite;
}
.bandm__panel:nth-child(2) { animation-delay: -.22s; }
.bandm__panel:nth-child(3) { animation-delay: -.44s; }
// 무늬 바닥 — 폭을 타일의 정수배(240px = 20칸 × 12px)로 고정하고 절반을 민다
.bandm__fill {
position: absolute;
inset: 0 auto 0 0;
width: 240px;
animation: fillFlow $duration $easing infinite;
}
// 점 — 반경 그라디언트 원을 타일로 찍는다
.bandm__fill--dots {
background-image: radial-gradient(circle at 12px 12px, $mem-ink 3.5px, transparent 4.5px);
background-size: 24px 24px;
}
// 물결 — 잉크 리본(타일 안 y8~28)의 위 가장자리에 산을, 아래 가장자리 경계에 골을 만든다
.bandm__fill--wave {
background-image:
linear-gradient(to bottom, transparent 8px, $mem-ink 8px 28px, transparent 28px),
radial-gradient(circle 10px at 12px 8px, $mem-ink 0 9.5px, transparent 10px),
radial-gradient(circle 10px at 0 28px, $mem-ink 0 9.5px, transparent 10px);
background-size: 24px 40px;
background-repeat: repeat;
}
// 십자 — 타일(24px) 안에 세로 막대(x 9.5~14.5)와 가로 막대(y 9.5~14.5)를 얹는다
.bandm__fill--cross {
background-color: $mem-sky;
background-image:
linear-gradient(to right, transparent 9.5px, $mem-ink 9.5px 14.5px, transparent 14.5px),
linear-gradient(to bottom, transparent 9.5px, $mem-ink 9.5px 14.5px, transparent 14.5px);
background-size: 24px 24px;
background-repeat: repeat;
}
// 이름표 — 무늬 위 글자는 흰 알약 하나에 잉크로만
.bandm__name {
position: absolute;
left: 50%;
bottom: $sp-2;
transform: translateX(-50%);
padding: $sp-1 $sp-2;
border-radius: $r-pill;
background: $mem-sheet;
border: 2px solid $mem-ink;
color: $mem-ink;
font-weight: 700; font-size: 11px; line-height: 1;
font-family: inherit;
}
// 절반(120px = 타일 10칸)만 밀면 한 바퀴 — 무늬가 주기적이므로 이음매가 없다
@keyframes fillFlow {
from { transform: translateX(0); }
to { transform: translateX(-120px); }
}
// 세 판이 0.22초씩 어긋나 들렸다 내려앉는다
@keyframes panelLift {
0%, 100% { transform: translateY(0); }
45% { transform: translateY(-10px); }
}
@media (max-width: 340px), (max-height: 220px) {
.bandm { width: 232px; gap: $sp-2; }
.bandm__panel { height: 128px; }
.bandm__name { bottom: $sp-1; font-size: 10px; }
}
@media (prefers-reduced-motion: reduce) {
.bandm__fill, .bandm__panel { 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: #71b9ab;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.bandm {
box-sizing: border-box;
display: flex;
gap: 12px;
width: clamp(252px, 82vw, 372px);
}
.bandm__panel {
position: relative;
flex: 1 1 0;
height: clamp(148px, 46vh, 208px);
border-radius: 16px;
background: #cec29c;
border: 3px solid #241f26;
box-shadow: 0 6px 0 #241f26;
overflow: hidden;
animation: panelLift 2s ease-out infinite;
}
.bandm__panel:nth-child(2) {
animation-delay: -0.22s;
}
.bandm__panel:nth-child(3) {
animation-delay: -0.44s;
}
.bandm__fill {
position: absolute;
inset: 0 auto 0 0;
width: 240px;
animation: fillFlow 2s linear infinite;
}
.bandm__fill--dots {
background-image: radial-gradient(circle at 12px 12px, #241f26 3.5px, transparent 4.5px);
background-size: 24px 24px;
}
.bandm__fill--wave {
background-image: linear-gradient(to bottom, transparent 8px, #241f26 8px 28px, transparent 28px), radial-gradient(circle 10px at 12px 8px, #241f26 0 9.5px, transparent 10px), radial-gradient(circle 10px at 0 28px, #241f26 0 9.5px, transparent 10px);
background-size: 24px 40px;
background-repeat: repeat;
}
.bandm__fill--cross {
background-color: #82adc2;
background-image: linear-gradient(to right, transparent 9.5px, #241f26 9.5px 14.5px, transparent 14.5px), linear-gradient(to bottom, transparent 9.5px, #241f26 9.5px 14.5px, transparent 14.5px);
background-size: 24px 24px;
background-repeat: repeat;
}
.bandm__name {
position: absolute;
left: 50%;
bottom: 8px;
transform: translateX(-50%);
padding: 4px 8px;
border-radius: 999px;
background: #ffffff;
border: 2px solid #241f26;
color: #241f26;
font-weight: 700;
font-size: 11px;
line-height: 1;
font-family: inherit;
}
@keyframes fillFlow {
from {
transform: translateX(0);
}
to {
transform: translateX(-120px);
}
}
@keyframes panelLift {
0%, 100% {
transform: translateY(0);
}
45% {
transform: translateY(-10px);
}
}
@media (max-width: 340px), (max-height: 220px) {
.bandm {
width: 232px;
gap: 8px;
}
.bandm__panel {
height: 128px;
}
.bandm__name {
bottom: 4px;
font-size: 10px;
}
}
@media (prefers-reduced-motion: reduce) {
.bandm__fill, .bandm__panel {
animation: none !important;
transform: none;
}
}import type { CSSProperties } from "react";
import styles from "./PatternBandMemphis.module.scss";
export type PatternBandMemphisProps = {
/** 판 이름 3개 (점 · 물결 · 십자 순서로 무늬가 고정) */
names?: string[];
/** 한 주기(기본 2000ms) */
duration?: number;
easing?: string;
/** 데모 무대 색(참고용 — 판 배경은 고정) */
color?: string;
};
type Vars = CSSProperties & { "--duration"?: string; "--easing"?: string; "--color"?: string };
export default function PatternBandMemphis({
names = ["점", "물결", "십자"],
duration = 2000,
easing = "linear",
color = "#2ec4a6",
}: PatternBandMemphisProps) {
const vars: Vars = { "--duration": `${duration}ms`, "--easing": easing, "--color": color };
/* 무늬는 순서대로 고정 — 점 · 물결 · 십자 */
const fills = [
[styles.panelDots, styles.fillDots],
[styles.panelWave, styles.fillWave],
[styles.panelCross, styles.fillCross],
];
return (
<section className={styles.bandm} style={vars}>
{names.map((n, i) => {
const [panel, fill] = fills[i % fills.length];
return (
<article key={n} className={`${styles.panel} ${panel}`}>
<div className={`${styles.fill} ${fill}`} aria-hidden="true" />
<span className={styles.name}>{n}</span>
</article>
);
})}
</section>
);
}03 반복 패턴 밴드 — 측정 누적면적 33.612% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 멤피스 디자인 패턴 랜딩 키트, 점·물결 섹션 9개
이 데모가 속한 글
멤피스 디자인 패턴 랜딩 키트, 점·물결 섹션 9개멤피스 디자인은 1980년대 밀라노에서 시작된, 점·물결선·지그재그 같은 기하 형상을 밝은 색 위에 물들이듯 반복하는 스타일입니다. 이 글은 이미지 한 장 없이 CSS 그라디언트 타일과 도형만으로 멤피스 패턴을 재현 이 글의 데모 전부 보기


