HTML, CSS 코드 최적화하기
HTML, CSS 코드를 최적화함으로써 렌더링 성능을 향상시킬 수 있다.
1. HTML 최적화 방법
(1) DOM 가볍게 만들기
DOM트리가 깊고 자식 요소가 많을수록 DOM 트리의 복잡도는 커진다. 복잡도가 클수록 DOM 트리가 변경되었을 때 개선해야 하는 것도 많아진다. HTML 요소에서 불필요하게 깊이를 증가시키는 요소가 있으면 삭제한다.
// 수정 전
<div>
<ol>
<li> 1st </li>
<li> 2nd </li>
<li> 3rd </li>
</ol>
</div>
// 수정 후 : 불필요한 div 요소 제거
<ol>
<li> 1st </li>
<li> 2nd </li>
<li> 3rd </li>
</ol>
(2) 인라인 스타일 사용하지 않기
CSS 파일을 따로 작성하면 단 한 번의 리플로우만 발생하는데, 인라인 스타일은 리플로우를 계속해서 발생시켜 파일 크기를 증가시킨다. 애초에 인라인 스타일은 웹 표준에 맞지 않으므로 지양해야한다. 인라인 스타일은 개별 요소에 스타일 속성을 작성해주는 것이기 때문에, 클로스로 묶어서 한 번에 작성해도 될 스타일 속성을 중복으로 작성하는 경우가 생긴다. 불필요한 코드 중복은 가독성을 떨어뜨리고 파일 크기를 증가시킨다.
//수정 전
<div style="margin: 10px;"> 마진 10px 적용 </div>
<div style="margin: 10px;"> 동일하게 마진 10px 적용 </div>
//수정 후 : class와 CSS로 대체
<div class="margin10"> 마진 10px 적용 </div>
<div class="margin10"> 동일하게 마진 10px 적용 </div>
.margin10 {
margin: 10px;
}
2. CSS 최적화 방법
(1) 사용하지 않는 CSS 제거하기
CSS 파일의 모든 코드의 분석이 끝난 후에 CSSOM 트리가 생성된다. 불필요한 CSS 코드가 있다면 CSSOM 트리의 완성이 늦어지기 때문에 사용하지 않는 CSS 코드는 제거하는 것이 좋다.
(2) 간결한 셀렉터 사용하기
셀렉터가 복잡할수록 스타일 계산과 레이아웃에 시간을 더 많이 소모하게 된다. 따라서 최대한 간결한 CSS 셀렉터를 사용하는 것이 좋다.
// 복잡한 CSS 셀렉터 예시
.cart_page .cart_item #firstItem { ... }
// 필요한 경우에는 어쩔 수 없지만, 가능한 한 간결하게 작성해줍니다.
.cart_item { ... }
3. 리소스 로딩 최적화하기
HTML 파일에서 JavaScript 파일을 불러올 땐 <script> 요소를, CSS 파일을 불러올 땐 <link> 요소를 사용하게 됩니다. 이때 파일을 불러오는 위치가 어디인가에 따라서 렌더링 완료 시점이 달라질 수 있다.
1. CSS 파일 불러오기
CSSOM 트리를 가능한 빠르게 구성할 수 있도록 HTML 문서 최상단에 배치하는 것이 좋다.
// CSS 파일은 HTML 파일 상단의 head 요소 안에서 불러오는 것이 좋습니다.
<head>
<link href="style.css" rel="stylesheet" />
</head>
2. JavaScript 파일 불러오기
<script> 요소를 HTML 코드 중간에 넣는다면, 해당 요소 이후에 생성될 DOM을 수정하는 코드가 있는 경우에는 화면이 의도한 대로 표시되지 않게 됩니다.DOM 트리 생성이 중단된 시간만큼 렌더링 완료 시간은 늦춰지게 됩니다. 이러한 이유로 JavaScript 파일은 DOM 트리 생성이 완료되는 시점인 HTML 문서 최하단에 배치하는 것이 좋습니다.
<body>
<div>...</div>
...
// JavsScript 파일은 body 요소가 닫히기 직전에 작성하는 것이 가장 좋습니다.
<script src="script.js" type="text/javascript"></script>
</body>
4. 브라우저 이미지 최적화하기
이미지의 용량을 줄이거나 요청의 수를 줄이는 것을 우선적으로 고려할 시, 사용자 경험을 빠르게 개선할 수 있다.
1) 이미지 스프라이트
웹 페이지를 로드하는 데 필요한 서버 요청 수를 줄이기 위해 이미지 스프라이트 기법을 사용할 수 있다.
이미지 스프라이트 기법은 여러 개의 이미지를 모아 하나의 스프라이트 이미지로 만들고 CSS의 background-position 속성을 사용해 이미지의 일정 부분만 클래스 등으로 구분하여 사용하는 방법이다.
하나의 이미지를 배경 이미지로 사용하되, 표시하고 싶은 부분에 맞춰 width, height, background-position 속성을 주어 아이콘을 만든다. 해당 기법을 이용하면 한번의 이미지 요청으로 대부분의 개별 이미지를 사용할 수 있기 때문에 네트워크 로딩 시간을 줄일 수 있다. 또한, 많은 이미지 파일을 개별로 관리할 필요없이 특정 스프라이트 이미지 파일만을 관리하면 되므로 관리가 용이하다는 장점이 있다.
2) 아이콘 폰트 사용하기
아이콘 폰트를 사용하여 용량을 줄일 수 있다.
(1) CDN으로 사용하기
Font Awesome에 가입하면 키트를 발급해주는데, 이 키트를 HTML 파일에서 <head> 요소에 넣어주기만 하면 CDN으로 Font Awesome을 사용할 준비가 완료된다.
Font Awesome 사이트에서 사용하고 싶은 아이콘을 찾아서 사용할 환경(HTML, React, Vue)에 맞는 코드를 복사하고 붙여넣기만 하면 사용할 수 있다.
(2) Font Awesome 모듈 설치하기
Font Awesome을 다른 라이브러리처럼 설치
// 핵심 패키지 설치
npm i --save @fortawesome/fontawesome-svg-core
// 아이콘 패키지 설치 (해당 코드는 무료 아이콘들입니다. 유료 아이콘을 사용할 경우 추가로 설치가 필요합니다.)
npm i --save @fortawesome/free-solid-svg-icons
npm i --save @fortawesome/free-regular-svg-icons
npm i --save @fortawesome/free-brands-svg-icons
// Font Awesome React 구성 요소 설치
npm i --save @fortawesome/react-fontawesome@latest
https://fontawesome.com/v5/docs/web/use-with/react#features
React
Font Awesome 6 brings loads of new icons and features to the most popular icon set in the world.
fontawesome.com
3. WebP 또는 AVIF 이미지 포맷 사용하기
새롭게 등장한 이미지 포맷인 WebP 또는 AVIF를 사용하여 용량을 더욱 감소시킬 수 있다. 다만 모든 브라우저에서 호환되지 않는다는 단점이 있다.
HTML의 <picture> 태그를 이용하면 각 브라우저의 호환에 맞도록 분기를 대체할 수 있다.
<picture>: img 요소의 다중 이미지 리소스(multiple image resources)를 위한 컨테이너를 정의할 때 사용한다.
다음과 같이 HTML 태그를 작성할 시, 만약 접속한 브라우저에서 <source>태그 내의 srcset에 정의한 WebP 포맷을 지원하지 않는다면 해당 <source> 태그는 무시됨. 속성을 이용하여 각 브라우저에 따라 이미지 포맷을 최적화할 수 있다.
<picture>
<source srcset="logo.webp" type="image/webp">
<img src="logo.png" alt="logo">
</picture>
5. 캐시 사용하기
캐시는 다운로드 받은 데이터나 값을 미리 복사해 놓는 임시 장소이다. 데이터에 접근하는 시간이 오래 걸리는 경우나 값을 다시 계산하는 시간을 절약하고 싶은 경우에 사용하며, 네트워크 리소스는 물론 로딩 시간을 줄일 수 있다.
- If-Modified-Since : 캐시된 리소스의 Last-Modified 값 이후에 서버 리소스가 수정되었는지 확인하고, 수정되지 않았다면 캐시된 리소스를 사용한다.
- If-None-Match : 캐시된 리소스의 ETag 값과 현재 서버 리소스의 ETag 값이 같은지 확인하고, 같으면 캐시된 리소스를 사용한다.
둘 중 하나만 사용했다가 매칭되는 응답 헤더가 없는 경우에는 재사용할 수 있는 경우에도 리소스를 다시 받아와야 하는 경우가 생길 수 있기 때문에 보통 두 종류의 헤더를 동시에 사용한다.
6. CDN 사용하기
CDN은 콘텐츠를 좀 더 빠르고 효율적으로 제공하기 위해 설계되었다. 네트워크 지연(latency)은 유저와 호스팅 서버간의 물리적 거리의 한계가 존재하기 때문에 발생할 수 밖에 없다. 유저와 서버의 거리가 멀다면 지연(latency) 또한 늘어난다. CDN은 이를 해결하고자 세계 곳곳에 분포한 분산된 서버에 콘텐츠를 저장한다.CDN은 유저가 가까운 곳에 위치한 데이터 센터(서버)의 데이터를 가져온다. 그러므로 데이터가 전달되기 위해 거쳐야하는 서버의 갯수가 크게 줄기 때문에 로딩 속도가 빨라진다.