CSS와 JavaScript 로딩 최적화 – render-blocking 리소스 줄이는 방법

1. 사이트가 느린데 이미지 문제가 아니라면?

이미지를 모두 최적화했는데도 PageSpeed Insights 점수가 낮다면 CSS와 JavaScript 파일이 문제일 수 있습니다.

“렌더링 차단 리소스 제거”라는 권고 사항이 PageSpeed 결과에서 자주 등장하는 이유가 여기에 있습니다. CSS와 JS 파일이 페이지 렌더링 자체를 막고 있는 경우입니다.

2. render-blocking 리소스란 무엇인가?

render-blocking 리소스는 브라우저가 페이지를 화면에 그리는 것을 차단하는 CSS나 JavaScript 파일입니다.

브라우저가 HTML을 파싱하다가 <link rel="stylesheet"> 태그를 만나면 CSS 파일 로딩이 완료될 때까지 렌더링을 중단합니다. CSS 없이 페이지를 그리면 레이아웃이 깨진 화면이 잠깐 보일 수 있기 때문입니다.

<script> 태그를 만나면 JS 파일 다운로드와 실행이 완료될 때까지 HTML 파싱 자체를 중단합니다. JS가 DOM을 변경할 수 있기 때문에 먼저 실행해야 합니다.

결과적으로 <head>에 많은 CSS와 JS 파일이 있으면 첫 화면이 표시되는 시간이 늦어집니다.

3. JavaScript 최적화 – defer와 async의 차이

<script> 태그에 defer 또는 async 속성을 추가하면 HTML 파싱을 차단하지 않고 JS를 로드할 수 있습니다.

일반 script (차단 방식)

HTML 파싱 중 스크립트 태그를 만나면 파싱을 멈추고 JS를 다운로드·실행한 뒤 파싱을 재개합니다.

<script src="app.js"></script>

async 방식

HTML 파싱과 JS 다운로드가 병렬로 진행됩니다. JS 다운로드가 완료되면 즉시 실행됩니다(이 순간 파싱은 잠깐 멈춤). 실행 순서가 보장되지 않아 순서가 중요하지 않은 독립적인 스크립트에 적합합니다.

<script src="analytics.js" async></script>

defer 방식

HTML 파싱과 JS 다운로드가 병렬로 진행됩니다. HTML 파싱이 완전히 완료된 후에 JS를 실행합니다. 여러 defer 스크립트는 선언 순서대로 실행됩니다. 대부분의 일반 스크립트에 적합합니다.

<script src="app.js" defer></script>

실무 권장 사항입니다. 일반 앱 코드는 defer를 사용하고, 구글 애널리틱스나 광고 스크립트처럼 독립적인 스크립트는 async를 사용합니다.

4. CSS 최적화 – 크리티컬 CSS 인라인 삽입

**크리티컬 CSS(Critical CSS)**는 첫 화면(Above the Fold)을 렌더링하는 데 필요한 최소한의 CSS입니다.

크리티컬 CSS를 <style> 태그로 HTML에 직접 삽입하면 별도 CSS 파일을 기다리지 않아도 첫 화면이 빠르게 표시됩니다. 나머지 CSS는 비동기로 로드합니다.

크리티컬 CSS를 비동기로 로드하는 방법입니다. media=”print”로 시작하고 onload로 media를 바꾸는 방식입니다.

<link rel="stylesheet" href="styles.css" media="print" onload="this.media='all'">

크리티컬 CSS를 자동으로 추출하는 도구로는 Critical, Penthouse, Critters 등이 있습니다.

5. 불필요한 CSS와 JS 제거 – 트리 쉐이킹

**트리 쉐이킹(Tree Shaking)**은 실제로 사용하지 않는 코드를 빌드 시 제거하는 최적화 기법입니다.

Bootstrap 전체를 import하면 실제로 사용하는 컴포넌트가 몇 개뿐이어도 전체 파일을 내려받아야 합니다. 필요한 컴포넌트만 개별 import하면 파일 크기를 크게 줄일 수 있습니다.

CSS에서도 마찬가지입니다. PurgeCSSPurgeCSS 같은 도구를 사용하면 HTML에서 실제로 사용하는 CSS 선택자만 남기고 나머지를 제거할 수 있습니다. 대형 CSS 프레임워크를 사용할 때 특히 효과적입니다.

워드프레스에서는 Autoptimize 플러그인의 미사용 CSS 제거 기능을 활용할 수 있습니다.

6. 번들 크기 줄이기 – 미니파이와 코드 스플리팅

**미니파이(Minify)**는 코드에서 주석, 공백, 줄바꿈, 긴 변수 이름을 제거해 파일 크기를 줄이는 과정입니다. 코드의 동작은 동일하게 유지됩니다.

CSS 미니파이 예시입니다. 원본 CSS에서 공백과 줄바꿈을 제거하면 파일 크기가 30~40% 줄어듭니다.

Webpack, Vite 같은 번들러는 프로덕션 빌드 시 자동으로 미니파이를 처리합니다. 워드프레스에서는 Autoptimize, W3 Total Cache 같은 플러그인으로 CSS와 JS 미니파이를 할 수 있습니다.

**코드 스플리팅(Code Splitting)**은 큰 JS 번들을 여러 작은 청크로 나눠, 현재 페이지에 필요한 코드만 먼저 로드하는 방법입니다. React, Vue, Next.js 같은 프레임워크를 사용할 때 특히 효과적입니다.

7. 리소스 힌트 – preload, prefetch, preconnect

브라우저에게 미리 준비할 리소스를 알려주는 리소스 힌트를 활용하면 로딩 속도를 더욱 개선할 수 있습니다.

preload: 현재 페이지에서 곧 필요한 리소스를 미리 가져옵니다. LCP 이미지, 주요 폰트, 크리티컬 CSS에 사용합니다.

<link rel="preload" href="hero-image.webp" as="image">

prefetch: 다음 페이지에서 필요할 리소스를 미리 가져옵니다. 사용자가 다음으로 방문할 가능성이 높은 페이지의 리소스에 사용합니다.

<link rel="prefetch" href="/next-page.js">

preconnect: 리소스를 요청할 외부 도메인과 미리 연결합니다. 구글 폰트, CDN, API 서버 등에 사용합니다.

<link rel="preconnect" href="https://fonts.googleapis.com">

8. 정리 및 다음 단계

오늘 배운 핵심을 정리합니다.

  • render-blocking 리소스는 HTML 렌더링을 차단해 첫 화면 표시를 느리게 합니다.
  • JS는 defer 또는 async 속성으로 비차단 로딩합니다.
  • 크리티컬 CSS를 인라인으로 삽입하고 나머지는 비동기로 로드합니다.
  • 미니파이와 트리 쉐이킹으로 파일 크기를 줄입니다.
  • preload, prefetch, preconnect로 중요 리소스를 미리 준비합니다.

다음 글에서는 HTTP/2가 무엇인지, HTTP/1.1과 어떻게 다른지 알아보겠습니다.

댓글 남기기

광고 차단 알림

광고 클릭 제한을 초과하여 광고가 차단되었습니다.

단시간에 반복적인 광고 클릭은 시스템에 의해 감지되며, IP가 수집되어 사이트 관리자가 확인 가능합니다.