HTML 페이지 로딩 최적화 기법

적절하게 최적화된 웹페이지는 방문자에게 빠른 응답성과 인터넷 연결에 대한 부하 절감 같은 효익을 제공한다.

이는 트래픽이 많거나 급증하는 사이트일수록 더욱 중요하지만 통신 인프라가 좋은 사용자에게도 극적인 개선 효과를 가져올 수 있다.

⭐️⭐️⭐️ 페이지 경량화 ⭐️⭐️⭐️

페이지 용량은 HTML 로딩 성능에 가장 큰 영향을 미친다.

구조를 변경하지 않고 페이지 용량을 줄이기 위해 인라인 스크립트와 스타일 시트를 별도 파일로 분리하는 방법이 있다.

만약 가능한 경우, 마크업 구조를 최적화하여 코드량을 줄이는 것도 방법이 될 수 있다.

마지막으로, 불필요한 공백을 제거하는 방법으로 페이지 용량을 줄일 수 있다.

HTTP 요청 수 최적화

웹페이지에서 참조하는 파일 개수는 클라이언트의 요청과 서버의 응답에 걸리는 시간에 영향을 준다. 따라서, 페이지에서 참조하는 파일 개수를 줄이면 페이지 로딩 속도를 개선할 수 있다.

브라우저 캐시 설정에 따라 파일 다운로드 요청을 보낼 때, If-Modified-Since 헤더를 통해 파일의 수정 여부를 확인하는 경우가 있다. 이런 경우, 파일의 수가 많을 수록 서버에서 확인에 걸리는 시간이 오래 걸려 초기 페이지 표시 속도가 느려질 수 있다.

CSS에서 이미지를 많이 사용하는 경우, image sprite 기법을 사용하면 단일 이미지를 캐싱하여 HTTP 요청 수를 줄일 수 있다.

CDN 사용하기

서버와 클라이언트의 물리적인 거리는 통신 시간에 영향을 준다. CDN(Content Delivery Network)은 지연시간을 단축하기 위해 지리적으로 분산된 서버 네트워크다. 웹사이트를 캐시해 두고 사용자에게 가장 가까운 서버에서 콘텐츠를 제공하는 방식으로 지연시간을 줄인다.

도메인 조회 횟수 줄이기

다운로드할 파일의 도메인이 다양할수록 DNS 조회 횟수가 늘어나서 초기 페이지 표시가 느려질 수 있다.

이런 문제가 발생하는 경우는 드물어서 실용적이지 않지만, 근검절약하는 느낌으로 페이지에 필요한 최소 도메인만 사용하는 것이 좋다.

재사용하는 콘텐츠 캐싱하기

캐싱은 언제나 적절한 만료시간을 부여하는 것이 중요하다.

보통 Last-Modified 헤더를 기준으로 사용자 에이전트가 캐싱을 처리한다. 따라서 대부분의 웹서버는 정적 파일에(.html, .css, etc.) Last-Modified 헤더를 자동으로 부여한다.

그러나 동적페이지(.php, .aspx)는 그럴 수 없기 때문에 Last-Modified 헤더를 보내지 않는다.

SPA 경우, 번들 파일 이름에 해시값을 넣어주는 방식으로 캐싱 만료처리를 하는 방법을 사용한다.

페이지 요소 우선 순위 정하기

페이지 콘텐츠를 먼저 다운로드하고 CSS와 JS는 그다음 다운로드하는 방식으로 페이지 로딩 속도를 개선할 수 있다.

일반적으로 페이지 콘텐츠는 텍스트이므로, 전송할 때 텍스트 압축을 사용하여 용량을 줄이기 때문에 사용자에게 더 빠른 응답성을 제공할 수 있다.

모든 동적인 기능들은 페이지 로딩이 완료된 후에 활성화되도록 구현해야 한다.

인라인 스크립트 줄이기

인라인 스크립트가 있는 경우, 브라우저의 구문 분석기가 스크립트에 의한 페이지 구조 변경을 가정하기 때문에 시간이 더 오래 걸릴 수 있다.

일반적으로 인라인 스크립트와, DOM 갱신을 유발하는 document.write() 사용을 줄이면 전반적인 페이지 로딩 속도를 개선할 수 있다.

고전적인 방식인 document.write() 기능을 사용하여 페이지 콘텐츠를 조작하는 코드는 AJAX 방식으로 변경해준다.

최신 CSS 및 유효한 마크업 사용하기

마크업 코드량을 줄이고 이미지를 활용한 레이아웃 또는 스타일이 적용된 텍스트를 표현하기 위한 이미지 사용을 대체할 수 있기 때문에 최신 스펙의 CSS 사용을 권장한다.

유효성 검사를 통과한 마크업을 사용하면 브라우저 구문 분석기가 오류 수정을 수행하는 과정이 없기 때문에 페이지 로딩 속도를 개선할 수 있다.

HTML Tidy 도구를 통해 공백 제거나 유효성 검사 같은 작업을 자동화할 수 있다.

SVG 에셋 minify & 압축하기

보통 드로잉 애플리케이션을 통해 생성된 SVG에는 불필요한 메타데이터가 포함된 경우가 많다. 서버를 구성하고 SVG 에셋에 gzip 압축을 적용하는 것을 권장한다.

이미지 minify & 압축하기

대용량 이미지는 페이지 초기 표시 속도를 느리게한다. 적절한 압축 방식으로 크기를 줄이는 것을 권장한다.

이미지나 표의 크기 지정하기

이미지 크기가 고정된 경우, 브라우저가 콘텐츠를 리플로우 과정을 생략하고 웹 페이지를 표시할 수 있다. 이렇게 하면 페이지 표시 속도가 빨라지며 페이지 로딩이 완료되었을 때 페이지 레이아웃이 변경되는 것을 방지할 수 있다. 따라서 가능하면 이미지에 높이와 너비를 지정하는 것을 권장한다.

테이블은 CSS 속성과 <col>, <colgroup> 요소를 사용하여 크기를 지정할 수 있다.

table-layout: fixed;

이미지에 lazy loading 적용하기

기본적으로 HTML에서 파악된 이미지는 documentload 이벤트를 보내기 전에 모두 렌더링된다.

반면에 뷰포트에 들어오는 시점에 이미지를 로딩하는 방식을 택하면 페이지 초기 표시 속도를 개선할 수 있다.

<img src="./images/foo.jpg" loading="lazy" alt="logo" />

load 이벤트 발생 시점에 지연 로딩 이미지를 사용할 수 없을 수도 있기 때문에 해당 이미지의 complete 속성을 확인하는 것이 좋다.

요령있게 user-agent 요구사항 설정하기

콘텐츠가 모든 웹브라우저에서 픽셀 단위로 완벽하게 표시되도록 요구하는 것은 소모적이다. 특히 구형 브라우저 지원의 경우 더욱 그렇다.

최신 브라우저 지원 범위를 기반으로 요구사항을 적용하는게 이상적이지만, 그럴 수 없는 경우도 있다.

가능하면 async/ defer 사용하기

<script> 요소가 여러개인 경우, async & defer 속성 모두 호환되도록 설정하고 가능하면 async를 사용하는 것을 권장한다. 그러나 실행 순서가 보장되어야 하는 경우 defer를 적절하게 사용해야 한다.

이를 통해 JavaScript가 로드되는 동안 페이지 구문 분석이 블록되는 것을 방지할 수 있다.

페이지 구조 예시

<html>
  <head>
    <link> 
      <!-- 페이지 외양을 위한 CSS 파일은 성능을 위해 수를 최소화하여 유지보수가 편하도록 별도 파일로 분리 -->
    <script>
      /* 페이지 로딩 중에 필요한 기능을 위한 자바스크립트 파일
       * 따라서 로딩 후에 필요한 상호작용 관련 자바스크립트 파일은
       * 성능을 위해 파일수를 최소화하고
       * 유지보수가 편하도록 별도 파일로 분리
       */
    </script>
  </head>
  <body>
    <!-- 페이지 전체 다운로드를 기다리지 않고 사용자에게 표시할 수 있는 페이지 콘텐츠의 조각들(<header>, <main>, <table> 등) -->
    <script>
      /* 상호작용을 수행하는데 사용하는 스크립트 파일
       * 어차피 페이지 로딩이 완료된 다음에야 의미있기 때문에
       * 페이지 콘텐츠 이후에 호출하도록 처리
       * 마찬가지로 파일수를 최소화하고 별도 파일로 분리
       */
    </script>

Last updated