GODRICH

맥시멀리즘 디자인 랜딩 키트, 겹쳐 붙인 콜라주 9종

맥시멀리즘 디자인은 여백을 비우는 대신 색면·큰 활자·스티커를 겹쳐 붙여 화면을 꽉 채우는 스타일입니다. 잡지에서 오려 붙인 콜라주가 그 대표 얼굴이고, 이 키트는 사진 파일 없이 CSS 값만으로 그 인상을 냅니다.

핀터레스트에서 이런 화면을 저장해 놓고 막상 만들려고 하면 어디부터 손대야 할지 막막합니다. 요소가 많아서가 아니라 겹치는 규칙이 없어서입니다. 아래 원페이지를 먼저 훑어보면서, 이 화면에서 마음대로 정해진 것이 몇 개나 되는지 세어 보세요. 셋입니다.

새 창에서 원페이지 열기

저 페이지를 이루는 부품 아홉 개를 하나씩 떼어 아래 격자에 늘어놓았습니다. 순서는 인기순이 아니라 콜라주 한 장을 실제로 만드는 순서입니다. 바탕에 사진 프레임을 겹치고, 목차를 얹고, 조각을 배열하고, 도장을 찍고, 띠를 두르고, 밑줄을 긋고, 카드를 포개고, 가장자리를 파내고, 마지막으로 서명을 남깁니다.

자동 재생 · 눌러서 해당 항목으로 · 전부 한 zip

01겹친 프레임 히어로

색면 그라디언트로 채운 사진 프레임 세 장이 각자 다른 위상으로 흔들리고, 그 위에 얹힌 제목 카드만 제자리에서 떠오릅니다. 뒤와 앞이 같은 방향으로 움직이면 겹침이 한 장으로 뭉쳐 보입니다.

z-index 겹침반대 위상radius 4
.hcol__frame {
  border: 6px solid #fff;            // 흰 여백이 사진 테두리 노릇을 한다
  animation-name: frameSway;
  animation-duration: 2s;
  animation-iteration-count: infinite;
}
.hcol__frame--sky  { --rot: 8deg;  animation-delay: -.7s; }
.hcol__frame--lime { --rot: -5deg; animation-delay: -1.4s; }

@keyframes frameSway {
  0%, 100% { transform: translateY(0) rotate(var(--rot)); }
  50%      { transform: translateY(8px) rotate(calc(var(--rot) + 5deg)); }
}

02잡지 목차형 내비

메뉴마다 두 자리 쪽번호를 붙이면 그것만으로 화면이 잡지 목차가 됩니다. 레몬색 칩은 칸마다 잠깐 앉았다가 다음 칸으로 뛰는데, 앉아 있는 구간이 있어야 어느 칸이 켜져 있는지 읽힙니다.

고정 폭 탭쪽번호 세리프radius 4
.ncol { --tab: 68px; --step: 72px; }   // 실측: 탭 68px + 간격 4px
.ncol__tab  { flex: 0 0 var(--tab); }  // 균등분배로 두면 이동량과 렌더 폭이 어긋난다

@keyframes chipHop {
  0%, 10%      { transform: translateX(0) rotate(-3deg); }
  13.3%        { transform: translateX(calc(var(--step) * .5)) translateY(-11px) rotate(5deg); }
  16.6%, 26.6% { transform: translateX(var(--step)) rotate(-3deg); }
  50%, 60%     { transform: translateX(calc(var(--step) * 3)) rotate(-3deg); }
  100%         { transform: translateX(0) rotate(-3deg); }
}

03오려낸 프레임 카드 격자

세 장이 각자 붙인 각도에서 0도까지 펴졌다 되돌아갑니다. 0.24초씩 어긋나게 두면 세 장이 한 덩어리가 아니라 따로 붙인 종이로 보입니다.

시차 0.24s각도 복원radius 4
.ccol__card--coral { --rot: -7deg; }
.ccol__card--sky   { --rot: 5deg;  animation-delay: -.24s; }
.ccol__card--grape { --rot: -4deg; animation-delay: -.48s; }

@keyframes cardStraighten {
  0%, 100% { transform: rotate(var(--rot)); box-shadow: 0 5px 0 rgba(36, 29, 46, .16); }
  45%      { transform: rotate(0deg) translateY(-8px); box-shadow: 0 13px 0 rgba(36, 29, 46, .12); }
}

04회전 스탬프 배지

점선 테두리 하나로 원이 도장이 됩니다. 0.55배까지 눌렸다가 1.16배로 튀어 오르는데, 기울기를 유지하려면 transform 값 하나 안에 rotate 를 매번 같이 써 줘야 합니다.

scale 0.55→1.16점선 테두리radius 50%
.scol__badge--lemon { --rot: -12deg; background: #ffd93d; }
.scol__badge--lime  { --rot: 8deg;   animation-delay: -.5s; }

@keyframes stampPress {
  0%, 55%, 100% { transform: rotate(var(--rot)) scale(1); }
  8%            { transform: rotate(var(--rot)) scale(.55); }
  20%           { transform: rotate(var(--rot)) scale(1.16); }
  32%           { transform: rotate(var(--rot)) scale(1); }
}

05마키 텍스트 띠

같은 낱말 묶음을 두 벌 깔고 한 벌 폭만큼만 밀면, 한 바퀴가 끝난 순간이 첫 프레임과 픽셀 단위로 같아집니다. 위아래 띠를 반대로 흘려보내면 두 줄이 서로 밀어내는 것처럼 읽힙니다.

두 벌 복제margin-right 간격translateX(-50%)
.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; }     // gap 으로 주면 -50% 가 어긋난다

@keyframes stripFlow { from { transform: translateX(0); } to { transform: translateX(-50%); } }

06손글씨 밑줄 후기

SVG 선 하나에 stroke-dashoffset 을 양수에서 0, 다시 음수로 보내면 왼쪽부터 그어졌다가 왼쪽부터 지워집니다. 되돌아가는 구간이 없으니 루프 이음매가 눈에 안 띕니다.

stroke-dashoffsetSVG pathradius 4
.tcol__line {
  fill: none;
  stroke: #d93a1e;
  stroke-width: 4;
  stroke-linecap: round;
  stroke-dasharray: 230;               // path 실측 길이보다 넉넉히
  animation-name: inkDraw;
  animation-duration: 2s;
  animation-iteration-count: infinite;
}
@keyframes inkDraw {
  0%   { stroke-dashoffset: 230; }
  45%  { stroke-dashoffset: 0; }
  70%  { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: -230; }
}

07겹침 레이어 요금제

카드 두 장을 음수 margin 으로 포개고 z-index 로 순서를 정합니다. 앞 카드가 떠오를 때 그림자 두께가 5px에서 17px로 늘어나야 층이 층으로 읽힙니다.

음수 margin 겹침그림자 확장radius 4
.pcol__plan--base { z-index: 1; transform: rotate(-3deg); }
.pcol__plan--pick {
  z-index: 2;
  margin-left: -20px;                  // 앞 카드가 뒤 카드 모서리를 덮는다
  margin-bottom: 16px;
}
@keyframes planLift {
  0%, 100% { transform: rotate(2deg) translateY(0);     box-shadow: 0 5px 0 rgba(36, 29, 46, .16); }
  50%      { transform: rotate(2deg) translateY(-12px); box-shadow: 0 17px 0 rgba(36, 29, 46, .12); }
}

08스탬프 CTA 밴드

띠 아래쪽을 반원으로 파냅니다. 마스크 두 겹이면 되는데, 원의 어느 쪽을 남기느냐가 전부입니다. 버튼은 도장처럼 기울며 눌리고, 내려가는 동안 그림자 두께도 14px에서 2px로 얇아집니다.

radial-gradient 마스크그림자=두께radius 4
.bcol {
  mask:
    radial-gradient(circle 8px at 50% 0, #000 98%, #0000 100%) 0 100% / 16px 8px repeat-x,
    linear-gradient(#000 0 0) 0 0 / 100% calc(100% - 8px) no-repeat;
}
@keyframes stampPush {
  0%, 100% { transform: translateY(-6px) rotate(-2deg); box-shadow: 0 14px 0 rgba(36, 29, 46, .35); }
  50%      { transform: translateY(0) rotate(1.5deg);   box-shadow: 0 2px 0 rgba(36, 29, 46, .35); }
}

09콜라주 푸터

큰 세리프 낱말을 일부러 잘리게 깔면 글자가 아니라 면으로 읽힙니다. 그 앞의 조각 넷은 0.5초씩 어긋나 떠다니는데, 올라갈 때 기울기 부호가 뒤집히면 종이가 뒤집히는 것처럼 보입니다.

배경 워드마크시차 0.5sradius 4
.fcol__word {
  position: absolute;
  left: -12px; bottom: -16px;
  color: rgba(36, 29, 46, .1);         // 면으로만 읽히게 10%
  font-size: 62px;
  white-space: nowrap;
}
@keyframes chipBob {
  0%, 100% { transform: translateY(0) rotate(var(--rot)); }
  50%      { transform: translateY(-9px) rotate(calc(var(--rot) * -1)); }
}

tailwind.config 커스텀

이 스타일에서 한 곳에 모아야 하는 값은 색이 아니라 각도입니다. 요소마다 기분대로 각도를 주면 겹침이 의도가 아니라 사고로 보입니다. 그래서 각도를 유틸리티 이름으로 바꿔 넷만 남깁니다.

theme: {
  extend: {
    colors: {
      cream: "#fbf3e4", sheet: "#ffffff", ink: "#241d2e", slate: "#57506a",
      coral: "#d93a1e", sky: "#2d6fb5", grape: "#6b3fa0",
      lemon: "#ffd93d", lime: "#b6e34f", blush: "#ffb3c7",
    },
    borderRadius: { chip: "4px", control: "12px", card: "16px", pill: "999px" },
    boxShadow: {
      paste: "0 5px 0 rgba(36,29,46,.16)",   // 붙어 있는 상태 = 두께
      stamp: "0 4px 0 rgba(36,29,46,.2)",
      lift:  "0 16px 0 rgba(36,29,46,.12)",  // 들어올렸을 때만
    },
    rotate: { a: "-3deg", b: "2deg", c: "-1.5deg", d: "5deg" },
  },
},
역할 토큰 언제
오려 붙인 각도 rotate-a ~ rotate-d 프레임·카드·배지·띠 전부
붙어 있는 두께 shadow-paste 바닥에 놓인 상태
들어올림 shadow-lift 떠오르는 순간에만

바이브코딩 프롬프트

설정 파일을 넣었다면 AI 편집기에 건네는 지시는 아래 한 덩어리로 끝납니다. 색 목록보다 각도 목록이 먼저 오는 순서가 중요합니다. 자르지 않은 원문은 zip 안의 prompt.md 에 있습니다.

각도는 네 개만 쓴다: -3deg, 2deg, -1.5deg, 5deg. 이 목록 밖의 각도를 만들지 않는다.
바닥에 붙은 요소의 그림자는 흐림 0 의 0 5px 0 rgba(36,29,46,.16), 들어올릴 때만
0 16px 0 으로 두껍게 바꾼다. 배경은 cream(#fbf3e4) 한 톤, 면은 sheet(#ffffff) 한 톤.
흰 글자는 coral·sky·grape 위에만 얹고, lemon·lime·blush 위에는 ink 글자만 얹는다.
사진은 쓰지 않는다 — 사진 자리는 두 색 linear-gradient 와 흰 테두리 6px 으로 대신한다.

위 지시로 나온 page/index.html 을 1280px 뷰포트에 띄워 페이지 전체를 한 장으로 찍었습니다.

결과

어디서 깨지는가 — 함정

제일 오래 헤맨 것은 CTA 띠의 가장자리였습니다. 아래쪽을 물결처럼 파내려고 radial-gradient 마스크를 깔았는데, 처음 쓴 circle 8px at 50% 0, #0000 98%, #000 100% 는 원의 바깥을 남기는 식이라 화면에는 아래로 뾰족한 삼각 톱니가 줄줄이 달렸습니다. 포스터를 열어 보고서야 알았습니다. 파도가 아니라 이빨이었습니다. 색 순서를 뒤집어 #000 98%, #0000 100% 로 원 안쪽을 남기자 그제야 반원이 아래로 매달렸습니다. 마스크는 "무엇을 지울까"가 아니라 "무엇을 남길까"로 읽어야 합니다.

두 번째는 마키 띠였습니다. 위아래 두 띠를 각각 -2.5도와 2도로 기울이고 음수 margin-top 으로 겹쳤더니, 렌더된 화면에서 아래 띠가 위 띠의 글자 밑동을 그대로 덮었습니다. 기울인 요소의 실제 점유 높이는 회전 전 높이보다 크기 때문에, 회전 전 기준으로 계산한 겹침 값이 그대로 통하지 않습니다. 아래 띠를 88% 폭으로 줄이고 오른쪽으로 붙여 띠 가장자리끼리만 겹치게 바꾸자 두 줄이 다 읽혔습니다. 같은 김에 트랙 폭도 Playwright 의 offsetWidth 로 다시 쟀습니다. 회전한 요소는 getBoundingClientRect 가 회전 후 경계 상자를 주므로 이 계산에는 쓸 수 없습니다. 위 띠 796px에 한 벌 398px, 아래 띠 524px에 한 벌 262px — 둘 다 정확히 절반이라 translateX(-50%) 한 바퀴의 이음매가 0px입니다. 두 함정을 다 손본 파일은 압축 비밀번호 s3yjtjja 으로 열리는 zip 안에 그대로 들어 있습니다.

접근성

색이 많을수록 대비를 눈으로 판정하면 안 됩니다. WCAG 2.1 최소 대비 기준의 상대 휘도 공식으로 열 가지 색을 전부 계산해 표로 정리했습니다. 본문 기준은 4.5:1입니다.

크림 바탕 위 흰 면 위 잉크 글자를 얹으면
잉크 #241d2e 14.76:1 16.28:1
슬레이트 #57506a 6.90:1 7.61:1
코랄 #d93a1e 4.16:1 4.59:1 3.55:1
스카이 #2d6fb5 4.70:1 5.18:1 3.14:1
그레이프 #6b3fa0 6.70:1 7.38:1 2.20:1
레몬 #ffd93d 1.25:1 1.38:1 11.82:1
라임 #b6e34f 1.35:1 1.49:1 10.92:1
블러시 #ffb3c7 1.52:1 1.68:1 9.71:1

여기서 쓰임이 두 갈래로 갈립니다. 코랄 글자는 흰 면 위에서 4.59:1로 통과하지만 크림 바탕에서는 4.16:1이라 본문으로 쓰면 안 됩니다. 그래서 부품 아홉 개의 코랄 글자는 전부 흰 카드 안에만 있습니다. 반대로 레몬·라임·블러시는 어느 바탕에서도 글자로 못 쓰는 대신 잉크 글자를 얹으면 9:1을 넘으므로, 배지와 띠의 으로만 씁니다.

움직임 쪽은 MDN prefers-reduced-motion 문서의 미디어 쿼리를 아홉 개 전부에 넣었습니다. 동작 줄이기를 켜면 흔들림과 흐름은 멈추지만 붙인 각도는 그대로 남습니다. MDN transform 문서rotate 로 만든 기울기가 이 스타일의 정체성이라, 각도까지 0으로 되돌리면 다른 디자인이 되기 때문입니다.

다른 밝은 톤 스타일이 궁금하면 종이 질감 디자인 랜딩 키트를 같이 보시고, 이 블로그가 뭘 주는 곳인지는 소개 페이지에 적어 뒀습니다.

FAQ

색을 여섯 개나 쓰면 촌스러워지지 않나요?

색 개수가 아니라 역할이 겹칠 때 촌스러워집니다. 이 키트에서 코랄·스카이·그레이프는 글자를 얹는 면이고 레몬·라임·블러시는 글자를 안 얹는 장식 면입니다. 역할이 갈려 있으면 한 화면에 여섯 색이 있어도 눈은 두 무리로 읽습니다.

각도를 왜 네 개로 묶나요?

기울기는 값이 아니라 목록이기 때문입니다. 요소마다 -2도, -7도, 3도처럼 제각각 주면 보는 사람은 그것을 "일부러 기울였다"가 아니라 "정렬이 틀렸다"로 읽습니다. 네 개를 돌려 쓰면 같은 손이 붙인 것처럼 보입니다.

사진 없이 만든 프레임이 어색하지 않나요?

사진 자리를 비워 두면 어색하지만, 두 색 그라디언트로 채우고 흰 테두리를 6px 두르면 액자 안에 무언가 들어 있는 것으로 읽힙니다. 실제 사진을 넣을 때도 이 구조 그대로 background 만 이미지로 바꾸면 되므로, 시안 단계에서 파일을 기다릴 필요가 없습니다.

압축 비밀번호를 입력하세요

비밀번호는 이 글 본문 안에 있습니다. 읽다 보면 나옵니다.