브라우저의 렌더링 과정을 공부하다보면 reflow와 repaint라는 단어들이 나오는데 오늘은 이 두 개념에 대해 알아보겠습니다!
우선 이 개념들을 알아보기 전에 브라우저의 렌더링 과정을 읽고 오시는걸 추천드려요!
리플로우와 리페인트는 DOM 요소가 시각적으로 변경됐을 때, 이 변화를 다시 계산하고 화면에 그려주는 작업을 말합니다.
DOM 요소의 기하학적 속성이 변경될때, 브라우저 사이즈가 변할때, 스타일시트가 로딩되었을 때 등 발생하는 변화들을 다시 해주는 작업을 뜻하고 레이아웃(Layout)이라고도 합니다.
즉, 요소의 변화에 따라 Layout 과정을 다시 수행하는 것을 Reflow라고 합니다.
DOM 요소의 속성 등이 변화되면 그 주변의 모든 요소도 영향을 받게되는데
결국 DOM 요소 중 하나라도 시각적 변화가 발생되면 DOM 트리 전체에 대해 다시 계산을 해야합니다.
Reflow는 렌더 트리를 재생성하므로 무거운 작업에 속합니다.
Reflow가 발생한 후 새로 계산된 Render Tree를 다시 화면에 그려주는 과정이 필요합니다.
그래서 변경된 요소를 실제로 화면에 그려주는 작업인 Paint단계를 다시 수행하는 것을 Repaint라고 합니다.
Reflow가 발생하면 필연적으로 Repaint가 실행됩니다.
그렇다고 무조건 Reflow가 발생해야만 Repaint가 발생하는건 아닙니다.
background-color, visibility와 같이 레이아웃에 영향을 주지 않는 경우는 Repaint만 발생합니다.
리페인트도 굉장히 무거운 작업이긴 하지만 리플로우 처럼 모든 요소들에 대한 기하학적 정보들을 계산해주는 작업은 아니기 때문에 리플로우 보다는 상대적으로 훨씬 가벼운 작업입니다.
불필요한 노드는 display: none 사용하기
Reflow 속성 사용 줄이기
DOM 속성 변경 코드 그룹핑 하기
div별로 속성을 가져와 변경할 경우 Reflow가 호출 횟수만큼 발생한 것을 볼 수 있다.
하지만 요소의 변경 할 부분을 바로 변경하지 않고 큐에 저장해뒀다가 후에 몰아서 변경하면 한 번에 처리하기 때문에 Reflow가 한번만 발생한 것이다.
// 나쁜 예
for(let i=1; i<10; i++){
div.style.left = (div1.getBoundingClientRect().left + i) + 'px';
}
// 좋은 예
let {left} = div1.getBoundingClientRect(); // reflow 유발 메서드는 변수에 저장해 사용
for(let i=1; i<10; i++){
div.style.left = (left + i) + 'px';
left += i;
}
<style>
.my-div {
width: 100px;
height: 100px;
padding: 5px;
border: 5px solid blue;
background-color: black;
color: white;
}
</style>
<body>
<div id="div"></div>
<script>
// 나쁜 예
div.style.width = "100px"; // reflow, repaint
div.style.height = "100px"; // reflow, repaint
div.style.padding = "5px"; // reflow, repaint
div.style.border = "5px solid blue"; // reflow, repaint
div.style.backgroundColor = "black"; // repaint
div.style.color = "white"; // repaint
// 좋은 예1
div.className = "my-div";
// 좋은 예2
div.style.cssText = "width: 100px; height: 100px; ...";
</script>
</body>