GODRICH

ai 랜딩페이지 오브 디자인 키트, 빛나는 섹션 9개

ai 랜딩페이지 오브 디자인은 화면 전체를 물들이는 대신 짙은 단색 무대 위에 빛나는 구슬 하나만 올려 제품의 성격을 말하는 방식입니다. 배경 그라디언트 없이도 AI 다워 보인다는 이 계산을 섹션 아홉 개로 잘라 정리했습니다.

지난 몇 년 동안 AI 제품 페이지는 대부분 화면 뒤편을 보라와 청록으로 물들이는 쪽을 골랐습니다. 다들 같은 배경을 쓰니 배경만으로는 구분이 안 되고, 그 위에 얹힌 글자와 버튼은 대비를 맞추느라 계속 무거워졌습니다. 여기 아홉 개는 반대로 갑니다. 무대를 잉크색 한 겹으로 눌러 두고 빛의 예산을 오브 하나에만 씁니다. 배경은 단색, 버튼은 솔리드, 빛나는 것은 구슬뿐입니다. 그렇게 조립한 한 장짜리 페이지가 아래에 실제로 돌아가고 있으니 스크롤해 보면서 화면 안에서 빛나는 것이 몇 개인지 세어 보세요.

새 창에서 원페이지 열기

저 페이지를 뜯어 아홉 조각으로 늘어놓은 것이 다음 격자입니다. 순서는 인기순이 아니라 방문자가 화면을 만나는 차례입니다. 첫 화면에서 눈이 멈추고, 상단 메뉴를 훑고, 기능 카드를 고르고, 목록으로 내려가고, 요금을 따져 보고, 다른 사람의 후기를 읽고, 가입 띠에서 결정하고, 푸터에서 헤어집니다. 아홉 번째인 버튼과 챗 인풋은 어느 섹션에나 끼어드는 조작 부품이라 마지막에 두었습니다.

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

01떠오르는 오브 히어로

152px 상자 안에 104px 구슬이 앉아 2초에 한 번 위아래 7px씩 오르내리고, 뒤에 깔린 빛 무리가 같은 박자로 0.82배에서 1배까지 부풀었다 줄어듭니다. 구슬은 사진도 filter: blur 도 아니라 하이라이트 한 겹, 하늘색 한 겹, 라일락 한 겹, 몸통 한 겹을 포갠 radial-gradient 네 장입니다.

radial-gradienttranslateYscalearia-hidden
.ho__orb {
  position: relative; z-index: 1; width: 104px; height: 104px; border-radius: 50%;
  background:
    radial-gradient(circle at 34% 28%, rgba(255, 255, 255, .92), rgba(255, 255, 255, 0) 44%),
    radial-gradient(circle at 28% 66%, rgba(110, 200, 255, .9), rgba(110, 200, 255, 0) 58%),
    radial-gradient(circle at 74% 72%, rgba(185, 160, 255, .8), rgba(185, 160, 255, 0) 56%),
    radial-gradient(circle at 50% 50%, rgba(47, 109, 246, .95) 10%, rgba(23, 20, 26, .96) 92%);
  animation-name: hoFloat; animation-duration: $duration; animation-timing-function: $easing;
  animation-iteration-count: infinite;
}
@keyframes hoFloat {
  0%, 100% { transform: translateY(7px); }
  50% { transform: translateY(-7px); }
}
@keyframes hoPulse {
  0%, 100% { transform: scale(.82); opacity: .5; }
  50% { transform: scale(1); opacity: .9; }
}

02미끄러지는 오브 닷 내비

메뉴 다섯 개 아래에 8px 발광 점 하나가 서서 활성 항목 쪽으로 가로로 미끄러집니다. 자리는 --p1 부터 --p5 까지 CSS 변수 다섯 개로 박아 두었고, 사람이 실제로 누르면 300ms 스프링 이징으로 옮겨 갑니다. 점 자체는 뜻을 전달하지 않으므로 활성 항목에는 aria-current 를 따로 답니다.

translateXtransitionaria-current
.nv__dot {
  --p1: 1.5px; --p2: 38px; --p3: 80px; --p4: 122px; --p5: 164px;
  position: absolute; left: 0; bottom: 0; width: 8px; height: 8px; border-radius: 50%;
  background: radial-gradient(circle at 38% 32%, rgba(255, 255, 255, .95), rgba(110, 200, 255, .95) 58%, rgba(47, 109, 246, .9) 100%);
  box-shadow: 0 0 12px 4px rgba(110, 200, 255, .45);
  transform: translateX(var(--p1));
  transition: transform $duration $easing;
}
@keyframes nvGlide {
  0%, 8% { transform: translateX(var(--p1)); }
  24%, 34% { transform: translateX(var(--p3)); }
  50%, 62% { transform: translateX(var(--p5)); }
  86%, 100% { transform: translateX(var(--p1)); }
}

03반짝 반응 카드 격자

카드 네 장에 28px 구슬이 하나씩 얹혀 있고, 손을 올리면 220ms 동안 카드가 2px 뜨고 그림자가 깊어지면서 구슬이 제 중심에서 1.35배로 커집니다. 커서를 쫓아다니는 스포트라이트는 쓰지 않았습니다. 빛나는 면적이 커질수록 어느 카드를 보고 있는지가 오히려 흐려지기 때문입니다.

scaletranslateYbox-shadowgrid-template-columns
.cg__orb {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 50%; transform-origin: 50% 50%;
  color: $stage-ink;
  background:
    radial-gradient(circle at 34% 28%, rgba(255, 255, 255, .95), rgba(255, 255, 255, 0) 46%),
    radial-gradient(circle at 66% 74%, rgba(185, 160, 255, .85), rgba(185, 160, 255, 0) 60%),
    radial-gradient(circle at 50% 50%, rgba(110, 200, 255, 1) 20%, rgba(47, 109, 246, .95) 96%);
  box-shadow: 0 0 10px rgba(110, 200, 255, .35);
  transition: transform $duration $easing;
}
.cg__card:hover, .cg__card:focus-visible {
  transform: translateY(-2px); box-shadow: $shadow-raised;
}
.cg__card:hover .cg__orb, .cg__card:focus-visible .cg__orb { transform: scale(1.35); }

04차례로 깨는 기능 목록

여섯 행에 놓인 14px 구슬이 위에서부터 334ms 간격으로 한 번씩 깨어납니다. 밝아지는 구간은 한 바퀴의 16퍼센트, 그러니까 320ms 안에 끝나도록 잡았습니다. 다음 행이 깨어나는 334ms보다 짧아야 한 번에 딱 하나만 밝기 때문입니다.

animation-delayopacityradial-gradient
@mixin orbSkin($hue) {
  background:
    radial-gradient(circle at 34% 26%, rgba(255, 255, 255, .92) 0%, rgba(255, 255, 255, 0) 44%),
    radial-gradient(circle at 52% 54%, $hue 0%, rgba($hue, .45) 58%, rgba($subject-ink, .92) 100%);
}
.fl__orb { width: 14px; height: 14px; border-radius: 50%; box-shadow: 0 0 10px rgba($color, .5); @include orbSkin($color); }
.fl.is-demo .fl__row:nth-child(2) .fl__orb, .fl.is-demo .fl__row:nth-child(2) .fl__label { animation-delay: 334ms; }
.fl.is-demo .fl__row:nth-child(3) .fl__orb, .fl.is-demo .fl__row:nth-child(3) .fl__label { animation-delay: 667ms; }
@keyframes flWake {
  0%   { opacity: .32; transform: scale(.86); }
  5%   { opacity: 1;   transform: scale(1.18); }
  11%  { opacity: 1;   transform: scale(1.06); }
  16%  { opacity: .32; transform: scale(.86); }
  100% { opacity: .32; transform: scale(.86); }
}

05오브 배지 요금제

세 플랜 중 추천 카드 머리 위로 14px 걸쳐 나온 28px 배지가 1초 주기로 6px 떠올랐다 내려앉습니다. 추천 카드는 색을 바꾸지 않습니다. 테두리를 잉크 32퍼센트로 진하게, 그림자를 $shadow-raised 로 깊게 주는 것이 전부라서 색을 구분하기 어려운 방문자에게도 위계가 그대로 남습니다.

translateYbox-shadowborder-color
.pr__orb {
  position: absolute; top: -14px; left: 50%; width: 28px; height: 28px; border-radius: 50%;
  background:
    radial-gradient(circle at 34% 26%, rgba(255, 255, 255, .95) 0%, rgba(255, 255, 255, 0) 46%),
    radial-gradient(circle at 52% 56%, $color 0%, rgba($color, .9) 54%, rgba($subject-ink, .82) 100%);
  box-shadow: 0 4px 12px rgba($color, .45);
  transform: translateX(-50%);
}
.pr__card--pick { border-color: rgba($subject-ink, .32); box-shadow: $shadow-raised; }
@keyframes prBob {
  0%   { transform: translateX(-50%) translateY(0); }
  50%  { transform: translateX(-50%) translateY(-6px); }
  100% { transform: translateX(-50%) translateY(0); }
}

06오브 아바타 후기

후기 세 장 맨 위에 파랑, 핑크, 민트 세 색조의 구슬 아바타가 하나씩 앉습니다. 얼굴 사진도 회사 로고도 별점도 없이 색조만으로 말하는 사람을 구분하는 방식이라, 실제 고객 사진을 아직 받지 못한 초기 제품에서 특히 쓸모가 있습니다. 손을 올리면 아바타가 불투명도 0.78에서 1로 오르며 1.18배 부풉니다.

radial-gradientscaletranslateY
@mixin orbSkin($hue) {
  background:
    radial-gradient(circle at 32% 26%, rgba(255, 255, 255, .95) 0%, rgba(255, 255, 255, 0) 44%),
    radial-gradient(circle at 52% 56%, $hue 0%, rgba($hue, .5) 58%, rgba($subject-ink, .92) 100%);
  box-shadow: 0 0 12px rgba($hue, .42);
}
.tm__orb {
  display: block; width: 28px; height: 28px; border-radius: 50%; opacity: .78;
  transform-origin: 50% 50%;
  transition: transform $dur-quick $easing, opacity $dur-quick $easing;
}
.tm__orb--first  { @include orbSkin($subject-blue); }
.tm__orb--second { @include orbSkin($subject-pink); }
.tm__orb--third  { @include orbSkin($subject-mint); }
.tm__card:hover .tm__orb, .tm__card:active .tm__orb { opacity: 1; transform: scale(1.18); }

07유영하는 오브 CTA 밴드

208px짜리 큰 구슬이 밴드 뒤편에서 좌우로 34퍼센트씩 왕복하며 천천히 흘러 다닙니다. 밴드는 overflow: hidden 으로 잘라 두었으니 구슬이 밴드 밖으로 새지 않습니다. 앞에 선 버튼은 크림색 솔리드 그대로 두고 호버에서 1px만 뜨게 했습니다. 빛나는 버튼을 얹으면 뒤의 구슬과 빛을 나눠 갖게 되기 때문입니다.

translateXradial-gradienttranslateY
.cb__orb {
  position: absolute; left: 50%; top: 50%;
  margin-left: -104px; margin-top: -104px;
  width: 208px; height: 208px; border-radius: 50%; z-index: 0; pointer-events: none;
  background: radial-gradient(circle at 50% 50%,
    rgba($color, .55) 0%,
    rgba($subject-blue, .40) 38%,
    rgba($subject-blue, 0) 70%);
  animation-name: orbDrift;
  animation-duration: $duration;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}
@keyframes orbDrift {
  0%   { transform: translateX(-34%); }
  50%  { transform: translateX(34%); }
  100% { transform: translateX(-34%); }
}

08궤도 오브 푸터

푸터 맨 위 2px 구분선이 그대로 궤도가 되고, 라일락 20px, 민트 14px, 파랑 24px 세 구슬이 왼쪽 밖에서 오른쪽 밖까지 건너가는데, 속도는 2초짜리 둘과 그 절반인 1초짜리 하나 두 종류뿐이고 셋을 갈라놓는 것은 -400·-500·-1200ms 의 음수 지연입니다. 움직이는 것은 구슬이 아니라 궤도와 폭이 같은 투명 캐리어입니다. 20·14·24px짜리 점에 퍼센트 값을 주면 자기 폭의 퍼센트라 궤도를 건너지 못하기 때문입니다.

translateXanimation-delaygrid-template-columns
.fo__beacon {
  position: absolute; left: 0; top: 50%; width: 100%; height: 0;
  animation-name: beaconCross;
  animation-timing-function: $easing;
  animation-iteration-count: infinite;
  animation-fill-mode: backwards;
}
.fo__beacon--slow  { animation-duration: $duration; animation-delay: -400ms; }
.fo__beacon--fast  { animation-duration: $dur-loop * .5; animation-delay: -500ms; }
.fo__beacon--drift { animation-duration: $duration; animation-delay: -1200ms; }
.fo__dot {
  position: absolute; left: 0; top: 0; transform: translate(-50%, -50%);
  width: 20px; height: 20px; border-radius: 50%;
}
@keyframes beaconCross {
  from { transform: translateX(-8%); }
  to   { transform: translateX(108%); }
}

09오브 버튼·챗 인풋

둥근 챗 입력창과 솔리드 버튼 둘입니다. 입력창이 포커스를 받으면 라일락 34퍼센트짜리 빛 무리가 box-shadow 로 딱 한 겹 생깁니다. 두 겹부터는 입력창이 스스로 빛나기 시작해 페이지의 빛 예산을 갉아먹습니다. 전송 버튼 안 8px 점은 누르는 동안 1.55배로 커지며 눌림을 알립니다.

box-shadowtransitionaria-label
.ch__field {
  display: flex; align-items: center; gap: $sp-2;
  padding: $sp-2 $sp-2 $sp-2 $sp-4;
  border: 1px solid rgba($subject-cream, .18);
  border-radius: $r-pill;
  background: rgba($subject-cream, .08);
  box-shadow: 0 0 0 0 rgba($color, 0);
  transition: box-shadow $dur-base $easing, border-color $dur-base $easing;
}
.ch__field:focus-within {
  border-color: rgba($color, .62);
  box-shadow: 0 0 0 4px rgba($color, .34);
}
.ch__dot {
  position: absolute; right: 5px; top: 5px;
  width: 8px; height: 8px; border-radius: 50%; opacity: .6;
  background: radial-gradient(circle at 50% 50%, rgba($subject-sky, 1) 0%, rgba($subject-blue, 1) 70%);
  transform-origin: 50% 50%;
  transition: transform $dur-instant $easing, opacity $dur-instant $easing;
}
.ch__send:active .ch__dot { transform: scale(1.55); opacity: 1; }

아홉 개를 480×300 화면에서 2초씩 12fps로 찍어 픽셀이 얼마나 바뀌는지 잰 값이 아래 표입니다. 누적면적은 첫 장과 한 번이라도 달라진 픽셀의 비율, 강도는 변한 픽셀의 평균 차이(0~255), 움직인프레임은 찍은 24장을 이웃끼리 견준 23칸 중 변화가 잡힌 칸의 수입니다.

부품 무대 오브 색조 누적면적 강도 움직인프레임
01 떠오르는 오브 히어로 잉크 sky 9.73% 43.7 23/23
02 미끄러지는 오브 닷 내비 잉크 sky 2.08% 48.5 15/23
03 반짝 반응 카드 격자 잉크 sky 10.70% 48.7 18/23
04 차례로 깨는 기능 목록 잉크 blue 4.37% 40.5 23/23
05 오브 배지 요금제 흰 페이퍼 blue 0.68% 36.2 16/23
06 오브 아바타 후기 잉크 blue 10.18% 40.9 17/23
07 유영하는 오브 CTA 밴드 오렌지 lilac 33.24% 25.5 18/23
08 궤도 오브 푸터 흰 페이퍼 lilac 6.16% 70.5 23/23
09 오브 버튼·챗 인풋 잉크 lilac 4.22% 40.3 12/23

07번이 33.24퍼센트로 가장 넓게 변하는데 강도는 25.5로 가장 낮습니다. 큰 구슬이 넓은 면을 부드럽게 쓸고 지나가기 때문입니다. 반대로 08번은 6.16퍼센트만 바뀌는 대신 강도가 70.5로 가장 높습니다. 작은 점이 어두운 띠 위를 또렷하게 건너가기 때문입니다. 넓고 흐리게 갈 것인가 좁고 또렷하게 갈 것인가를 이 두 숫자가 갈라 줍니다.

tailwind.config 커스텀

값을 한 곳에 모아야 하는 이유는 색이 아니라 빛의 예산 때문입니다. 그림자는 쉼(rest), 떠오름(raised), 포커스 빛 무리(halo) 세 개뿐이고 그중 빛나는 것은 halo 하나입니다. 세 개를 넘기는 순간 어느 요소가 앞에 있는지 눈이 고르지 못합니다.

theme: {
  extend: {
    colors: {
      ink: "#17141a", surface: "#252228", line: "#332f38",
      cream: "#fff7e6", mute: "#beb7ad",
      sky: "#6ec8ff", brand: "#2f6df6", lilac: "#b9a0ff",
      flame: "#ff4d1f", paper: "#ffffff",
      pink: "#ff9ebb", mint: "#4cd4a6",
    },
    borderRadius: { card: "16px", control: "12px", chip: "4px", pill: "999px" },
    boxShadow: {
      rest: "0 6px 12px rgba(23,20,26,.32)",
      raised: "0 14px 24px rgba(23,20,26,.32)",
      halo: "0 0 0 4px rgba(185,160,255,.34)",
    },
    spacing: { gutter: "16px" },
    transitionTimingFunction: {
      spring: "cubic-bezier(.2,.8,.2,1)",
      pop: "cubic-bezier(.2,1.4,.4,1)",
    },
  },
},

sky, brand, lilac 세 색을 아무렇게나 흩뿌리지는 않습니다. 이 셋은 페이지를 내려가며 단계적으로 바뀝니다. 01부터 03까지는 하늘색, 04부터 06까지는 파랑, 07부터 09까지는 라일락입니다. 방문자가 스크롤을 내릴수록 빛의 온도가 조금씩 옮겨 가는 셈이라, 각 섹션이 다른 화면처럼 보이면서도 한 페이지로 읽힙니다. 텍스트 색을 세 벌 만들 필요도 없습니다. 잉크 무대에서는 cream, 흰 무대에서는 ink 하나면 끝납니다. Tailwind를 안 쓴다면 같은 값이 CSS 변수로 정리된 tokens.css 파일 하나만 링크해도 됩니다.

바이브코딩 프롬프트

설정을 심었으면 Claude Code나 Cursor에 넘길 지시는 아래 한 덩어리로 충분합니다. 색 목록보다 무엇이 빛나면 안 되는지를 먼저 말하는 순서가 중요합니다. 생략 없는 원문은 zip 안 prompt.md 에 들어 있습니다.

빛나는 것은 오브뿐이다. 배경은 ink 단색으로 칠하고 그라디언트를 쓰지 않는다.
버튼은 cream 솔리드, 호버는 translateY 1~2px 와 그림자 교체로만 표현한다.
오브는 이미지도 filter:blur 도 아니다. radial-gradient 를 겹쳐 만든다 —
하이라이트를 30% 30% 에 한 겹, 몸통을 50% 50% 에 한 겹, 뒤에 빛 무리 한 겹.
오브는 aria-hidden="true" 로 읽기에서 빼고, 활성·추천·순서는 글자와 테두리로 따로 적는다.
색조는 페이지를 내려가며 sky → brand → lilac 로 옮긴다.

어디서 깨지는가 — 함정

가장 오래 붙들었던 것은 07번 CTA 밴드의 부제였습니다. 큰 구슬이 좌우로 흘러 다니니 밴드 안 네 줄이 각각 구슬의 다른 높이를 지나가고, 그래서 줄마다 뒤에 깔리는 색이 다릅니다. 구슬을 가운데 세워 두고 글자를 감춘 뒤 줄마다 가장 밝은 배경 픽셀을 찍어 봤더니, 19px 제목은 구슬 위쪽 어깨인 #53528a 를 지나며 6.70:1로 버티는데, 바로 아래 11px 부제만 핵을 정면으로 통과해 #6e6096 을 만나고 거기서 크림 72퍼센트가 3.58:1로 떨어졌습니다. 부제를 흐리게 깔아 제목과 위계를 만들어 뒀던 것이 원인입니다. 11px에 500 굵기라 큰 글자 예외도 못 받으므로 알파를 걷어 크림 100퍼센트로 올렸고, 같은 #6e6096 위에서 5.22:1이 되었습니다. 위계는 다시 크기(19px 대 11px)와 굵기(800 대 500)가 맡습니다. 흐린 글자로 위계를 만드는 습관은 잉크 맨바닥에서는 통하지만 빛 위에서는 그대로 깨집니다.

둘째는 줄바꿈입니다. 01번 제목에 word-break: keep-all 을 걸면 한국어는 어절 가운데서 끊기지 않아 보기 좋아집니다. 그런데 일본어는 띄어쓰기가 없어서 같은 속성을 걸면 줄을 바꿀 자리가 통째로 사라지고 제목이 가로로 넘칩니다. 결국 :lang(ko) 셀렉터를 달아 한국어에만 걸었습니다. 무대 색과 구슬 크기는 세 언어가 공유해도 되지만 글자 규칙은 그렇지 않습니다.

셋째는 다시 언어였습니다. 02번의 점이 서는 다섯 자리는 1.5px, 38px, 80px, 122px, 164px로 박아 둔 값인데, 이 좌표는 한국어 라벨을 480×300 화면에서 getBoundingClientRect 로 실제로 재서 얻은 제작용 실측값입니다. 라벨 폭은 언어마다 다르므로 영어와 일본어 화면에서는 점이 글자 한가운데를 비껴 섭니다. 그래서 데모 안에서는 offsetLeftoffsetWidth 로 진짜 좌표를 한 번 읽어 --p1 부터 --p5 까지를 덮어쓰게 했고, 창 크기가 바뀔 때도 같은 계산을 다시 돌립니다. 아홉 부품이 든 zip 의 비밀번호는 e3bm95my 이고, 이 좌표 덮어쓰기 코드도 그 안에 그대로 있습니다.

접근성

구슬은 뜻을 전하지 않으므로 아홉 개 전부 aria-hidden="true" 로 읽기에서 빼고, 상태와 순서는 글자나 테두리로 따로 적었습니다. 02번의 활성 메뉴는 MDN aria-current 문서대로 속성을 달아 소리로도 위치를 알리고, 05번의 추천 플랜은 색이 아니라 테두리와 그림자로 구분합니다.

MDN prefers-reduced-motion 문서의 미디어 쿼리는 아홉 개 전부에 넣었고, 움직임만 끄고 정보는 남겼습니다. 01번은 구슬과 빛 무리가 제자리에 서서 불투명도 0.9로 켜진 채 멈춥니다. 02번의 점은 첫 자리에 주차하고 위치는 aria-current 가 대신합니다. 03번은 카드 네 장이 쉬는 높이에 그대로 놓이고 손을 올려도 튀지 않으며, 04번은 여섯 구슬이 전부 완전히 밝은 상태로 굳습니다. 05번의 배지는 카드 위 가운데에 멈추고, 06번의 아바타 셋은 불투명도 1로 고정되어 세 색조가 오히려 또렷해집니다. 07번의 큰 구슬은 밴드 한가운데 주차해 글자 뒤 배경 역할만 하고, 08번의 세 구슬은 궤도의 20, 50, 62퍼센트 지점에 각각 서서 빈 선이 되지 않게 합니다. 09번은 포커스 링과 예시 글자를 켜 둔 채 애니메이션만 끕니다.

대비는 WCAG 2.1 최소 대비 기준의 상대휘도 공식으로 직접 계산했습니다.

글자 조합 대비 판정
잉크 무대 #17141a 위 크림 글자 #fff7e6 17.11:1 통과
잉크 위 하늘색 라벨 #6ec8ff 9.87:1 통과
잉크 위 크림 72% 합성 #beb7ad 9.18:1 통과
후기 카드 #252228 위 크림 글자 14.72:1 통과
흰 무대 #ffffff 위 잉크 글자 #17141a 18.24:1 통과
CTA 제목(19px) 배경 최악 #53528a 위 크림 100% 6.70:1 통과
CTA 부제(11px) 배경 최악 #6e6096 위 크림 100% 5.22:1 통과
같은 #6e6096 위에 부제를 크림 72%로 깔았을 때 3.58:1 실패 — 알파를 걷어 수리
CTA 눈썹(10px) 배경 최악 #203871 위 크림 72% 6.32:1 통과
CTA 주석(9px) 배경 최악 #1e305f 위 크림 62% 5.59:1 통과
잉크 위 브랜드 파랑 #2f6df6 4.03:1 본문 금지, 장식 아이콘만

기준을 못 넘는 줄은 둘이고 둘 다 처리가 끝났습니다. 부제의 3.58:1은 위에 적은 대로 알파를 걷어 5.22:1로 올렸고, 브랜드 파랑은 작은 장식 아이콘에만 쓰고 읽어야 하는 글자에는 쓰지 않았습니다. 구슬의 재료가 되는 그라디언트 자체는 MDN radial-gradient 문서의 표준 값이라, 지원이 없는 환경에서 최악의 결과도 단색 원입니다.

같은 무대를 부드러운 그림자로 푸는 방식은 뉴모피즘 소프트 UI 랜딩에, 이 편이 일부러 피한 배경 그라디언트 쪽은 오로라 메시 그라디언트 랜딩에 따로 정리해 두었습니다. 어떤 스타일이 지금 유행하는지는 디자인 트렌드 모아보기에서 이어 보세요.

FAQ

배경에 그라디언트를 조금만 깔면 안 되나요?

깔 수는 있지만 그러면 구슬이 배경에 묻힙니다. 이 키트의 전제는 화면에서 빛나는 곳이 한 군데뿐이라는 것입니다. 배경까지 빛나면 방문자의 눈이 어디를 봐야 할지 고르지 못하고, 무대 위 글자 대비도 지점마다 달라져 매번 다시 재야 합니다.

구슬을 filter: blur 로 만들면 더 쉽지 않나요?

더 쉽지만 값이 비쌉니다. filter 는 요소를 따로 합성해 그리므로 구슬이 여러 개 움직이는 화면에서 부담이 커지고, 흐림 정도를 화면 크기마다 다시 잡아야 합니다. 겹친 radial-gradient 는 배경 그리기 한 번으로 끝나고 하이라이트 위치를 퍼센트로 고정할 수 있습니다.

React 프로젝트에도 바로 붙일 수 있나요?

zip 안에 아홉 부품의 React 판이 .tsx.module.scss 쌍으로 같이 들어 있습니다. 시간, 이징, 대표색은 props로 받으므로 붙인 다음 값만 갈아 끼우면 됩니다. 바닐라 판과 React 판은 같은 토큰으로 함께 검증했습니다.

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

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