🎨 Frontend CSS5. 색·시각 효과02 — Gradients & Interpolation

02 — Gradients & Interpolation

한 줄 답: Gradient는 두 색 사이의 좌표 공간을 보간하는 함수이며, 어떤 색공간에서 보간하느냐가 결과를 절반 이상 결정한다. linear-gradient(red, blue)가 중간에 회색이 끼는 건 sRGB 보간의 함정이고, linear-gradient(in oklch, red, blue)가 깨끗한 보라를 그리는 건 OKLCH 보간이 perceptually uniform하기 때문이다.


Why — 왜 gradient가 어렵나

CSS의 gradient는 표면적으로 단순하다 — 색 두 개와 방향만 주면 된다. 그런데 결과가 자주 어색하다.

/* 예시 1: 회색 중간이 끼는 그라데이션 */
background: linear-gradient(to right, red, blue);
/* 중간이 진흙색 (~#7f007f의 어두운 보라가 아니라, RGB 평균인 칙칙한 색) */
 
/* 예시 2: 회색 단계를 거치는 hue 변화 */
background: linear-gradient(to right, yellow, blue);
/* 중간이 *회색*. 사람 직관: 초록 → 청록을 거쳐야 하는데 sRGB 평균은 회색 */

이유: sRGB 보간은 각 채널의 산술 평균을 낸다. 빨강 rgb(255 0 0) + 파랑 rgb(0 0 255)의 중간은 rgb(127 0 127) — 어두운 보라. 노랑 rgb(255 255 0) + 파랑 rgb(0 0 255)의 중간은 rgb(127 127 127) — 회색.

사람 눈은 지각적 보간을 기대한다 — 빨강에서 파랑으로 가려면 보라를 거치고, 노랑에서 파랑은 초록·청록을 거쳐야 한다. 이 기대를 만족하는 게 OKLCH 보간이다.


How — Gradient의 세 종류와 보간 색공간

Gradient 분류

종류함수용도
Linearlinear-gradient(<angle>, ...)표면 채우기, 배경, 마스크
Radialradial-gradient(<shape> at <pos>, ...)글로우, 스포트라이트, 둥근 배경
Conicconic-gradient(from <angle> at <pos>, ...)색상환, 파이 차트, 도트 패턴, gradient border
Repeatingrepeating-linear-gradient, repeating-radial-gradient, repeating-conic-gradient반복 패턴 (줄무늬, 격자)

Interpolation method — in <colorspace>

CSS Images Level 4(2024)에서 도입. 어느 색공간에서 색을 보간할지 명시.

/* sRGB (기본, 잘 안 보임) */
background: linear-gradient(red, blue);
background: linear-gradient(in srgb, red, blue);
 
/* OKLCH (사실상 표준) */
background: linear-gradient(in oklch, red, blue);
 
/* hue 보간 방향 명시 */
background: linear-gradient(in oklch longer hue, red, blue);
background: linear-gradient(in oklch shorter hue, red, blue);
background: linear-gradient(in hsl decreasing hue, red, blue);

지원하는 색공간:

  • srgb, srgb-linear, hsl, hwb, lab, lch, oklab, oklch
  • xyz, xyz-d50, xyz-d65
  • display-p3, rec2020, a98-rgb, prophoto-rgb

브라우저 지원: Chrome 111+ / Safari 16.2+ / Firefox 113+ (Baseline 2023).


What — 자주 쓰는 패턴

1) Linear Gradient — 각도와 stop

/* 각도 (12시=0deg, 시계방향) */
background: linear-gradient(135deg, #4a90e2, #f5a623);
 
/* 키워드 방향 */
background: linear-gradient(to bottom right, #4a90e2, #f5a623);
 
/* 다중 stop */
background: linear-gradient(
  to right,
  oklch(62% 0.21 254) 0%,
  oklch(70% 0.18 200) 50%,
  oklch(80% 0.15 145) 100%
);
 
/* hard stop (선명한 경계) */
background: linear-gradient(
  to right,
  red 0% 50%,
  blue 50% 100%
);
 
/* OKLCH 보간 + multi-stop */
background: linear-gradient(
  in oklch to right,
  oklch(60% 0.2 25),
  oklch(60% 0.2 145),
  oklch(60% 0.2 265)
);
/* L=60 고정이라 *진짜로* 같은 밝기의 hue ramp */

2) Radial Gradient — 모양·위치·크기

/* 기본 — 타원, 중심, 콘테이너 코너까지 */
background: radial-gradient(white, transparent);
 
/* 모양 + 위치 + 크기 */
background: radial-gradient(
  circle 200px at top right,
  oklch(80% 0.15 254 / 0.6),
  transparent
);
 
/* 글로우 효과 패턴 */
.glow-bg {
  background:
    radial-gradient(circle at 20% 30%, oklch(70% 0.2 25 / 0.4), transparent 50%),
    radial-gradient(circle at 80% 70%, oklch(70% 0.2 254 / 0.4), transparent 50%),
    var(--surface);
}

size 키워드: closest-side, closest-corner, farthest-side, farthest-corner (기본).

3) Conic Gradient — 각도 기반

/* 색상환 (color wheel) */
.color-wheel {
  background: conic-gradient(
    in oklch longer hue,
    oklch(70% 0.2 0),
    oklch(70% 0.2 360)
  );
  border-radius: 50%;
}
 
/* 파이 차트 */
.pie {
  background: conic-gradient(
    #4a90e2 0% 25%,
    #f5a623 25% 60%,
    #7ed321 60% 100%
  );
  border-radius: 50%;
}
 
/* gradient border (07장과 연결) */
.fancy-border {
  background:
    linear-gradient(white, white) padding-box,
    conic-gradient(from 45deg, #4a90e2, #f5a623, #7ed321, #4a90e2) border-box;
  border: 2px solid transparent;
}

4) Repeating Gradient — 패턴

/* 스트라이프 */
background: repeating-linear-gradient(
  45deg,
  oklch(95% 0 0),
  oklch(95% 0 0) 10px,
  oklch(90% 0 0) 10px,
  oklch(90% 0 0) 20px
);
 
/* 도트 패턴 */
background: repeating-radial-gradient(
  circle at 0 0,
  transparent 0 4px,
  oklch(80% 0 0) 4px 5px
);

5) currentColor + gradient — 테마 따라 자동 변화

.button {
  color: oklch(62% 0.21 254);
  background: linear-gradient(
    in oklch,
    color-mix(in oklch, currentColor 20%, transparent),
    color-mix(in oklch, currentColor 5%, transparent)
  );
}
/* color만 바꿔도 그라데이션 색이 함께 따라온다 */

What-if — 잘못 쓰면

1) sRGB 보간의 진흙색

/* 나쁨 */
background: linear-gradient(red, lime);
/* 중간에 칙칙한 갈색이 낀다 */
 
/* 좋음 */
background: linear-gradient(in oklch, red, lime);
/* 중간이 깨끗한 노랑-주황 */

2) transparent의 함정

/* 흑색이 슬쩍 끼는 페이드 */
background: linear-gradient(red, transparent);
/* transparent는 *검은색 0 알파*로 해석됨 → 중간이 어두워짐 */
 
/* 명시적 동일 색의 0 알파 */
background: linear-gradient(red, rgb(255 0 0 / 0));
/* 또는 */
background: linear-gradient(in oklch, red, oklch(63% 0.24 25 / 0));

transparent는 spec상 rgba(0,0,0,0)이다. 페이드아웃 만들 때는 같은 색 + 알파 0을 명시해야 깔끔하다. OKLCH 보간을 쓰면 어느 정도 완화되지만, 명시적 동일색 페이드가 가장 안전.

3) Conic gradient의 시작 각도 혼동

/* 기본 시작은 12시 (0deg) */
background: conic-gradient(red, blue);
/* red가 12시 정 위치, blue가 그 직전 */
 
/* 6시에서 시작 */
background: conic-gradient(from 180deg, red, blue);

from이 없으면 상단 정중앙이 시작. 파이 차트를 만들 때 *3시(=90deg)*에서 시작하고 싶으면 명시.

4) 성능 — 큰 면적 gradient + filter

/* 나쁨: 큰 그라데이션에 blur — paint 비용 폭증 */
.bg {
  width: 100vw; height: 100vh;
  background: linear-gradient(...);
  filter: blur(40px);
}
 
/* 좋음: 작은 그라데이션을 scale로 크게 */
.bg {
  width: 200px; height: 200px;
  background: linear-gradient(...);
  filter: blur(40px);
  transform: scale(10);
  transform-origin: 0 0;
}

filter는 합성 단계에 GPU로 처리되지만, 입력 raster 크기에 비례한다. 작게 그리고 transform으로 키우는 게 사실상 표준 트릭.

5) Gradient를 폰트 컬러로 — background-clip: text

.gradient-text {
  background: linear-gradient(in oklch, #4a90e2, #f5a623);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}

text-shadow로는 그라데이션 텍스트가 불가능하다 (단색만). background-clip: text가 사실상 유일한 방법. 단, 복사·접근성color: transparent 때문에 손해를 본다 — forced-colors 모드에서 안 보일 수 있으니 @media (forced-colors: active)에서 color: CanvasText 처리 권장.


Insight — Gradient의 역사

“Photoshop 5.0(1998)에서 시작된 라디언트가 24년 만에 CSS의 1급 시민이 됐다”

1998년 Photoshop 5.0의 Gradient Tool이 디자인의 사실상 표준 효과가 됐다. CSS는 한참 늦었다 — linear-gradient가 CSS3 Images에서 표준화된 게 2011년, radial-gradient가 2012년, conic-gradient는 2018년(Chrome 69)에 처음 들어왔다.

흥미로운 반전: conic-gradient는 한동안 polyfill로 살았다. Lea Verou의 conic-gradient.js(2017)가 SVG로 conic을 흉내냈고, 그 폴리필을 보고 “이건 CSS 1급으로 만들어야 한다” 는 합의가 형성됐다. 사용자 폴리필이 표준을 끌어당긴 드문 사례다.

OKLCH 보간(in oklch)은 2024년이 분기점이다. Chrome·Safari·Firefox가 동시에 풀린 다음, Tailwind v4가 기본 gradient 보간을 OKLCH로 바꿨다. 그 영향으로 디자이너의 직관과 코드의 결과가 30년 만에 일치하기 시작했다.

또 하나의 반전: gradient는 렌더링 비용이 의외로 싸다. 큰 면적이라도 GPU로 한 번에 그려진다. 비싼 건 gradient + filter blur의 조합 — 큰 raster를 blur 통과시키는 게 문제지, gradient 자체가 아니다.


요약 + Mermaid

  • Gradient는 3종류 — linear / radial / conic.
  • 보간 색공간이 결과의 절반 — in oklch가 사실상 표준.
  • transparent 페이드는 같은 색 + 알파 0으로 명시.
  • background-clip: text로 그라데이션 텍스트 (text-shadow로는 불가능).
  • 큰 면적 gradient + blur는 작게 그리고 transform: scale로.

다음: 03-shadows — gradient가 표면의 색이라면 shadow는 표면의 깊이다.