layout, paint, composite
이번에는 브라우저가 화면을 만드는 과정을 봅니다.
드래그할 때 부드럽게 움직이는 에디터와 뚝뚝 끊기는 에디터의 차이는 대단한 철학에서 나오지 않습니다. 브라우저에게 매 프레임 어떤 일을 시키느냐에서 나옵니다.
브라우저는 대략 layout, paint, composite 단계를 거쳐 화면을 만듭니다. 이 셋을 구분하면 왜 transform 기반 이동이 편집 도구에 유리한지 감이 옵니다.
layout은 자리 계산이다
layout은 각 요소가 문서 안에서 어디에 놓이고 얼마나 큰지 계산하는 단계입니다.
width, height, left, top, font-size 같은 값은 layout에 영향을 줄 수 있습니다. 특히 일반 문서 흐름 안에서는 한 요소의 크기가 바뀌면 주변 요소도 다시 계산해야 합니다.
change width
-> layout
-> paint
-> composite
편집기에서 드래그 중 매 프레임 layout을 크게 건드리면 화면이 무거워질 수 있습니다.
paint는 픽셀 만들기다
paint는 배경, 테두리, 그림자, 텍스트 같은 시각 결과를 픽셀로 그리는 단계입니다. background, box-shadow, filter 같은 속성은 paint 비용에 영향을 줍니다.
composite는 이미 그린 레이어를 합친다
transform이나 opacity 변경은 많은 경우 composite 단계에서 처리될 수 있습니다. 이미 그려진 레이어를 이동하거나 투명도만 바꾸는 식입니다.
transform은 이미 계산된 box에 affine matrix를 적용한다.
animation frame마다 O(n)으로 만질 DOM 수를 제한해야 한다.
그래서 드래그 preview에는 transform: translate(...)가 잘 맞습니다.
transform: translate(24px, 12px);
사용자가 드래그하는 동안에는 transform으로 빠르게 보여주고, pointerup에서 모델 좌표를 commit합니다.
read와 write를 섞지 말자
DOM 측정과 스타일 쓰기를 마구 섞으면 forced reflow가 생길 수 있습니다.
read: getBoundingClientRect()
write: element.style.transform = ...
read again
브라우저가 “아니 방금 바꿨는데 또 물어본다고요?” 하면서 layout을 즉시 다시 계산하게 됩니다. 그래서 보통 한 프레임 안에서 read를 모으고, 계산하고, write를 모아서 처리합니다.
will-change는 미리 힌트를 줄 수 있지만, 모든 요소에 붙여두면 오히려 메모리를 낭비합니다. 필요한 순간에 제한적으로 써야 합니다. 마법 가루처럼 뿌리는 속성이 아닙니다.
데모에서 볼 것
데모에서는 left/top 이동과 transform 이동의 차이를 비교합니다.
오늘의 핵심은 렌더링 파이프라인을 존중하는 것입니다. 편집기는 매 프레임 빠르게 반응해야 하므로, 브라우저에게 가능한 한 적은 일을 시켜야 합니다. 착한 도구는 사용자를 편하게 하고, 착한 구현은 브라우저를 편하게 합니다.