05마키 텍스트 띠
기울어진 띠 안에서 같은 낱말 묶음을 두 벌 깔고 한 벌 폭만큼만 밀어, 한 바퀴가 끝나도 이음매가 보이지 않습니다.
쓰임섹션 사이 구분 띠, 브랜드 문구 반복
두 벌 복제margin-right 간격translateX(-50%)

<main class="stage">
<section class="mcol">
<div class="mcol__band mcol__band--coral">
<div class="mcol__track">
<span class="mcol__bit">COLLAGE</span>
<span class="mcol__bit">MAXIMAL</span>
<span class="mcol__bit">PASTE</span>
<span class="mcol__bit">CUT</span>
<span class="mcol__bit" aria-hidden="true">COLLAGE</span>
<span class="mcol__bit" aria-hidden="true">MAXIMAL</span>
<span class="mcol__bit" aria-hidden="true">PASTE</span>
<span class="mcol__bit" aria-hidden="true">CUT</span>
</div>
</div>
<div class="mcol__band mcol__band--lemon">
<div class="mcol__track mcol__track--back">
<span class="mcol__bit">겹치기</span>
<span class="mcol__bit">기울이기</span>
<span class="mcol__bit">오리기</span>
<span class="mcol__bit" aria-hidden="true">겹치기</span>
<span class="mcol__bit" aria-hidden="true">기울이기</span>
<span class="mcol__bit" aria-hidden="true">오리기</span>
</div>
</div>
</section>
</main>@use "../../../../site/static/demo-tokens" as *;
// 콜라주·맥시멀 팔레트 (01 과 같은 값). 코랄 위는 흰 글자(4.59:1), 레몬 위는 ink 글자(11.82:1)
$cg-cream: #fbf3e4;
$cg-sheet: #ffffff;
$cg-ink: #241d2e;
$cg-coral: #bb7f74;
$cg-lemon: #d1c8a3;
$serif: Georgia, "Nanum Myeongjo", "Times New Roman", serif;
$duration: $dur-loop; // 한 벌 폭을 다 흘려보내는 한 주기
$easing: linear; // 띠는 등속이어야 이음매가 안 보인다
$color: $cg-coral; // 위 띠의 바탕색
@include stage($cg-cream);
.mcol {
width: clamp(240px, 82vw, 340px);
display: flex;
flex-direction: column;
}
.mcol__band {
box-sizing: border-box;
overflow: hidden;
padding: $sp-2 0;
border-radius: $r-xs;
box-shadow: 0 4px 0 rgba($cg-ink, .18);
}
.mcol__band--coral {
z-index: 1;
background: $cg-coral;
color: $cg-sheet;
transform: rotate(-2.5deg);
}
// 아래 띠는 조금 좁게, 오른쪽으로 밀어 붙인다. 겹치는 건 띠 가장자리끼리만 — 글자를 덮으면 콜라주가 아니라 사고다
.mcol__band--lemon {
z-index: 2;
width: 88%;
margin-top: $sp-2;
margin-left: auto;
background: $cg-lemon;
color: $cg-ink;
transform: rotate(2deg);
}
// 트랙 — 같은 낱말 묶음을 두 벌 이어 붙이고 한 벌 폭(=50%)만 민다
.mcol__track {
display: flex;
width: max-content;
animation-name: stripFlow;
animation-duration: $duration;
animation-timing-function: $easing;
animation-iteration-count: infinite;
}
.mcol__track--back { animation-name: stripFlowBack; }
// 간격은 gap 이 아니라 낱개 margin-right — gap 은 2N 조각 사이에 2N-1 개뿐이라 -50% 가 어긋난다
.mcol__bit {
margin-right: $sp-6;
font-family: $serif;
font-weight: 700;
font-size: 17px;
line-height: 1.2;
letter-spacing: .06em;
white-space: nowrap;
}
@keyframes stripFlow {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}
@keyframes stripFlowBack {
from { transform: translateX(-50%); }
to { transform: translateX(0); }
}
@media (max-width: 360px), (max-height: 230px) {
.mcol { width: 236px; }
.mcol__bit { font-size: 13px; margin-right: $sp-4; }
}
@media (prefers-reduced-motion: reduce) {
.mcol__track { animation: none !important; transform: translateX(0); }
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #fbf3e4;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.mcol {
width: clamp(240px, 82vw, 340px);
display: flex;
flex-direction: column;
}
.mcol__band {
box-sizing: border-box;
overflow: hidden;
padding: 8px 0;
border-radius: 4px;
box-shadow: 0 4px 0 rgba(36, 29, 46, 0.18);
}
.mcol__band--coral {
z-index: 1;
background: #bb7f74;
color: #ffffff;
transform: rotate(-2.5deg);
}
.mcol__band--lemon {
z-index: 2;
width: 88%;
margin-top: 8px;
margin-left: auto;
background: #d1c8a3;
color: #241d2e;
transform: rotate(2deg);
}
.mcol__track {
display: flex;
width: max-content;
animation-name: stripFlow;
animation-duration: 2s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
.mcol__track--back {
animation-name: stripFlowBack;
}
.mcol__bit {
margin-right: 24px;
font-family: Georgia, "Nanum Myeongjo", "Times New Roman", serif;
font-weight: 700;
font-size: 17px;
line-height: 1.2;
letter-spacing: 0.06em;
white-space: nowrap;
}
@keyframes stripFlow {
from {
transform: translateX(0);
}
to {
transform: translateX(-50%);
}
}
@keyframes stripFlowBack {
from {
transform: translateX(-50%);
}
to {
transform: translateX(0);
}
}
@media (max-width: 360px), (max-height: 230px) {
.mcol {
width: 236px;
}
.mcol__bit {
font-size: 13px;
margin-right: 16px;
}
}
@media (prefers-reduced-motion: reduce) {
.mcol__track {
animation: none !important;
transform: translateX(0);
}
}import type { CSSProperties } from "react";
import styles from "./MarqueeBandCollage.module.scss";
export type MarqueeBandCollageProps = {
/** 위 띠의 낱말 한 벌. 화면에는 두 벌이 깔린다 */
top?: string[];
/** 아래 띠의 낱말 한 벌 */
bottom?: string[];
duration?: number;
easing?: string;
color?: string;
};
type Vars = CSSProperties & { "--duration"?: string; "--easing"?: string; "--color"?: string };
const defaultTop = ["COLLAGE", "MAXIMAL", "PASTE", "CUT"];
const defaultBottom = ["겹치기", "기울이기", "오리기"];
export default function MarqueeBandCollage({
top = defaultTop,
bottom = defaultBottom,
duration = 2000,
easing = "linear",
color = "#d93a1e",
}: MarqueeBandCollageProps) {
const vars: Vars = { "--duration": `${duration}ms`, "--easing": easing, "--color": color };
// 한 벌을 그대로 복제해 두 벌을 깐다. 복제본은 스크린리더에서 숨긴다
const doubled = (xs: string[]) => [...xs, ...xs];
return (
<section className={styles.mcol} style={vars}>
<div className={`${styles.band} ${styles.bandCoral}`}>
<div className={styles.track}>
{doubled(top).map((w, i) => (
<span key={`t${i}`} className={styles.bit} aria-hidden={i >= top.length}>{w}</span>
))}
</div>
</div>
<div className={`${styles.band} ${styles.bandLemon}`}>
<div className={`${styles.track} ${styles.trackBack}`}>
{doubled(bottom).map((w, i) => (
<span key={`b${i}`} className={styles.bit} aria-hidden={i >= bottom.length}>{w}</span>
))}
</div>
</div>
</section>
);
}05 마키 텍스트 띠 — 측정 누적면적 6.316% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 맥시멀리즘 디자인 랜딩 키트, 겹쳐 붙인 콜라주 9종
이 데모가 속한 글
맥시멀리즘 디자인 랜딩 키트, 겹쳐 붙인 콜라주 9종맥시멀리즘 디자인은 여백을 비우는 대신 색면·큰 활자·스티커를 겹쳐 붙여 화면을 꽉 채우는 스타일입니다. 잡지에서 오려 붙인 콜라주가 그 대표 얼굴이고, 이 키트는 사진 파일 없이 CSS 값만으로 그 인상을 냅니다. 이 글의 데모 전부 보기


