리플로우와 리페인트
만약 자바스크립트 코드에 DOM이나 CSSOM을 변경하는 DOM API가 사용된 경우 DOM이나 CSSOM이 변경된다. 이때 변경된 DOM과 CSSOM은 다시 렌더 트리로 결합되고 변경된 렌더 트리를 기반으로 레이아웃과 페인트 과정을 거쳐 브라우저의 화면에 다시 렌더링한다. 이를 리플로우(reflow), 리페인트(repaint)라 한다.
리플로우는 레이아웃 계산을 다시 하는 것을 말하며, 노드 추가/삭제, 요소의 크기/위치 변경, 윈도우 리사이징 등 레이아웃에 영향을 주는 변경이 발생한 경우에 한하여 실행된다. 리페인트는 재결합된 렌더 트리를 기반으로 다시 페인트를 하는 것을 말한다.
따라서 리플로우와 리페인트가 반드시 순차적으로 동시에 실행되는 것은 아니다. 레이아웃에 영향이 없는 변경은 리플로우 없이 리페인트만 실행된다.
리플로우
- 레이아웃 계산을 다시 하는 것을 말하며, 노드 추가/삭제, 요소의 크기/위치 변경, 윈도우 리사이징 등 레이아웃에 영향을 주는 변경이 발생한 경우에 한하여 실행된다.
- 이 과정을 리플로우(Reflow), 레이아웃(Layout), 레이아웃팅(Layouting)이라고도 부릅니다.
리플로우가 발생하는 상황
- DOM 노드의 추가 또는 제거
- DOM 노드의 위치 변경
- DOM 노드의 크기 변경
- 폰트 변경(텍스트 내용)과 이미지 크기 변경 시
- 페이지 초기 렌더링 시
- 윈도우 리사이징 시
- 스타일 추가 또는 제거
- 클래스 Attribute의 동적 변화
- JS를 통한 DOM 동적 변화
- 요소에 대한 offsetWidth / offsetHeight 계산 시
리페인트
- 재결합된 렌더 트리를 기반으로 다시 페인트를 하는 것을 말한다.
- 리플로우가 발생하거나 배경색 변경 등의 단순한 스타일 변경과 같은 작업이 발생하는 경우에 발생합니다.
- 이 과정을 리페인트(Repaint), 리드로우(Redraw)라고 합니다.
- 리페인트만 발생하는 경우
- visibility : hidden 으로 DOM 요소를 숨기는 경우
- background-color, visibility, outline 등의 스타일 변경
리플로우 최소화 방법
최소화 해야하는 이유
- 리플로와 리페인트 모두 처리 비용이 발생하지만 리페인트보다 리플로의 비용이 훨씬 높습니다. 리플로는 변경 범위에 따라 전체 페이지의 레이아웃을 변경해야 할 수도 있기 때문입니다.
- 어느 경우든 리플로와 리페인트 때문에 UI의 화면 표현이 느려져 사용자 경험에 영향을 줄 수 있으므로 코드를 작성할 때 이를 최소화해야 합니다.
최소화 방법
- display 속성
- 기본적으로 리플로와 리페인트는 모두 화면에 변경된 사항이 반영되는 시점에 발생합니다.
- 여러 속성의 스타일을 변경하는 중간 단계에서는 화면에 표시하지 않고, 작업이 완료되면 최종 결과가 반영되는 마지막 시점에 요소를 다시 표시합니다.
- 노드 복제
- 변경하려는 요소의 노드를 복제한 후 복제된 노드에 필요한 작업을 실행하는 방법입니다.
- 복제된 노드는 DOM 트리에 추가된 상태가 아니므로 렌더링 성능에 영향을 줄 수 있는 작업을 실행하더라도 리플로나 리페인트가 발생하지 않습니다.
- 캐싱
- 특정 속성과 메서드를 사용하기만 해도 리플로가 발생할 수 있습니다. 자주 사용하는 속성의 값이나 메서드의 반환값을 변수에 저장하면 직접 속성이나 메서드를 호출하는 횟수를 줄여 성능을 향상시킬 수 있습니다.
- CSS 규칙
- 각 요소에 접근해 값을 변경하기 보다는 CSS 규칙을 생성하고 해당 규칙이 요소에 반영되게 하는 것이 좋습니다.
- 하지만 대상 요소의 수가 많지 않다면 CSS 규칙 처리 방식보다 오히려 개별 요소에 접근해 처리하는 방식이 더 빠릅니다.
- 클래스 변화에 따른 스타일 변화를 원할 경우, 최대한 DOM 구조 상 끝단에 위치한 노드에 줍니다
- DOM 트리에서 끝단에 위치한 노드에 클래스 변화를 줄 경우, 이는 리플로우의 행동반경을 전체 페이지가 아닌 일부 노드들로 제한할 수 있다.
- 인라인 스타일을 최대한 지양합니다.
- 인라인 스타일로 주어진 경우, 리플로우는 페이지 전체에 걸쳐 수차례 발생한다.
- 인라인 스타일로 하지 않을 경우 외부 스타일 클래스의 조합으로 단 한번만 리플로우가 발생합니다.
- 애니메이션이 들어간 요소는 가급적 postion을 fixed 또는 absolute로 지정합니다.
- position을 fixed 또는 absolute로 지정할 경우 다른 요소들의 레이아웃에 영향을 끼치지 않으므로 페이지 전체의 Reflow 대신 해당 애니메이션 요쇼의 Repaint만 발생합니다.
- JS를 통해 스타일 변화를 줄 경우 가급적 한 번에 처리합니다.
- 여러 번에 걸쳐 처리할 경우 여러번 중복된 Reflow와 Repaint가 발생합니다.
- 단 한번의 변화만을 발생시키는 것이 더욱 효과적입니다.
참고자료
모던 자바스크립트 deep dive