[TIL] CSS Geometry

2026. 05. 23.Yeji Kim
Frontend

1. 어떤 사이트?

cssgeometry.realerror.com

CSS로 Figma 같은 그래픽 툴을 만들고 싶은 사람을 위한 선형대수·기하학 강의를 표방하는 사이트이다. (슬로건은 "Math first")

평소 보던 CSS 문서가 이 속성으로 이런 효과를 낼 수 있어요 식이라면, 이쪽은 회전된 박스 위에 마우스가 들어왔는지 어떻게 판단할 건가 같은 에디터 문제에서 출발해 좌표·벡터·행렬로 푸는 흐름이다.


2. 인사이트 1 - transport layr 잘 구현하기

에디터에서 자주 등장하는 동작들은 사실 거의 다 같은 식 위에 얹혀 있다.

  • 마우스가 어떤 객체 위에 있는지 판단 (hit test)
  • 마우스 드래그로 객체 옮기기
  • 휠로 줌 인/아웃 (특히 커서 위치를 기준으로 줌)
  • marquee selection, 스냅핑, 가이드

이 모든 게 결국 화면 좌표 ↔ 캔버스(월드) 좌표 변환이라는 한 겹의 변환에 기댄다. 카메라가 (x, y, zoom)이라고 할 때, 변환은 다음 두 함수가 전부다.

ts
type Camera = { x: number; y: number; zoom: number };
 
function screenToCanvas(sx: number, sy: number, cam: Camera) {
  return { x: (sx - cam.x) / cam.zoom, y: (sy - cam.y) / cam.zoom };
}
 
function canvasToScreen(cx: number, cy: number, cam: Camera) {
  return { x: cx * cam.zoom + cam.x, y: cy * cam.zoom + cam.y };
}

이걸 잘 깔아두면 줌·드래그·스냅 같은 동작들이 별개 기능이 아니라 같은 좌표계 위의 작은 식으로 바뀔 수 있다.


3. 인사이트 2 - Cursor-anchored zoom

Figma에서 마우스 휠로 줌하면 커서가 가리키던 지점이 화면에서 움직이지 않는다. 아래 변환 식만 있으면 자연스럽게 유도된다.

조건은 한 줄이다.

text
줌 전 커서 아래 캔버스 좌표 === 줌 후 커서 아래 캔버스 좌표

식으로 풀면:

ts
function zoomAt(sx: number, sy: number, factor: number, cam: Camera) {
  // 1) 줌 전, 커서가 가리키는 캔버스 좌표를 기억
  const before = screenToCanvas(sx, sy, cam);
 
  // 2) 줌 적용
  cam.zoom *= factor;
 
  // 3) 같은 캔버스 좌표가 같은 화면 좌표를 가리키도록 카메라 재배치
  //    canvasToScreen(before, cam) === (sx, sy) 가 되어야 함
  cam.x = sx - before.x * cam.zoom;
  cam.y = sy - before.y * cam.zoom;
}

에디터의 인터랙션은 CSS 트릭의 모음이 아니라, 잘 정의된 좌표 변환 한 겹 위에 얹힌 작은 식들의 모음이다.


참고