개인 노트 정리) 마크업16 - CSS 코드 최적화

2023. 9. 22. 22:02개인노트-인강

The RED 견고한 UI 설계를 위한 마크업
Part 3. Performance
01. CSS 코드 최적화

 

# CSS 코드 최적화

- CSS Optimization

## 최적화 기법의 2가지 포인트

1. Remove unused CSS (사용하지 않는 CSS 제거)

2. Eliminate render-blocking resources. (렌더 차단 리소스 제거)

 

- css는 기본적으로 렌더 차단 리소스라고 부른다.

- 웹 브라우저가 css파일을 만나서 다운로드하고, css파일을 해석하는 동안 웹 페이지 랜더링은 차단된다. 그래서 렌더 차단 리소스라고 부른다.

- css를 더 이상 렌더 차단 리소스가 되지 않도록 만들 수 있다.

## Remove unused CSS (사용하지 않는 CSS 제거)

- unused CSS는 페이지 렌더링을 차단하는 리소스. 이기 때문에 제거해야 한다.

- 브라우저가 스타일을 계산하는데 잠재적으로 더 많은 시간을 소비.

- 구글 라이트하우스는 2KB 이상 미사용 CSS가 포함된 파일을 검출하여 오류로 보고한다.

- 구글 라이트하우스는 개발자도구에 기본적으로 내장되어 있다.

### 구글 라이트 하우스로 사용하지 않는 css를 검출하는 방법

- 최근에는 사람들이 모바일로 접속하기 때문에 모바일로 선택한다.

- Generate report 버튼을 클릭한다.

- 좌측 상단 빨간색 삼각형은 오류에 해당하는 경고의 의미이다.

- url을 클릭하여 coverage 탭(Cmd + Shift + P / Ctrl+Shift+P)을 통해서 실제로 사용되지 않는 css 코드를 확인할 수 있다.

- Coverage 탭을 통해 unused CSS 확인

사용하지 않는 코드는 붉은색으로 표시되는 것을 확인

- 참고 : 크롬 라이트하우스는 fontface 규칙을 사용하지 않는 css로 보고하는 오류가 있다.

### 구글 라이트 하우스 Coverage탭을 통해서 더 구체적으로 사용하지 않는 css코드를 확인하는 방법

- Cmd + Shift + P / Ctrl+Shift+P 단축키를 입력한 뒤, coverage를 검색을 한다.

- Show Coverage 를 클릭하면 Coverage 탭이 등장한다.

- 새로고침 버튼을 클릭하면 다양한 파일 목록이 등장한다.

- CSS 파일만 sorting 할 수 있다. 파일을 클릭하면 안의 내용을 확인할 수 있다. 붉은색으로 표시된 부분이 사용하고 있지 않는 코드줄이다.

## Eliminate render-blocking resources. (렌더 차단 리소스 제거)

- Render blocking 왜 문제인가? 브라우저가 외부 리소스를 다운로드하고 파싱하는 동안 페이지 콘텐츠를 파싱하거나 렌더링하지 않기 때문에 페이지 표시 속도 저하의 원인.

- unused CSS가 Render blocking을 가중하는 요인이다.

### 해결방법

- lighthouse에서 Eliminate render-blocking resources 항목을 볼 수 있다. 여기 표시되는 목록 파일들이 렌더 차단을 하고 있는 파일들의 목록이다.

- 라이트 하우스가 렌더 블로킹 리소스를 표시하는 조건 : 

1. defer, async 속성이 없는 <head> 요소의 <script> 태그. -> 해결방법 : script 태그에 async나 defer태그를 사용해야 한다.

2. media 속성과 값이 없는 <link rel="stylesheet"> 태그. -> 해결방법 : stylesheet 태그에는 media 속성의 태그를 사용해야 한다.

### Render blocking <script>

- 결론적으로 defer태그를 더 추천한다.

- defer속성은 웹 페이지가 모두 그려지고, dom이 들어왔을 때, 그 때 script를 실행한다.

// 병렬 다운로드, 즉시 실행
<script async src="script.js"></script>

// 병렬 다운로드, 지연 실행
<script defer src="script.js"></script>

1. 필수 스크립트는 html에 <script> 형식으로 작성.
2. 기타 스크립트는 </body> 종료 태그 직전에 선언.
3. 마지막에 파싱해도 문제 없으면 defer 속성.
4. 돔이 파싱되는 동시에 가능한 빠른 시점에 실행 필요하면 async 속성.

### Render blocking <link rel="stylesheet">

- css의 렌더 블로킹 리소스 문제.

- media 속성이 없으면 css파일을 다운로드하고 해석하는 동안 웹브라우저 화면에는 아무것도 그려내지 않는다.

- media 속성은 하나의 조건문이라고 생각해도 된다.

<!-- Render blocking resource -->
<link href="style.css"    rel="stylesheet">
<link href="style.css"    rel="stylesheet" media="all">
<!-- Render blocking resource -->
<link href="portrait.css" rel="stylesheet" media="orientation:portrait">
<link href="print.css"    rel="stylesheet" media="print">

- media="orientation:portrait" // orientation:portrait 일 때만 이 stylesheet를 해석한다는 의미이다.

- media="print" // print 할 때만 해석한다는 의미이다.

- 특정 조건에서만 css를 해석하도록 조건문 처리를 했기 때문에 렌더 차단 리소스로 파악이 되지 않는다.

- 그래서 반응형 웹을 구현을 할 때에도 해상도 구간별로 별도의 css를 작성한 다음에 link 태그에 media 쿼리 구문을 적용하여 모바일에서는 모바일 코드만 데스크탑에서는 데스크탑 코드만 다운로드해서 렌더링 하도록 만들면 가장 좋은 결과를 얻을 수 있다.

### CSS 파일이 렌더링을 차단하는 과정

- css 로딩이 끝나기 전까지 fcp가 발생하지 않는다. 

- fcp는 first content paint의 약자이다. 첫번째 내용물이 화면에 그려지는 시점을 의미한다.

- 즉, css파일이 다운로드되고 해석되는 동안 아무것도 그려내지 않는다. 그래서 사용자들은 이 페이지가 느리다고 생각할 수 있다.

### 렌더를 차단하는 css파일. 렌더를 차단하는 blocking 이슈를 해결하는 방법

1. 반응형 웹인 경우 해상도 구간별로 css 파일을 분리하고 media 속성으로 분기.

<link href="*.css" rel="stylesheet" media="(max-width:639px)">
<link href="*.css" rel="stylesheet" media="(min-width:640px) and (max-width:960px)">
<link href="*.css" rel="stylesheet" media="(min-width:961px)">

- 첫번째 줄 부터 : 모바일에서 적용할 코드, 테블릿에서 적용할 코드, 데스크탑에서 적용할 코드 로 나누었다.

- 조건에 맞지 않는 css링크는 다운로드하지 않고, 해석하지 않기 때문에 더 빨리 렌더링할 수 있다.

2-1. 필수 스타일은 페이지 <head>에 <style> 태그 안에 css 코드를 작성하는 것. 이렇게하면 이 코드들은 렌더차단 리소스가 되지 않는다.

2-2. 지연하고 싶은 스타일은 <link rel="preload"> 속성으로 병렬 로딩 후 지연 적용. 예를 들면, javascript도 그렇지만 css도 뷰포트 화면 안에 있는 내용물을 그리는데 당장 필요한 css도 있고, 그렇지 않은 css도 있다. (예를 들어 사용자가 어떠한 행동을 해서 팝업을 띄우거나, 화면 스크롤 아래쪽에 있는 내용들은 당장 필요한 css는 아니다.) 이러한 css 들은 병렬로 loading 하고, 가능한 늦게 화면에 적용이 되도록 지연로딩을 할 수 있다. 이 때 사용하는 기법이 preload(병렬로딩기법) 이다.

- 정리하면. 필수 스타일은 임베딩, 지연 스타일은 병렬 로딩 후 지연 적용. 아래 예시 코드

<style>
/* 필수 스타일 여기 */
</style>
<link rel="preload" as="style" href="x.css" onload="this.onload=null;this.rel='stylesheet'">

- onload속성 해석 : javascript로 페이지 onload가 완료(로딩이 완료) 되면 rel 속성에 있는 'preload'라는 값을 'stylesheet'로 바꿔준다.

- 그래서 preload상태일때는 다운로드만 하고, 화면에 적용하지 않다가 'stylesheet' 라는 값이 들어가면 그 때, 화면에 stylesheet를 적용 한다.

- 이 코드를 사용하게되면 css를 병행로딩. 렌더 차단하지 않고 html 문서를 해석하면서 동시에 css도 다운로드 받는다. 그리고 나중에 css 파일 로딩이 끝났을 때, 그 때 웹 페이지에 적용한다.

- 그 결과 아래처럼 Render blocking CSS 이슈를 해결할 수 있다.

외부 스타일 파일이 렌더링(FCP)을 차단하지 않음.

## 정리

1. 웹 브라우저는 외부 JS, CSS 파일을 로딩 하고 파싱 하는 동안 렌더링 차단 상태를 유지한다.
2. 사용하지 않는 JS, CSS 제거.
3. 필수 코드는 페이지에 <style>...</style>, <script>...</script> 작성하기.
4. 필수 아닌 JS는 </body> 종료 직전 위치를 고려. defer, async 속성을 사용.
5. 필수 아닌 CSS는 병렬 로딩(preload)하고 지연 적용(onload)하기.