웹 사이트를 개발할 때 스타일을 넣기 위해 css를 활용합니다.
css 를 활용할때 브라우저 성능에 많은 영향을 미칠수 있기에 적절히 활용해야합니다.
오늘 글에서는 브라우저 랜더링 과정을 다시 한번 생각해보고, 구글링을 통해서 브라우저 랜더링 퍼포먼스에 영향을 줄 수 있는 css 들과 css 를 최적화 해서 사용할 수 있는 방법이 어떤것이 있는지 체크해보겠습니다.
먼저 내려받은 html 파일과 css 파일을 파싱합니다.
랜더링 엔진이 html 파일을 한줄 한줄 읽어가며 브라우저가 읽을 수 있는 DOM 트리를 구성합니다. html 파일을 읽어가다 <style>
혹은 <link>
태그를 만나게 된다면 서버에 css 파일을 요청하고, css 파일을 파싱하여 CSSOM 트리를 만듭니다.
DOM 트리와 CSSOM 트리가 완성되었다면 두 트리를 결합해 랜더링 트리를 만듭니다. 랜더링 트리를 만들때 실제로 브라우저에 표현되지 않을 태그와 스타일은 랜더링 트리에서 제외됩니다. (예를 들면 display: none
, visibility: hidden
)
랜더링 트리가 완성되었다면 실제 브라우저에 표현될 노드들의 위치와 크기를 계산합니다. 이 과정을 Layout 라고 합니다.
Layout 과정이 끝나고 브라우저에 실제로 표현하는 단계입니다. 계산된 노드들을 픽셀로 변환하고 레이어를 만듭니다. 이 과정은 Paint 라고 합니다.
Layout 과 Paint 과정이 끝났다면 레이어를 합쳐서 화면에 표현합니다. 이 과정을 Composition 이라고 합니다.
이후, 브라우저에서 리랜더링이 발생한다면 아래와 같은 과정을 거칩니다.
생성된 DOM 트리에서 노드의 위치나 크기가 변경되었다면 Reflow 과정을 거칩니다. 영향을 받은 노드와 그 노드로 인해 영향을 받게되는 모든 노드의 위치나 크기를 다시 레이어 하는 과정입니다. 모든 노드의 위치, 크기를 다시 계산해 랜더링 트리에 반영합니다.
Reflow 과정을 거친 이후, 다시 Paint 하는 과정인 Repaint 과정을 거칩니다.
브라우저 랜더링 과정을 살펴봤을때 브라우저의 성능 저하를 피하기 위한 방법은 Reflow 과정을 피하는 방법이라고 생각을 하게 됩니다. Reflow 는 영향을 받은 노드의 레이어를 다시 계산해 랜더링 트리에 반영하기에 잘 관리하지 않는다면 메모리 누수가 발생하여 성능에 막대한 영향을 끼칩니다. 먼저 Reflow 를 발생시키는 css 속성에 대해서 살펴봅시다.
width (max, min), height (max, min), margin, padding, display, border-width, border, top, position, font 관련 속성 (font-size, font-family ...), float, clear, text-align, overflow (x, y), top, bottom, left, right, vertical-align, white-space
위 태그들을 살펴보면 대부분 위치와 크기를 잡을때 사용하는 태그라는 사실을 알 수 있습니다.
사실은 조금 충격적이었던게 대부분 흔히 사용하는 태그이고, 아무런 생각 없이 사용하던 css 들이 잘못 사용하면 퍼포먼스에 심각한 영향을 미칠수 있겠구나 하는 생각이 들었습니다.
최근에는 가급적이면 중복된 css 를 사용하지 않도록 노력하고, 적용된 클래스를 건들여서 css 를 적용하려고 노력했지만 위와 같이 덮어 씌운 css 들도 생각보다 많이 있었습니다.
color, border-style, visibility, background (image, position ...), text-decoration, outline (color, style, width ...), border-radius, box-shadow
브라우저 퍼포먼스를 최적화 하기 위해 가급적이면 Reflow 단계를 건너뛰고 Repaint 단계만 거칠 수 있도록 합니다.
부득이하게 Reflow 단계를 거쳐야 한다면 성능 저하를 최소화 하는 방안으로 단계를 거칠수 있겠습니다.
Reflow 과정은 영향을 받은 모든 노드의 위치, 크기를 다시 계산해 레이어에 반영합니다. 가장 하단에 위치한 노드의 클래스를 통해 스타일이 변경되는 경우엔 영향을 받는 노드들이 적어져 성능 저하를 최소화 할 수 있습니다.
스타일 속성을 통해 스타일을 설정하는 경우 리플로우가 발생합니다. 가독성 저하 및 브라우저 성능 저하를 방지하기 위해 인라인 스타일은 지양합니다.
position: absolute
, position: fixed
를 사용한다. 변경되는 노드의 포지션을 absolute 혹은 fixed 를 적용함으로써 다른 노드에 미치는 영향을 최소화 할 수 있습니다. 이때 top, bottom 등 의 속성을 이용해 애니메이션을 적용하는 것이 아닌
translateY
와 같은 속성을 이용해 애니메이션을 적용합니다.
<table>
을 사용하지 않는다.요즘에는 레이아웃을 만들때
<div>
태그를 활용하지만 이전에<table>
태그를 활용할 때가 있었습니다.<table>
태그는 점진적으로 랜더링 되지 않고, 모든 노드가 계산된 이후 화면에 랜더링이 되고, 하나의 노드에 변경이 있더라도 (예를 들면 하나의<td>
) 모든 노드에 Reflow 가 발생합니다.
display: none
보다는 visibility:hidden
display: none
속성은 Reflow 와 Repaint 과정을 모두 발생시킵니다. 반면에visibility: hidden
속성은 Repaint 만 발생시키기에 브라우저 성능 최적화의 방안으로 활용할 수 있습니다
프론트 작업을 할때 css 는 Javascript 보다 등한시 하는 경우가 많았습니다. 브라우저 성능 최적화를 고려하면서도 Script 최적화만 고려했지 css 는 생각하지 않았던 경우가 많았는데, 이번 조사를 통해서 css 최적화를 고려하여 작업을 해야겠다는 생각이 들었습니다. 케이스 바이 케이스지만 위에 적은 상황들을 가급적이면 지키고자 노력하고, 더 좋은 방안이 있나 서치해봐야 겠다는 생각을 해봅니다.