🎨브라우저 로딩 과정🎨
- 파싱
- 스타일
- 레이아웃
- 페인트
- 합성 & 렌더
📃웹 페이지 로딩 최적화
브라우저 로딩 과정에서 파싱 중 블록 리소스가 발생할 수 있으며, CSS와 자바스크립트가 이에 해당한다. 최적화의 첫번째 단계는 이 블록 리소스를 최적화하는 것이다.
CSS 최적화
- CSSOM 트리는 CSS를 모두 해석해야 구성할 수 있다. 렌더링이 차단되지 않도록 CSS는 항상 HTML 문서 최상단(<head> 아래)에 배치한다.
<head> <link href="style.css" rel="stylesheet" /> </head>
- 특정 조건에서만 필요한 CSS가 있을 때 미디어 쿼리를 사용한다.
<link href="style.css" rel="stylesheet" /> <link href="print.css" rel="stylesheet" media="print" /> <link href="portrait.css" rel="stylesheet" media="orientation:portrait" />
- 외부 스타일시트를 가져올 때 사용하는 @import 사용은 피한다.
- 상황에 따라 내부 스타일시트를 사용한다.
자바스크립트 최적화
자바스크립트는 DOM트리와 CSSOM트리를 동적으로 변경할 수 있기 때문에 HTML 파싱을 차단하는 블록 리소스이다. <script> 태그를 만나면 스크립트가 실행되며 그 이전까지 생성된 DOM에만 접근할 수 있다.
- 외부 자바스크립트의 경우에는 모든 스크립트가 다운&실행될 때까지 DOM 트리 생성이 중단된다.
- HTML 문서 최하단(</body> 직전)에 배치한다.
<body> <div>...</div> <script src="app.js" type="text/javascript"></script> </body>
- <head>아래에 있거나 HTML 내부에 <script>태그가 포함되어 있을 때도 HTML파싱을 멈추지 않게 할 수 있다. <script>태그에 defer나 async속성을 명시하면 스크립트가 DOM트리와 CSSOM트리를 변경하지 않겠다는 의미이기 때문에 브라우저가 파싱을 멈추지 않는다. (! 브라우저 지원범위가 한정적이므로 유의한다)
<html> <head> <script async src="https://google.com/analatics.js" type="text/javascript"></script> </head> <body> <div>...</div> <div>...</div> </body> </html>
- 👉 <head/> 에서 CSS 파일 로드
- 👉 <body/> 직전에 자바스크립트 파일 로드
- 👉 내부 스타일시트 사용
리소스 요청 수 줄이기
CSS 최적화
- 이미지 스프라이트
- CSS, 자바스크립트 번들하기
- 내부 스타일시트 사용하기(리소스 캐시를 사용할 수 없기 때문에 필요한 경우에만 사용한다.)
- 작은 이미지를 HTML, CSS로 대체(Base64로 변환된 URI로 대체. 이 경우도 캐시 문제가 있으므로 필요한 경우에만 사용한다.)
자바스크립트 최적화
- 중복 코드 제거하기(자주 사용되는 코드는 utils.js 파일로 정리해 사용한다.)
// **중복 코드 사용 (최적화 전)** // foo.js function filter() { ... } function map() { ... } filter(); map(); // bar.js function filter() { ... } function find() { ... } filter(); find();
// **중복 코드 제거 (최적화 후)** // utils.js export function find() { ... } export function filter() { ... } export function map() { ... } // foo.js import {filter, map} from 'utils.js' filter(); map(); // bar.js import {filter, find} from 'utils.js' filter(); find();
- 만능 유틸 사용 주의하기
HTML 최적화
- 태그의 중첩을 최소화하여 단순하게 구성한다.
- 공백, 주석 등을 제거하여 사용한다.
- DOM 트리의 노드 수는 전체 1500개 미만, 최대 깊이는 32개, 자식 노드를 가진 부모 노드는 60개 미만
- 간결한 CSS 선택자 사용(ID대신 클래스 선택자를 사용한다.)
- 압축(Minify)하여 사용하기
📃웹 페이지 랜더링 최적화
웹 페이지를 렌더링하기 위해서는 DOM과 CSS가 필요하다. 그러나 다양한 기능과 효과를 구현하기 위해 자바스크립트를 많이 사용하기 때문에 자바스크립트가 렌더링 성능에 어떤 영향을 주는지 잘 알아야 한다.
레이아웃 최적화
렌더링 과정에서 레이아웃은 DOM 요소들이 화면에 어느 위치에 어떤 크기로 배치될지를 결정하게 되는 계산 과정이다. 아래 그림같이 변경된 스타일을 반영하고 다시 레이아웃을 해야만 렌더링 할 수 있다.
(이미지 참조 : 렌더링 성능)
자바스크립트 실행 최적화
DOM의 속성을 변경하면 화면 업데이트를 위해 레이아웃이 일어날 수 있다. 특정 속성을 읽을 때 최신 값을 계산하기 위해 레이아웃이 동기적으로 발생한다. 이를 강제 동기 레이아웃이라고 한다. 강제 동기 레이아웃은 자바스크립트 실행 시간을 늘어나게 하므로 신경 써야 한다.
- 강제 동기 레이아웃 피하기
- 레이아웃 스래싱(thrashing) 피하기
function resizeAllParagraphs() { const box = document.getElementById('box'); const paragraphs = document.querySelectorAll('.paragraph'); for (let i = 0; i < paragraphs.length; i += 1) { paragraphs[i].style.width = box.offsetWidth + 'px'; } } // 레이아웃 스래싱을 개선한 코드 function resizeAllParagraphs() { const box = document.getElementById('box'); const paragraphs = document.querySelectorAll('.paragraph'); const width = box.offsetWidth; for (let i = 0; i < paragraphs.length; i += 1) { paragraphs[i].style.width = width + 'px'; } } 참고 : [레이아웃에 영향을 미치는 요소](https://gist.github.com/paulirish/5d52fb081b3570c81e3a)
가능한 한 하위 노드의 DOM을 조작하고 스타일을 변경
DOM을 변경하면 스타일 계산, 페인트 과정이 모두 필요하며, 조작이나 스타일 변경을 하는 DOM이 상위에 있을수록 한 프레임에 드는 시간이 길어진다.
- 👉 DOM 트리 상위 노드의 스타일을 변경하면 하위 노드에 모두 영향을 미친다.
- 👉 변경 범위를 최소화할수록 레이아웃 범위가 줄어든다.
영향받는 엘리먼트 제한
DOM과 스타일을 변경하면 레이아웃 과정에서 주변의 엘리먼트도 영향을 받아 다시 레이아웃을 해야 하는 경우가 있다.
- 👉 부모-자식 관계 : 부모 엘리먼트가 변경되면 자식 엘리먼트도 같이 변경된다. 부모 엘리먼트의 높이를 고정하면 자식 엘리먼트는 영향을 받지 않게 된다.
- 👉 같은 위치 : 여러 개의 엘리먼트가 인라인으로 있을 때 첫 번째 엘리먼트의 width 값 변경으로 나머지에 영향을 미치므로 유의한다.
숨겨진 엘리먼트 수정
display: none 은 DOM 조작과 스타일을 변경하더라도 레이아웃과 페인트가 발생하지 않는다. 많은 수의 엘리먼트를 변경해야 할 경우 숨겨진 상태에서 엘리먼트를 변경하고 다시 보이도록 하여 레이아웃 발생을 최대한 줄인다. (! visibility: hidden 은 보이지않아 리페인트는 발생하지 않지만, 공간을 차지하기 때문에 레이아웃은 발생한다.)
- 👉 display: none 으로 숨겨진 엘리먼트를 변경할 경우에는 레이아웃, 리페인트가 발생하지 않아 성능에 유리하다.
CSS 규칙수 최소화
- 👉 사용하는 규칙이 적을수록 계산이 빠르므로 최소화한다.
- 👉 복잡한 선택자는 스타일 계산에 많은 시간이 걸리므로 사용을 피한다.
DOM 깊이 최소화
- 👉 DOM이 작고 깊이가 얕을수록 계산이 빠르다.
- 👉 불필요한 래퍼 엘리먼트는 제거한다.
애니메이션 최적화
- 👉 한 프레임 처리가 16ms(60fps) 내로 완료되어야 렌더링 시 끊기는 현상 없이 자연스러운 렌더링은 만들어낼 수 있다.
- 👉 자바스크립트 API를 사용하는 것보다 CSS 사용을 권장한다.
requestAnimationFrame() 사용
브라우저의 프레임 속도(보통 60fps)에 맞추어 애니메이션을 실행할 수 있도록 해준다. 특히 setInterval, setTimeout 과 달리 프레임을 시작할 때 호출되기 때문에 일정한 간격으로 애니메이션을 수행할 수 있는 장점이 있다. 또한 현재 페이지가 보이지 않을 때는 콜백함수가 호출되지 않기 때문에 불필요한 동작을 하지 않는다.
function animate() { // 애니메이션 처리 프레임 코드 requestAnimationFrame(animate); } requestAnimationFrame(animate);
CSS 애니메이션 사용
- 👉 position: absolute 처리 : 애니메이션 영역이 주변 영역에 영향을 주지 않도록 주의해야 한다. absolute 나 fixed 로 설정하면 주변 레이아웃에 영향을 주지 않는다.
- 👉transform 사용 : 레이어로 분리되기 때문에 영향받는 엘리먼트가 제한되어 레이아웃과 페인트를 줄일 수 있다. 그리고 합성만 발생시키기 때문에 애니메이션 사용 시 렌더링 속도가 향상할 수 있다.
/* bad */ @keyframes move { 50% { top: 100px; left: 100px; } } /* good */ @keyframes move { 50% { transform: translate(100px, 100px); } }
참고 TOAST UI
'IT > CS' 카테고리의 다른 글
[CS] 인터넷은 어떻게 작동하는가 (0) | 2023.05.24 |
---|---|
[CS] 브라우저 렌더링 과정 :: CSS 최적화 (0) | 2021.06.07 |