dom

3 개의 포스트

figma

속성 패널과 주석 기능, 이제 Figma Make에서 사용 가능 | Figma 블로그 (새 탭에서 열림)

Figma Make에 속성 패널과 주석 기능이 추가되어, 사용자는 코드를 직접 작성하지 않고도 시각적으로 인터페이스를 수정할 수 있게 되었다. 속성 패널은 간격·타이포그래피·레이아웃 같은 시각적 변경을 정밀하게 처리하고, 주석은 애니메이션이나 상호작용처럼 설명이 필요한 변경을 특정 요소에 연결해 전달한다. 두 기능은 디자인과 코드 사이의 간극을 줄이고, 프롬프트 기반 편집보다 정확하고 효율적인 작업 흐름을 제공한다. ## Figma Make의 속성 패널과 주석 기능 - Figma Make 편집기에서 요소를 선택한 뒤 시각적 컨트롤이나 자연어 주석으로 코드를 수정할 수 있다. - 디자인을 수정하는 과정과 코드가 업데이트되는 과정을 하나의 연속적인 작업 흐름으로 통합한다. - 새 기능은 처음부터 작업하는 경우뿐 아니라 기존 코드 기반 프로젝트를 편집할 때도 사용할 수 있다. ## 속성 패널을 활용한 시각적 편집 - 상단 툴바에서 **Edit**를 선택하면 요소의 속성을 조정할 수 있다. - 조정 가능한 항목에는 다음이 포함된다. - 패딩, 요소 간 간격, 코너 반경 - 글꼴 굵기, 줄 높이, 자간 - 투명도, `z-index`, 테두리 스타일 - 위치와 레이아웃 속성 - 코드의 전체 DOM 트리를 레이어 패널처럼 확인하면서 원하는 요소를 선택할 수 있다. - 동일한 요소의 모든 인스턴스를 한 번에 선택해 일괄 수정할 수 있다. - 현재는 코드베이스에 정의된 색상 및 타이포그래피 토큰을 사용해 디자인 일관성을 유지한다. - 향후 Code Connect가 적용되면 Figma Design 컴포넌트와 코드 컴포넌트 간 연결도 강화될 예정이다. ## 변경 사항 검토와 코드 반영 - 속성 패널에서 변경한 내용은 즉시 코드에 확정되지 않고 프롬프트 입력창에 먼저 단계적으로 쌓인다. - 사용자는 각 변경 사항을 검토한 뒤 적용하거나 마음에 들지 않는 변경을 폐기할 수 있다. - 적용을 완료하면 Figma Make가 실제 코드를 수정하고 새로운 파일 버전을 생성한다. - 따라서 캔버스에서 시각적으로 확인한 결과와 실제 배포되는 코드 사이의 불일치를 줄일 수 있다. ## 주석을 통한 정밀한 프롬프트 작성 - 속성 패널만으로 표현하기 어려운 상호작용, 애니메이션, 동작 변경에는 주석 기능을 사용할 수 있다. - **Annotate for agent**를 선택한 뒤 캔버스에서 변경 대상 영역을 직접 표시하고 자연어로 요구사항을 작성한다. - 예시는 다음과 같다. - 썸네일에 마우스를 올리면 약간 확대 - 버튼을 300ms 지연 후 페이드 인 - 버튼을 탭할 때 눌리는 효과 추가 - 메뉴 버튼 클릭 시 전체 화면 내비게이션 오버레이 표시 - 번호가 매겨진 주석으로 여러 요소를 동시에 지정할 수 있다. - 에이전트는 표시된 정확한 위치와 설명을 함께 활용해 관련 코드 전체에 변경 사항을 적용한다. ## 프롬프트 비용과 작업 효율 - 직접 요소를 선택하면 에이전트가 수정 대상을 탐색하거나 추측할 필요가 줄어든다. - 일반적인 텍스트 프롬프트로 같은 변경을 설명하는 것보다 토큰을 적게 사용하고 더 빠르게 완료할 수 있다. - 변경 사항은 적용 전까지 크레딧을 소비하지 않고 대기한다. - 최종적으로 변경 사항을 적용할 때 크레딧이 차감되고 파일이 새 버전으로 업데이트된다. ## 디자인과 코드의 통합 - 속성 패널은 시각적 조정에, 주석은 동작과 맥락이 필요한 변경에 적합하다. - 두 기능을 통해 사용자는 코드를 직접 다루면서도 Figma와 유사한 시각적 편집 경험을 유지할 수 있다. - 같은 편집 경험은 향후 Figma Design의 코드 레이어에도 제공될 예정이다. - 장기적으로는 Figma 캔버스에서 코드 기반 결과물을 여러 방향으로 탐색하고 팀과 함께 비교하는 작업이 가능해진다. 실무에서는 간격·타이포그래피·레이아웃처럼 명확한 시각 속성은 속성 패널로 수정하고, 인터랙션이나 애니메이션처럼 의도가 중요한 변경은 주석으로 요청하는 방식이 가장 효율적이다. 적용 전 검토 단계가 제공되므로 여러 변경을 시도한 뒤 실제 코드 반영 여부를 결정하는 것도 권장된다.

figma

Canvas 기반 제품에 접근성 구축하기 | Figma 블로그 (새 탭에서 열림)

Figma는 캔버스 렌더링으로 무한 줌과 실시간 협업 같은 성능을 얻었지만, 브라우저의 기본 접근성 기능을 사용할 수 없게 되었다. 이를 해결하기 위해 디자인의 scenegraph를 기반으로 접근성 정보를 담은 내부 트리와 이를 반영하는 Mirror DOM을 구축했다. 그 결과 스크린 리더 사용자는 Figma 파일을 탐색·편집하고, 캔버스 선택 상태와 키보드 탐색을 연동하며, 비시각적 변경 사항도 안내받을 수 있다. ## 캔버스 기반 제품의 접근성 문제 - Figma 캔버스는 일반 HTML/DOM 대신 자체 렌더링 시스템을 사용한다. - 이 방식은 전통적인 웹 앱보다 높은 성능을 제공한다. - 무한 줌 - 실시간 멀티플레이어 협업 - 게임과 유사한 고성능 그래픽 처리 - 반면 브라우저가 자동으로 생성하는 접근성 트리를 활용할 수 없다. - 실제 캔버스에는 여러 디자인 레이어가 있어도 포커스를 유지하는 `<input>` 요소 하나만 존재하므로, 스크린 리더가 인식할 구조가 거의 없었다. ## 접근성 트리 합성 - 브라우저의 접근성 트리는 DOM, 시맨틱 HTML, ARIA 속성, 계산된 상태를 바탕으로 생성된다. - Figma는 이 기능을 되살리기 위해 실제 캔버스와 별도로 접근성용 DOM 요소를 합성했다. - 이 구조를 통해 스크린 리더가 Figma 파일의 레이어를 탐색하고 편집할 수 있게 했다. - 시각적 렌더링과 접근성 정보를 분리해, 캔버스의 성능을 유지하면서 브라우저의 보조 기술과 연동한다. ## 네 가지 핵심 시스템 Figma의 접근성 구현은 다음 시스템들이 협력하는 구조다. - **내부 접근성 트리** - 각 디자인 레이어의 접근성 정보를 캐시한다. - 변경이 발생할 때 전체를 다시 만들지 않고 필요한 부분만 갱신한다. - **Mirror DOM React 컴포넌트** - 내부 접근성 트리를 참조해 실제 DOM 요소를 생성한다. - 각 레이어에 대응하는 접근성 요소를 재귀적으로 렌더링한다. - **양방향 선택 동기화** - 캔버스에서 노드를 선택하면 대응하는 DOM 요소에 포커스를 이동한다. - 스크린 리더나 키보드로 DOM 요소를 탐색하면 캔버스 선택 상태도 갱신한다. - **공지 시스템** - 탐색 외의 변경 사항을 사용자에게 알린다. - 예를 들어 객체 이동, 도구 전환 등 시각 사용자에게는 명확하지만 스크린 리더 사용자는 놓칠 수 있는 변화를 안내한다. ## 문맥에 따른 접근성 요약 - 각 디자인 레이어마다 스크린 리더가 읽을 수 있는 **접근성 요약(accessible summary)** 을 생성한다. - 같은 디자인이라도 사용 중인 애플리케이션 문맥에 따라 요약 방식이 달라진다. - 프로토타입을 보는 상황에서는: - 편집 관련 기능을 대부분 제외한다. - 텍스트 필드의 내용이나 클릭 동작이 있는 요소의 버튼 역할처럼 최종 사용자에게 필요한 정보만 제공한다. - 문서를 편집하는 상황에서는: - 오토레이아웃 프레임처럼 편집에 필요한 구조도 접근성 트리에 포함한다. - 레이어별 요약을 만든 뒤 트리를 위에서 아래로 순회하며, 접근성에서 제외된 노드는 제거하고 하위 노드를 상위 구조에 병합한다. - 문서 최초 로딩 시에는 전체 접근성 트리를 구성하지만, 이후에는 편집된 부분만 수술적으로 갱신해 비용을 줄인다. ## Mirror DOM의 재귀적 렌더링 - React 기반 `Mirror DOM` 컴포넌트가 접근성 트리의 각 레이어를 DOM으로 변환한다. - 각 컴포넌트는 특정 레이어의 접근성 요약을 구독한다. - 요약에서 다음 정보를 가져와 DOM 요소를 생성한다. - `label`: 스크린 리더가 읽을 이름 - `role`: 버튼, 입력 필드 등 요소의 의미 - `children`: 하위 레이어 - 하위 레이어는 같은 컴포넌트를 재귀적으로 호출해 DOM 트리를 구성한다. - 내부 접근성 트리를 최소 단위로 갱신하면 React가 실제 DOM 변경도 최소화할 수 있다. ## 시각적 콘텐츠와 접근성 콘텐츠의 분리 - Mirror DOM은 화면에 보이지 않지만 보조 기술이 해석할 수 있는 구조를 제공한다. - 일반적인 visually hidden 스타일을 사용하지 않는 점이 특징이다. - 캔버스 기반 제품에서는 접근성용 DOM이 페이지 레이아웃이나 캔버스 렌더링에 영향을 주지 않도록 별도의 방식으로 관리해야 한다. - 핵심은 시각적 UI를 억지로 HTML로 대체하는 것이 아니라, 보조 기술이 필요로 하는 의미 구조를 별도로 합성하는 것이다. 캔버스 기반 제품에 접근성을 추가할 때는 브라우저가 자동으로 제공하던 기능을 직접 재구축해야 한다. 특히 내부 접근성 트리, 점진적 갱신, 시각 UI와 DOM의 양방향 상태 동기화를 함께 설계하는 것이 중요하다.

github

Diff 라인 성능 개선을 위한 험난한 여정 (새 탭에서 열림)

GitHub는 대규모 풀 리퀘스트에서도 **Files changed** 탭의 반응성과 안정성을 유지하기 위해 단일 해결책이 아닌 여러 최적화 전략을 적용했다. 특히 diff 라인마다 생성되는 DOM 요소, React 컴포넌트, 이벤트 핸들러를 줄여 메모리 사용량과 입력 지연을 낮추고, 가장 큰 변경 사항에는 가상화를 적용해 렌더링 범위를 제한하는 방향을 택했다. 핵심 교훈은 작은 구조적 최적화도 수천 개의 diff 라인에 누적되면 큰 성능 개선으로 이어진다는 것이다. ## 대규모 풀 리퀘스트에서 성능이 어려운 이유 - GitHub의 풀 리퀘스트는 한 줄 수정부터 수천 개 파일과 수백만 줄을 포함하는 변경까지 규모 편차가 매우 크다. - 일반적인 풀 리퀘스트는 빠르게 동작했지만, 대규모 변경에서는 다음 문제가 발생했다. - JavaScript 힙이 극단적인 경우 1GB를 초과 - DOM 노드 수가 40만 개 이상으로 증가 - 페이지 상호작용이 매우 느려지거나 사실상 사용할 수 없게 됨 - 입력 후 다음 화면이 표시되기까지의 시간인 INP가 허용 수준을 초과 - 모든 기능과 브라우저의 기본 동작을 유지하면서 최악의 경우까지 해결하는 단일 기법은 현실적인 한계가 있었다. ## 풀 리퀘스트 규모별 최적화 전략 GitHub는 변경 규모와 복잡도에 따라 서로 다른 전략을 조합했다. - **diff 라인 컴포넌트 최적화** - 대부분의 풀 리퀘스트에서 기본 diff 화면을 빠르게 유지 - 중간 및 대규모 리뷰에서도 브라우저의 기본 `find-in-page` 같은 동작을 보존 - **가상화를 통한 점진적 성능 저하** - 가장 큰 풀 리퀘스트에서는 한 번에 렌더링하는 콘텐츠 양을 제한 - 모든 내용을 동시에 DOM에 올리지 않아 응답성과 안정성을 우선 - **기반 컴포넌트와 렌더링 개선** - 특정 모드에 관계없이 모든 크기의 풀 리퀘스트에 누적 효과를 제공 - 렌더링 구조 자체를 단순화해 메모리와 상호작용 비용을 줄임 ## 초기 목표와 측정 지표 최적화 작업의 목표는 단순히 평균 속도를 높이는 데 그치지 않았다. - JavaScript 힙 크기와 메모리 사용량 감소 - DOM 노드 수 감소 - 평균 INP 개선 - 특히 최악의 사용자 경험을 나타내는 p95와 p99 INP 대폭 개선 - 이를 위해 상태, HTML 요소, JavaScript 코드, React 컴포넌트 수를 전반적으로 줄이는 단순화 전략을 채택 ## v1의 문제: diff 라인당 높은 렌더링 비용 React로 처음 diff 화면을 구현한 v1은 작은 재사용 컴포넌트를 많이 조합하는 구조였다. - unified 뷰의 diff 한 줄에는 최소 약 10개의 DOM 요소가 필요했다. - split 뷰에서는 한 줄당 약 15개의 DOM 요소가 필요했다. - 구문 강조를 적용하면 추가 `<span>` 요소가 더해져 DOM 수가 증가했다. - React 계층에서도 다음과 같은 컴포넌트가 생성됐다. - unified 뷰: 한 줄당 최소 8개 컴포넌트 - split 뷰: 한 줄당 최소 13개 컴포넌트 - 댓글, hover, focus 등 추가 상태가 활성화되면 컴포넌트 수는 더 늘어났다. - 작은 컴포넌트마다 React 이벤트 핸들러를 5~6개씩 연결하는 경우가 많았다. - 결과적으로 diff 한 줄에 20개 이상의 이벤트 핸들러가 붙을 수 있었고, 이를 수천 줄에 적용하면서 비용이 급격히 커졌다. v1의 한 줄당 최소 구조는 다음과 같았다. - DOM 요소 10~15개 - React 컴포넌트 8~13개 - React 이벤트 핸들러 20개 이상 - 다수의 작은 재사용 컴포넌트 이 구조는 일반적인 규모에서는 문제가 없었지만, 데이터 크기가 사실상 제한되지 않는 대규모 풀 리퀘스트에서는 변경 줄 수가 늘수록 INP와 JavaScript 힙 사용량이 함께 악화됐다. ## v2의 방향: 작은 변경을 대규모로 누적 v2에서는 눈에 띄지 않는 HTML 구조까지 점검해 diff 라인당 비용을 줄였다. - 줄 번호 셀에 불필요하게 포함되어 있던 `<code>` 태그를 제거했다. - diff 한 줄에서 DOM 노드 2개를 줄이는 것은 개별적으로는 작은 개선처럼 보인다. - 그러나 10,000줄을 렌더링하면 DOM 노드 20,000개를 제거하는 효과가 발생한다. - 이처럼 줄 단위의 사소한 최적화도 대규모 데이터에서는 메모리 사용량과 렌더링 비용에 크게 누적된다. - 성능 개선에서는 큰 기능 변경만큼 불필요한 태그, 컴포넌트, 이벤트 핸들러를 하나씩 제거하는 작업도 중요하다. ## 실용적인 결론 대규모 목록이나 코드 diff를 렌더링할 때는 처음부터 최악의 데이터 규모를 고려해야 한다. 컴포넌트를 잘게 나누는 구조가 유지보수에는 유리할 수 있지만, 각 요소에 상태와 이벤트 핸들러를 추가하면 수천 개 항목에서 큰 비용이 된다. 따라서 DOM 구조를 단순화하고, 항목별 렌더링 비용을 측정하며, 극단적인 규모에는 가상화를 적용하는 조합이 효과적이다.