08패턴 마퀴 띠
점·물결·십자·반원·삼각 조각을 한 벌 만들어 그대로 두 벌 깔고 한 벌만큼만 밀어, 한 바퀴가 끝나도 이음매가 보이지 않습니다.
쓰임섹션 사이 배너 띠, 이벤트 안내 흐름
translateX(-50%)margin-rightmax-content

<main class="stage">
<section class="marqm" aria-label="패턴 마퀴 띠">
<div class="marqm__viewport">
<div class="marqm__track">
<span class="marqm__tok marqm__tok--dot"></span>
<span class="marqm__tok marqm__tok--squig"></span>
<span class="marqm__tok marqm__tok--cross"></span>
<span class="marqm__tok marqm__tok--half"></span>
<span class="marqm__tok marqm__tok--tri"></span>
<span class="marqm__tok marqm__tok--dot"></span>
<span class="marqm__tok marqm__tok--squig"></span>
<span class="marqm__tok marqm__tok--cross"></span>
<span class="marqm__tok marqm__tok--half"></span>
<span class="marqm__tok marqm__tok--tri"></span>
</div>
</div>
<p class="marqm__hint">다음 섹션으로 이어지는 띠</p>
</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-coral; // 점 조각의 색
@include stage($mem-base);
.marqm {
box-sizing: border-box;
width: clamp(272px, 90vw, 416px);
}
.marqm__viewport {
overflow: hidden;
border-radius: $r-card;
background: $mem-sheet;
border: 3px solid $mem-ink;
box-shadow: 0 6px 0 $mem-ink;
}
// 트랙 — 같은 다섯 조각을 두 벌 깐다. 간격은 gap 이 아니라 margin-right(2N 개 사이 gap 은 2N-1 개라 -50% 가 어긋난다)
.marqm__track {
display: flex;
width: max-content;
align-items: center;
padding: $sp-4 0;
animation: trackFlow $duration $easing infinite;
}
.marqm__tok {
margin-right: $sp-4;
}
// 점 — 동그라미 하나
.marqm__tok--dot {
width: 22px;
height: 22px;
border-radius: 50%;
background: $color;
border: 3px solid $mem-ink;
}
// 물결 — 톱니 원뿔 한 줄짜리 리본
.marqm__tok--squig {
width: 44px;
height: 12px;
background: conic-gradient(from 315deg at 50% 100%, $mem-lemon 0 90deg, transparent 90deg 360deg) 0 0 / 12px 12px repeat-x;
border-top: 3px solid $mem-ink;
}
// 십자 — 막대 두 개
.marqm__tok--cross {
position: relative;
width: 22px;
height: 22px;
}
.marqm__tok--cross::before,
.marqm__tok--cross::after {
content: "";
position: absolute;
background: $mem-sky;
border: 2px solid $mem-ink;
border-radius: $r-xs;
}
.marqm__tok--cross::before { left: 50%; top: 0; width: 8px; height: 100%; transform: translateX(-50%); }
.marqm__tok--cross::after { top: 50%; left: 0; height: 8px; width: 100%; transform: translateY(-50%); }
// 반원
.marqm__tok--half {
width: 26px;
height: 14px;
border-radius: $r-pill $r-pill 0 0;
background: $mem-mint;
border: 3px solid $mem-ink;
}
// 삼각
.marqm__tok--tri {
width: 24px;
height: 22px;
background: $mem-pink;
clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
.marqm__hint {
margin: $sp-3 0 0;
color: $mem-stone;
font-weight: 600; font-size: clamp(11px, 2.6vw, 13px); line-height: 1;
font-family: inherit;
text-align: center;
}
// 한 벌만큼(-50%) 민다 — 두 벌이 픽셀 단위로 같으므로 이음매가 없다
@keyframes trackFlow {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}
@media (max-width: 340px), (max-height: 220px) {
.marqm { width: 240px; }
.marqm__track { padding: $sp-3 0; }
.marqm__tok { margin-right: $sp-3; }
.marqm__tok--dot { width: 18px; height: 18px; }
.marqm__tok--squig { width: 36px; }
.marqm__tok--cross { width: 18px; height: 18px; }
.marqm__tok--half { width: 22px; height: 12px; }
.marqm__tok--tri { width: 20px; height: 18px; }
.marqm__hint { margin-top: $sp-2; font-size: 10px; }
}
@media (prefers-reduced-motion: reduce) {
.marqm__track { 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: #fdf4ec;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.marqm {
box-sizing: border-box;
width: clamp(272px, 90vw, 416px);
}
.marqm__viewport {
overflow: hidden;
border-radius: 16px;
background: #ffffff;
border: 3px solid #241f26;
box-shadow: 0 6px 0 #241f26;
}
.marqm__track {
display: flex;
width: max-content;
align-items: center;
padding: 16px 0;
animation: trackFlow 2s linear infinite;
}
.marqm__tok {
margin-right: 16px;
}
.marqm__tok--dot {
width: 22px;
height: 22px;
border-radius: 50%;
background: #d5aea9;
border: 3px solid #241f26;
}
.marqm__tok--squig {
width: 44px;
height: 12px;
background: conic-gradient(from 315deg at 50% 100%, #cec29c 0 90deg, transparent 90deg 360deg) 0 0/12px 12px repeat-x;
border-top: 3px solid #241f26;
}
.marqm__tok--cross {
position: relative;
width: 22px;
height: 22px;
}
.marqm__tok--cross::before,
.marqm__tok--cross::after {
content: "";
position: absolute;
background: #82adc2;
border: 2px solid #241f26;
border-radius: 4px;
}
.marqm__tok--cross::before {
left: 50%;
top: 0;
width: 8px;
height: 100%;
transform: translateX(-50%);
}
.marqm__tok--cross::after {
top: 50%;
left: 0;
height: 8px;
width: 100%;
transform: translateY(-50%);
}
.marqm__tok--half {
width: 26px;
height: 14px;
border-radius: 999px 999px 0 0;
background: #71b9ab;
border: 3px solid #241f26;
}
.marqm__tok--tri {
width: 24px;
height: 22px;
background: #ebd6db;
clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
.marqm__hint {
margin: 12px 0 0;
color: #5d5560;
font-weight: 600;
font-size: clamp(11px, 2.6vw, 13px);
line-height: 1;
font-family: inherit;
text-align: center;
}
@keyframes trackFlow {
from {
transform: translateX(0);
}
to {
transform: translateX(-50%);
}
}
@media (max-width: 340px), (max-height: 220px) {
.marqm {
width: 240px;
}
.marqm__track {
padding: 12px 0;
}
.marqm__tok {
margin-right: 12px;
}
.marqm__tok--dot {
width: 18px;
height: 18px;
}
.marqm__tok--squig {
width: 36px;
}
.marqm__tok--cross {
width: 18px;
height: 18px;
}
.marqm__tok--half {
width: 22px;
height: 12px;
}
.marqm__tok--tri {
width: 20px;
height: 18px;
}
.marqm__hint {
margin-top: 8px;
font-size: 10px;
}
}
@media (prefers-reduced-motion: reduce) {
.marqm__track {
animation: none !important;
transform: none;
}
}import type { CSSProperties } from "react";
import styles from "./MarqueeBandMemphis.module.scss";
export type MarqueeBandMemphisProps = {
hint?: string;
/** 한 주기(기본 2000ms) */
duration?: number;
easing?: string;
/** 점 조각의 색 */
color?: string;
};
type Vars = CSSProperties & { "--duration"?: string; "--easing"?: string; "--color"?: string };
/* 같은 다섯 조각(점·물결·십자·반원·삼각)을 두 벌 깐다 */
const TOKS = [styles.tokDot, styles.tokSquig, styles.tokCross, styles.tokHalf, styles.tokTri];
export default function MarqueeBandMemphis({
hint = "다음 섹션으로 이어지는 띠",
duration = 2000,
easing = "linear",
color = "#ff5c47",
}: MarqueeBandMemphisProps) {
const vars: Vars = { "--duration": `${duration}ms`, "--easing": easing, "--color": color };
const track = [...TOKS, ...TOKS];
return (
<section className={styles.marqm} style={vars} aria-label="패턴 마퀴 띠">
<div className={styles.viewport}>
<div className={styles.track}>
{track.map((t, i) => (
<span key={i} className={`${styles.tok} ${t}`} />
))}
</div>
</div>
<p className={styles.hint}>{hint}</p>
</section>
);
}08 패턴 마퀴 띠 — 측정 누적면적 7.698% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 멤피스 디자인 패턴 랜딩 키트, 점·물결 섹션 9개
이 데모가 속한 글
멤피스 디자인 패턴 랜딩 키트, 점·물결 섹션 9개멤피스 디자인은 1980년대 밀라노에서 시작된, 점·물결선·지그재그 같은 기하 형상을 밝은 색 위에 물들이듯 반복하는 스타일입니다. 이 글은 이미지 한 장 없이 CSS 그라디언트 타일과 도형만으로 멤피스 패턴을 재현 이 글의 데모 전부 보기


