CSS Graphics Geometry
Guide
Reference
GitHub
Guide
Reference
GitHub
  • Part 0. Math foundations

    • 좌표계와 CSS pixel
    • 점, 벡터, 거리와 기본 용어
    • 각도, 라디안, atan2
  • Part 1. Transform linear algebra

    • translate, scale, rotate
    • CSS matrix(a,b,c,d,e,f)
    • 변환 순서와 transform-origin
    • local, world, screen 좌표계
    • inverse matrix와 포인터 입력
    • 좌표와 transform 디버깅
  • Part 2. Infinite canvas math and architecture

    • viewport와 camera 모델
    • cursor anchored zoom
    • ruler와 tick 계산
    • 주기 함수와 grid step
    • content, overlay, controls layer
    • scene graph와 nested transform
  • Part 3. Editor tool math

    • Pointer Events와 드래그
    • DOMRect와 getBoundingClientRect
    • hit testing과 bounding box
    • selection rectangle과 marquee
    • selection bounds와 handles
    • resize와 rotation handle
    • snapping과 smart guides
    • group, frame, clipping
  • Part 4. CSS graphics properties as math

    • CSS box로 도형 만들기
    • clip-path, radius, shadow
    • 선형보간과 linear-gradient
    • 거리 함수와 radial/conic-gradient
    • stacking context와 합성
    • layout, paint, composite
  • Part 5. Editor state and persistence

    • 레이어 모델과 z-index
    • 이동, 복제, 삭제, 잠금
    • undo/redo command model
    • JSON export/import
  • Part 6. SVG overlay and vector editing

    • SVG viewBox와 좌표계
    • getScreenCTM과 inverse
    • SVG pointer-events와 stroke hit testing
    • cubic bezier path editing
    • mask, clipPath, marker
  • Part 7. Figma to CSS translation

    • Figma node와 CSS DOM 모델
    • Frame constraints와 Auto Layout
    • Fills, strokes, effects를 CSS로
    • Vector와 text 변환
    • gradient 밖의 CSS 수학
    • Figma gradient를 CSS gradient로 변환하기
    • 수학이 필요한 Figma to CSS 속성들
    • Figma VectorNetwork 정리
  • Appendix A. Canvas renderer transition

    • Canvas로 넘어가는 기준
  • Appendix B. Motion and timing

    • 모션 수학과 timing 함수
    • Keyframe timeline 엔진
    • Motion path 수학
    • Bezier curve 길이 구하기

거리 함수와 radial/conic-gradient

이번에는 원형으로 퍼지는 색, radial-gradient입니다. 그리고 옆에 살짝 붙여서 conic-gradient도 같이 보겠습니다.

지난 시간의 linear-gradient가 “축 위에서 어디쯤이냐”를 물었다면, radial-gradient는 이렇게 묻습니다.

“중심에서 얼마나 멀리 있니?”

그리고 conic-gradient는 이렇게 묻습니다.

“중심을 기준으로 몇 도 방향이니?”

질문이 참 단순하죠. 그런데 이 질문 두 개가 원형 그라디언트, 각도형 컬러 피커, 브러시 크기, 원형 hit area, 핸들 근접 판정까지 줄줄이 데리고 옵니다. 중심과 거리, 중심과 각도. 이 조합은 그래픽 에디터에서 생각보다 자주 나타납니다.

중심에서 거리 재기

한 픽셀의 위치를 pixel, 중심을 center라고 하면 둘의 차이는 벡터입니다.

v = pixel - center

이 벡터의 길이를 구하면 중심에서 픽셀까지의 거리가 됩니다.

d = length(pixel - center)

반지름이 radius라면, 이 거리를 0..1 값으로 정규화할 수 있습니다.

u = clamp(d / radius, 0, 1)

u = 0이면 중심, u = 1이면 반지름 지점입니다. 색상 stop은 이 u 값을 기준으로 샘플링됩니다.

여기서 “거리장”이라는 말을 쓸 수 있습니다. 각 픽셀마다 중심으로부터의 거리값을 하나씩 가지고 있는 장입니다. 이름이 좀 학술적으로 들리지만, 사실은 모든 픽셀에 “너 중심에서 몇 점?” 하고 점수를 매기는 겁니다.

radial gradient distance field diagramcenterpixelcircle:u = length(pixel - center) / rellipse:q = ((x-cx)/rx, (y-cy)/ry)u = length(q)conic uses angle
radial-gradient는 중심에서 픽셀까지의 거리장을 색으로 읽습니다. ellipse는 x/y를 반지름으로 나눈 정규화 공간에서 계산하면 됩니다.

color stop은 위치표다

gradient의 color stop은 그냥 색 목록이 아닙니다. “이 위치에서는 이 색”이라는 표입니다.

radial-gradient(
  circle farthest-corner at 50% 48%,
  #f6c85f 0%,
  #0d9488 36%,
  #9ac8eb 68%,
  #101820 100%
)

위 코드는 이렇게 읽으면 됩니다.

center = (50%, 48%)
radius = distance(center, farthestCorner)
u = distance(pixel, center) / radius
color = interpolate stops by u

예를 들어 u = 0.52라면 36%와 68% 사이에 있으니, 브라우저는 teal과 blue 사이를 보간합니다. 즉 color stop은 “색을 몇 번째로 칠할지”가 아니라, 거리 함수의 결과값을 색으로 바꾸는 lookup table에 가깝습니다. 말이 좀 그럴싸하죠. 하지만 하는 일은 착합니다.

CSS에서 circle farthest-corner를 쓰면 반지름은 중심에서 가장 먼 모서리까지의 거리입니다.

r = max(
  distance(center, topLeft),
  distance(center, topRight),
  distance(center, bottomRight),
  distance(center, bottomLeft)
)

그래서 중심을 드래그하면 색이 단순히 “위치만” 바뀌는 게 아닙니다. 중심에서 가장 먼 모서리도 바뀌고, 그 결과 100% stop이 놓이는 실제 픽셀 거리도 바뀝니다. 이 부분을 안 보면 gradient editor를 만들 때 stop marker가 묘하게 밀립니다. 어? 왜 맞는데 안 맞지? 하는 그 맛없는 버그가 여기서 나옵니다.

원과 타원은 살짝 다르다

circle은 x와 y를 같은 비율로 봅니다. 그런데 ellipse는 가로 반지름과 세로 반지름이 다릅니다. 그래서 먼저 좌표를 타원 기준으로 정규화한 다음 길이를 재면 됩니다.

q = ((x - cx) / rx, (y - cy) / ry)
u = length(q)

이렇게 하면 타원도 “정규화된 공간에서는 원”처럼 다룰 수 있습니다. 그래픽스에서 자주 쓰는 수법입니다. 어려운 도형을 바로 상대하지 말고, 쉬운 좌표계로 끌고 와서 계산하는 겁니다. 수학도 가끔 협상을 합니다.

CSS 파라미터로 보면

CSS의 radial-gradient에서 shape, size, position은 결국 중심과 반지름을 정하는 말입니다.

background: radial-gradient(circle at 50% 50%, red, blue);

이 문장은 대략 이렇게 읽을 수 있습니다.

center = box center
shape = circle
color = sample by distance from center

디자인 에디터에서는 중심점 핸들과 반지름 핸들을 따로 노출하면 모델이 깔끔해집니다. 사용자는 핸들을 움직이고, 에디터는 그 값을 CSS 문자열로 바꿉니다.

conic-gradient는 거리 대신 각도다

conic-gradient는 중심점까지는 radial-gradient와 같습니다. 하지만 색을 고르는 기준이 거리가 아니라 각도입니다.

background: conic-gradient(
  from 0deg at 50% 48%,
  #f6c85f 0deg,
  #0d9488 120deg,
  #9ac8eb 240deg,
  #f6c85f 360deg
);

CSS gradient 각도는 화면 위쪽을 0deg로 보고, 시계 방향으로 증가한다고 생각하면 편합니다. 그래서 화면 좌표의 벡터 v = pixel - center에서 conic angle은 이렇게 잡을 수 있습니다.

dx = pixel.x - center.x
dy = pixel.y - center.y
angle = atan2(dx, -dy)

보통 수학 시간의 atan2(dy, dx)와 인자 순서가 달라 보이죠. 괜찮습니다. 우리가 원하는 기준이 “오른쪽 0도”가 아니라 “위쪽 0도”라서 그렇습니다. CSS가 살짝 장난을 치는 게 아니라, 화면 좌표계에 맞춘 겁니다. 그래도 처음 보면 조금 얄밉긴 합니다.

여기서 color stop은 0%..100% 대신 0deg..360deg 위치표가 됩니다.

angle = 156deg
active stop interval = 120deg -> 240deg
color = interpolate stops by angle

그래서 radial과 conic은 같은 “중심점 기반 gradient”처럼 보이지만, 샘플링 함수가 다릅니다.

radial: color = f(distance(pixel, center))
conic:  color = f(angle(pixel - center))

이 차이를 분리해두면 UI도 좋아집니다. radial editor는 중심점과 반지름/타원 핸들이 중요하고, conic editor는 중심점과 각도 stop marker가 중요합니다.

편집기에서 쓰이는 곳

원형 브러시 미리보기, spotlight 효과, radial color picker는 모두 거리장을 시각화한 것입니다. 사용자가 핸들 근처를 클릭했는지 판단할 때도 같은 거리 계산을 씁니다.

회전된 타원형 gradient처럼 복잡해 보이는 경우도 있습니다. 이때는 포인터를 먼저 오브젝트의 local 좌표로 되돌린 다음 거리 함수를 적용하면 훨씬 단순해집니다. “좌표계를 바꾸면 문제가 쉬워진다”는 말, 앞으로도 계속 나옵니다. 교수님이 질리게 말할 예정입니다.

데모에서 볼 것

데모에서는 가운데 흰 핸들을 직접 드래그해보세요. radial 모드에서는 원형 stop marker가 0%, 36%, 68%, 100% 거리 위치를 보여줍니다. conic 모드에서는 각도 방향선과 0deg, 120deg, 240deg stop marker를 보여줍니다.

radial-gradient는 결국 중심에서의 거리로 색을 고르는 함수입니다. conic-gradient는 중심 기준 각도로 색을 고르는 함수입니다. 그러니 원형 도구를 만들 때마다 속으로 이렇게 물어보면 됩니다. “이 픽셀은 중심에서 얼마나 멀고, 어느 방향이지?”

Edit this page
최근 수정: 26. 5. 14. PM 5:45
Contributors: easylogic
Prev
선형보간과 linear-gradient
Next
stacking context와 합성