HTML, CSS, JavaScript, React 등 지금까지 주구장창 코드를 짜고 구현하는 것에만 집중해왔는데 면접을 보고나서 "아, 조금 더 근본적인 개념을 공부할 필요가 있겠다" 라는 생각을 하게 됐습니다.
그래서 먼저 브라우저에서 렌더링 엔진을 이해할 필요가 있다고 생각해서 포스팅을 합니다.
위의 그림은 렌더링 엔진의 작동 과정을 나타낸 이미지입니다. 과정에 대한건 추후에 렌더링 과정에 대한 글로 정리해보겠습니다.
Reflow
는 한국말로 번역하자면 다시 배치한다는 의미입니다. DOM노드의 레이아웃에 영향을 주는 요소들이 바뀌면(width, height 등등) 영향을 받는 모든 노드들의 수치를 다시 계산해서 렌더트리를 재생성하는 과정을 Reflow
라고 합니다.
그렇다면 Repaint는 뭘까요? 말 그대로 '다시 그린다' 는 의미입니다. 앞에서 Reflow
과정으로 렌더트리가 재생성되고, 이렇게 생성된 렌더트리를 브라우저에 우리가 보는 화면으로 그리는 과정이 바로 Repaint
입니다.
그렇다면 만약 레이아웃과 관계없는 스타일(background-color, visibility 등)을 바꿨을 때는 어떤 일이 일어날까요? Reflow
는 레이아웃과 관련이 있다고 했었죠? 그래서 Reflow
과정이 스킵되고 바로 Repaint
과정으로 넘아가서 다시 그리게 됩니다.
그렇다면 결국 뷰를 빠르게 그리기 위해서 Reflow와 Repaint를 최소한으로 그려야 합니다. 최적화에는 여러가지 방법이 있는데 이 사이트에서 많은 도움을 얻었습니다.
클래스 변화에 따른 스타일을 변경할 경우 최대한 DOM트리 끝단의 노드를 선택하자.
한마디로 Reflow의 반경을 최소한으로 하자는 의미입니다. 레이아웃에 영향을 받는 노드들이 적으면 적을수록 지출되는 비용이 적어지겠죠.
인라인 스타일을 배제하자.
애니메이션을 가진 노드는 position: fixed, position: absolute를 줘서 전체 노드트리에서 분리시키자.
position 'fixed', 'absolute' 속성을 지정된 노드는 전체 노드트리에서 분리됩니다. (이 속성이 레이아웃에 영향을 받지 않는 이유겠죠.) 따라서 Reflow 과정은 발생하지 않고 Repaint 비용만 들어가기 때문에 훨씬 비용을 덜 쓸 수 있겠죠.
테이블 레이아웃은 피하자.
페이지가 테이블 레이아웃으로 구성되어있으면, 이를 모두 계산한 후에 화면에 그립니다. 그러면 UX측면에서 좋지 않겠죠?
cssText 혹은 클래스를 지정해서 스타일을 입히자.
JavaScript 코드 안에서 스타일을 줄 때마다 매번 DOM을 호출해서 입히지 말자는 얘기입니다.
클래스를 줘서 css 파일 안에서 스타일을 주거나, cssText를 통해 한 번에 스타일을 주는 것이 좋습니다.
캐쉬를 활용해 Reflow 수행 횟수를 줄이자.
중복되는 수치에 대한 스타일 정보를 변수로 저장해 캐싱하는게 좋습니다. 예를 들어, container 역할을 하는 div 태그의 너비를 두, 세번 DOM을 호출해서 사용하는 것보다는 이 너비를 하나의 변수로 캐싱해서 사용하는 것이 Reflow 비용을 줄일 수 있습니다. 왜냐면 이렇게 스타일 정보를 요청할 때마다 정확한 정보를 전달하기 위해 레이아웃 변경 정보를 담는 큐를 싹 다 비우고 다시 변경사항을 큐에 담기 때문이죠.
DOM 사용을 최소화하자.
제가 생각할 때 핵심적인 해결책인 것 같습니다. 프로그래머스 프런트엔드 과제테스트를 볼 때도 DOM사용을 최소하해라 라는 조건이 있었거든요. 이 것은 추후에 더 알아보겠습니다.