Figma node와 CSS DOM 모델
이제 Figma에서 만든 디자인을 CSS 기반 에디터나 웹 화면으로 옮기는 이야기를 해봅시다.
여기서 제일 먼저 버려야 할 생각이 하나 있습니다. “Figma node 하나는 div 하나다.” 이 말은 시작점으로는 괜찮지만, 끝까지 믿으면 곧 삐걱댑니다. Figma의 node는 디자인 모델이고, CSS의 DOM은 브라우저가 그릴 구조입니다. 둘은 닮았지만 같은 생물은 아닙니다.
Figma는 scene graph다
Figma 파일 안에는 frame, group, rectangle, vector, text, component instance 같은 node가 tree로 들어 있습니다.
node = {
id,
type,
parentId,
absoluteTransform,
relativeTransform,
size,
fills,
strokes,
effects
}
이 구조는 우리가 앞에서 만든 scene graph와 아주 비슷합니다. 부모 transform이 있고, child가 있고, frame은 clipping과 layout 규칙도 가질 수 있습니다.
Figma transform은 top-left 기준으로 읽는다
Figma node의 relativeTransform은 2x3 affine transform입니다.
T = [
[a, c, e],
[b, d, f]
]
local 점을 parent 좌표로 보내면 이렇게 됩니다.
x' = a * x + c * y + e
y' = b * x + d * y + f
여기서 local (0, 0)은 node의 top-left입니다. Figma의 rotation도 top-left 기준으로 해석됩니다. 그래서 CSS DOM으로 투영할 때는 기본 center origin을 그대로 쓰면 안 맞을 수 있습니다.
.node {
position: absolute;
width: var(--figma-width);
height: var(--figma-height);
transform-origin: 0 0;
transform: matrix(a, b, c, d, e, f);
}
Figma에는 CSS의 transform-origin처럼 별도 스타일 속성이 있는 게 아니라, transform matrix와 node size를 조합해서 pivot 동작을 만들어야 합니다. center 기준으로 회전시키고 싶다면 center가 부모 좌표에서 고정되도록 e, f를 다시 계산합니다.
pivotLocal = (width / 2, height / 2)
pivotParent = oldMatrix * pivotLocal
newTranslation = pivotParent - newLinearPart * pivotLocal
이 식은 Figma to CSS뿐 아니라 group 안의 child를 frame으로 옮기는 reparenting, rotation handle, resize handle에서도 계속 다시 나옵니다. 결국 “어느 점을 고정할 것인가?”를 정하는 문제입니다.
CSS는 projection이다
CSS 구현에서는 이 모델을 DOM과 style로 투영합니다.
Figma Frame -> div.frame
Figma Group -> div.group or flattened wrapper
Figma Rectangle -> div with width/height/background/border
Figma Vector -> svg path or exported asset
Figma Text -> text element with font styles
여기서 중요한 건 “변환 결과”를 저장 모델로 삼지 않는 겁니다. Figma에서 가져온 원본 구조나 우리가 정리한 중간 모델을 유지하고, 렌더링할 때만 DOM/CSS를 만듭니다. 그래야 다시 export하거나, undo/redo하거나, Canvas 렌더러로 바꿀 때 덜 흔들립니다.
1:1 변환이 안 되는 지점
Figma의 stroke align은 inside, center, outside를 가질 수 있지만 CSS border는 기본적으로 box model 안에 포함되는 방식이 다릅니다. Figma의 layer blur와 background blur도 CSS filter, backdrop-filter와 완전히 같은 모델이 아닐 수 있습니다.
그래서 변환기는 늘 세 가지 선택을 합니다.
1. CSS primitive로 직접 표현한다.
2. wrapper나 pseudo-element를 추가해서 근사한다.
3. SVG나 이미지 asset으로 내보낸다.
완벽한 변환보다 중요한 건 정책이 일관적인 겁니다. 같은 Figma 속성이 어떤 경우에는 div, 어떤 경우에는 svg로 튀면 나중에 디버깅할 때 머리가 살짝 뜨거워집니다.
데모에서 볼 것
데모에서는 Figma node tree가 DOM tree와 CSS style projection으로 어떻게 나뉘는지 봅니다.
오늘의 핵심은 이겁니다. Figma to CSS는 파일을 문자열로 바꾸는 일이 아니라, 한 그래픽 모델을 브라우저 모델로 번역하는 일입니다. 번역가는 단어만 바꾸지 않고 문맥도 봅니다. 우리도 그래야 합니다.