Nextjs에서 FCM을 통한 알림 수신하기
브라우저의 이해 #1 Reflow, Repaint에 대하여 알아봅니다.
2019-03-10
Explanation
이번에는 Reflow와 Repaint에 대하여 알아보려고 합니다.
그래도 적지 않은 시간동안 웹 개발일을 하고, 꽤 적지 않은 시간… 프론트 위주의 개발일을 해왔는데요. 민망하게도 브라우저가 렌더링하는 과정이나 Reflow, Repaint에 대해 잘 알지 못하고 있었답니다. 이렇게 글을 적기 전에 공부를 조금 하니, 하… 이런 것도 잘 알지 못하고 개발을 하고 있었다는 것이 창피하네요… 흑…
하지만 모르는 것은 창피한게 아닙니다. 알려하지 않는게 창피한 것이죠!
(자기 위로…)
포스팅을 위해 인터넷에서 몇몇 글들을 읽어 보았는데요. 브라우저 렌더링에 관한 부분은 NAVER D2에 있는 글이 정말 세세하게 잘 적혀 있는거 같아요.
링크. https://d2.naver.com/helloworld/59361
위 NAVER D2의 글을 읽고 렌더링에 관해 적는 건 무의미하다 생각이 들었지만.. 간단하게 요약하자면, 브라우저마다 다른 렌더링 엔진을 사용하고 있는데요. 크롬/사파리는 웹킷(webkit), 파이어폭스는 게코(Gecko) (다이나믹듀…) 렌더링 엔진에 따라서 동작하는 과정이 조금 다르지만, 오늘 적으려했던 reflow와 repaint는 비슷한 순서로 동작한답니다.
브라우저는 일단 HTML, StyleSheets를 해석 합니다. 그리고 HTML 문서의 해석이 끝나면 ‘DOM 트리’를 만들고, StyleSheets 문서의 해석이 끝나면 ‘스타일 규칙’을 만듭니다.
위에서 만들어진 ‘DOM 트리’와 ‘스타일 규칙’을 합쳐서 ‘렌더 트리’를 만들어요. 그리고 여기에서 reflow(배치)가 호출?되어서 각각의 요소들의 레이아웃을 위치 시킨답니다.
(이름이 좀 이상하게 느껴질 수 있는 거 같아요. 제가 여기에서 reflow가 호출된다고 했는데, 처음엔 그냥 배치가 되고 이후 수정에 대해서 reflow가 발생하겠지만, 그 수행하는 과정이 같을테니 그냥 이후의 이해를 위해 reflow라고 사용하였습니다.)
여기서 또 짧게 렌더 트리에 대해 적어보자면, 렌더 트리는 DOM 요소를 기반으로 만들어지겠지만, 완전히 대응하는 구조로 만들어지진 않아요. DOM 트리가 문서의 구조를 나타낸다면 렌더 트리는 문서의 시각적 구조를 나타낸다고 생각할 수 있을 거 같아요.
그래서 예를 들면 스타일에 ‘display’속성이 ‘none’으로 되어 있다면, DOM 에는 물론 존재하지만, 시각적으로는 없는 것이기 때문에 렌더 트리에는 할당되지 않는 답니다.
또한, float 또는 position 값이 absolute, fixed 이렇게 스타일적으로 DOM 문서의 순서과 상관없이 시각적으로 별개로 위치하는 요소의 경우에는 DOM 트리와 다른 위치의 렌더 트리에 할당된다고 해요.
이름 그대로 렌더트리가 탐색되고 paint 매서드가 호출되어서 UI 기반의 구성요소를 사용해서 그린다고 하네요. 설명이 짧아 정확하게 이해할 수는 없지만 여하튼, 이전에 만들어진 렌더트리(레이아웃)을 기반으로 화면을 그리는 작업을 하는 단계인거 같아요.
그리고 여기에서 수정 사항이 생기면 이 글의 제목에 있는 Repaint가 호출됩니다.
그리고 그리기에서 참고로 그려지는 순서는 CSS2 기준으로 배경색 > 배경이미지 > 테두리 > 자식 > 아웃라인 순서라고 하네요.
여기까지가 Reflow와 Repaint를 이해하기 위한 정도의 간단한 브라우저의 렌더링 과정을 정리해본건데.. 이해에 도움이 됬을지 모르겠네요.
이제 본격적으로 Reflow에 대해 알아봅니다!
앞서 ‘렌더 트리’의 과정에서, 요소들의 레이아웃 위치를 렌더 트리에 구성하는데 거기서 Reflow가 호출된다고 했었는데요. 우선 기본적으로 최초에 한번 실행이 되고, 이후에 요소들의 레이아웃에 영향을 주는 변화가 생기면 다시 렌더 트리를 구성해야 하겠죠?? 고것을 Reflow라고 하는 것 같아요.
그러면 reflow가 일어나는 상황을 생각해보면, 새로운 요소(=엘리먼트=노드)가 추가되거나 또는 요소가 지워지거나, 요소의 위치가 변경되거나 크기가 변경되거나, 만약에 위치값이나 크기값이 상대값으로 되어 있다면 브라우저(윈도우)의 크기가 변경될때도 발생할 것 같아요.
글을 이만큼 적고보니 가장 중요한 부분을 빼먹은거 같네요. 늦었지만 지금 적자면, 이 글에 중요한 부분은 브라우저의 렌더링 과정을 이해하고 reflow와 repaint를 줄여서 성능을 높이자, 혹은 불필요한 성능 저하를 줄이자 입니다.
아직 이야기하진 않았지만, 브라우저 렌더링 과정에서 Reflow는 Repaint의 상위 과정이기 때문에 Reflow가 발생하면 자연히 Repaint도 발생되는 것 같아요.
Reflow가 많이 발생하면 성능이 떨어지겠죠?? 그래서 간단하게 Reflow를 줄이는 몇가지 예시를 들어보자면,
1 2 3 4 5 6 7 8 |
// bad const body = document.body; body.style.width = '50px'; body.style.height = '100px'; // good const body = document.body; body.style.cssText = 'width: 50px; heigh: 100px;'; |
위와 같이 요소에 스타일을 줄때는 cssText로 reflow가 한번만 실행되도록 할 수 있어요.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// bad const ulElement = document.getElementsByTagName('ul')[0]; for(let i=0; i<10; i++) { ulElement.innerHTML += `<li> list${i} </li>`; } // good const ulElement = document.getElementsByTagName('ul')[0]; let strHtml = ulElement.innerHTML; for(let i=0; i<10; i++) { strHtml += `<li> list${i} </li>`; } ulElement.innerHTML = strHtml; |
비슷한 예로 여러개의 엘리먼트가 추가된다면 위와 같이 가상의 형태로 추가할 엘리먼트를 구성하고 한번에 수정해서 reflow를 줄일 수 있을 거 같아요.
앞서 이야기한 대로 Repaint는 Reflow의 하의 과정이니까 Reflow가 발생하면 자연히 Repaint가 발생할 거에요. 하지만 Reflow가 발생하지 않고 Repaint만 발생하는 경우도 있답니다. Reflow가 레이아웃, 포지션에 대한 변화 때문에 일부 혹은 전체를 다시 구성하고 그리는 반면, 만약 레이아웃에 영향을 주지 않는 엘리먼트 개별의 변화에서는 Reflow가 발생하지 않고 Repaint만 발생한답니다.
예를 들자면 color, background-color, visibility 같은 스타일 속성들이 있을 것 같아요.
참고링크.
1. https://d2.naver.com/helloworld/59361
2. https://github.com/wonism/TIL/blob/master/front-end/browser/reflow-repaint.md
3. https://webclub.tistory.com/346
4. https://www.slideshare.net/doosungeom/reflow-and-repaint
끝