문서 내 노드들의 레이아웃, 포지션을 재계산 후 다시 뿌려주는 행위로 Repaint보다도 더 심각한 퍼포먼스 저하를 유발시키는 프로세스이다. 특정
엘리먼트에 대한 Reflow 발생 시, 페이지에서의 해당 요소는 즉시 Reflow State가 되며 해당 엘리먼트의 자식요소와 부모/조상 요소역시
레이아웃 계산을 진행한다. 쉽게 말해 페이지를 전체 다시 렌더링 하는것고 다른 바 없다.
Reflow는 퍼포먼스 측면에서 매우 고비용을 발생시키는 프로세스로, 휴대전화와 같은 저성능 디바이스에서는 특히나 더욱 느린 DOM 스크립팅을 발생시키는 주범이다.
특정 엘리먼트에 스타일변화가 생길 경우 레이아웃 재정리를 위해 Reflow가 실행된다. 자식요소에 아무 변화가 없더라도 기계는 이를 미리 알고있지 못한다. 그렇기 때문에 작은 변화에도 자식개체 뿐 아니라, 페이지 전체에 Reflow가 실행된다.
클래스 변화로 인한 Reflow는 막을 수 없다. 그러나 이로 인한 reflow의 범위를 줄일 수 있다. DOM 트리에서 가급적 하위에 위치한 노드에 클래스 변화를 줄 경우, 이는 리플로우의 행동반경을 전체 페이지가 아닌 일부 노드들로 제한할 수 있다. 다시말해 페이지를 감싸는 클래스를 수정하는 행위는 되도록 피해야 한다.
OOCSS 방식을 통해 클래스변화가 발생한다면, 특정 엘리먼트에 대해 상당히 많은 클래스를 적용시켜서 reflow가 상당히 발생할 거 같지만, 실제로는 리플로우의 영향을 최소화함으로써 퍼포먼스적인 측면에서 큰 이득이 발생한다.
인라인 스타일을 적용할 경우 페이지에 있는 노드가 바껴 repaint 혹은 reflow가 발생 할 때, 이 스타일을 재해석하고, reflow 작업을 다시 발생시키게 된다. 즉 다시말해 수차례에 reflow 작업을 발생시키는 것이다. 그런데 인라인 스타일을 쓰지 않는다면 외부스타일 클래스의 조합으로 단 한번만 리플로우를 발생시킨다.
우리가 js 혹은 css를 가지고 애니메이션을 만들어 적용시키는 것은, 초당 수 많은 reflow를 발생시키게 하는 행위이다. 이러한 경우에 해당 개체의 position 속성을 fixed 또는 absoute로 주게 되면 다른 요소들의 레이아웃에 영향을 주지 않는다. 즉, repaint만 발생시키는 것이다.
가로로 100px 이동하는 애니메이션이 존재한다고 가정하자
이때 첫번 째 방법은 한 동작에 1px 씩 움직이는 것이고 두번 째 방법은 3px씩 움직이는 것이다. 물론 퀄리티로 따져보면 첫번 째 방법이 훨씬 부드럽게 보인다. 그러나 3px 씩 움직이는 것 보다 퍼포먼스가 떨어진다. 당연히 많은 reflow를 발생시키에 일어나는 일이다. 그렇기에 퀄리티와 퍼포먼스를 조정 해야한다.
아마 프론트엔드 개발자가 되기 위해 공부를 하고 있다면 한번 쯤은 들어봤을 말이다. 테이블 레이아웃을 피하라는 것, 테이블로 구성된 페이지 레이아웃은 점진적 페이지렌더링이 적용되지 않는다. 쉽게 말해 테이블 중 어느 한 곳이라도 바뀌면 테이블 전체에 reflow가 발생하는 거다.
var toChange = document.getElementById('elem');
toChange.style.background = '#333';
toChange.style.color = '#fff';
toChange.style.border = '1px solid #ccc';
다음 코드를 생각해 보자. 이 코드는 여러번 reflow와 repaint를 발생시킨다. 이를 다시 바꿔보면 다음과 같이 해결 할 수 있다.
/* CSS */
#elem { border:1px solid #000; color:#000; background:#ddd; }
.highlight { border-color:#00f; color:#fff; background:#333; }
/* js */
document.getElementById('elem').className = 'highlight';
relative는 자신의 위치 기준으로 움직이는 방식으로, 노드가 움직일 경우 모든 노드에 위치에 영향을 주게된다. 즉 relative는 수 많은 reflow를 발생 시킬 수도 있다는 것이다.