웹 성능 최적화: 사이트 속도 향상하기

· 12분 읽기

목차

웹사이트 성능은 단순히 사이트를 더 빠르게 느끼게 하는 것이 아니라 수익에 직접적인 영향을 미칩니다. 연구에 따르면 페이지 로드 시간이 1초 지연되면 전환율이 7% 감소하고, 모바일 사용자의 53%는 로드하는 데 3초 이상 걸리는 사이트를 포기합니다.

이 종합 가이드에서는 Core Web Vitals 이해부터 고급 캐싱 기술 구현까지 웹사이트 성능을 최적화하는 검증된 전략을 안내합니다. 전자상거래 스토어, 콘텐츠 사이트 또는 웹 애플리케이션을 운영하든 이러한 기술은 사용자에게 더 빠르고 반응성 있는 경험을 제공하는 데 도움이 됩니다.

Core Web Vitals 설명

Core Web Vitals는 웹에서 사용자 경험을 측정하기 위한 Google의 표준화된 지표입니다. 2021년부터 Google 검색 알고리즘의 순위 요소가 되어 SEO와 사용자 만족도 모두에 필수적입니다.

이러한 지표는 사용자 경험의 세 가지 중요한 측면인 로딩 성능, 상호작용성 및 시각적 안정성에 중점을 둡니다. 각 지표를 분석하고 실용적인 최적화 전략을 살펴보겠습니다.

LCP — Largest Contentful Paint

목표: 2.5초 미만

LCP는 가장 큰 가시적 콘텐츠 요소가 화면에 렌더링되는 데 걸리는 시간을 측정합니다. 일반적으로 히어로 이미지, 메인 제목 또는 비디오 플레이어 등 페이지가 처음 로드될 때 뷰포트를 지배하는 요소입니다.

LCP를 느리게 만드는 일반적인 원인은 다음과 같습니다:

최적화 전략:

  1. 중요 리소스 프리로드: 브라우저에 LCP 요소를 즉시 가져오도록 지시
<link rel="preload" as="image" href="hero.webp">
<link rel="preload" as="font" href="main-font.woff2" crossorigin>
  1. 서버 응답 시간 최적화: 더 빠른 호스팅 사용, 서버 측 캐싱 구현 및 데이터베이스 쿼리 최적화를 통해 TTFB를 600ms 미만으로 목표
  2. CDN 사용: 사용자에게 더 가까운 엣지 위치에서 정적 자산 제공
  3. 렌더링 차단 리소스 제거: 중요 CSS를 인라인으로 포함하고 중요하지 않은 JavaScript를 지연
  4. 이미지 최적화: WebP 또는 AVIF와 같은 최신 형식 사용, 적극적으로 압축하고 반응형 이미지 제공

프로 팁: Lighthouse Analyzer를 사용하여 LCP 요소를 식별하고 빠르게 로드되는 것을 차단하는 요소를 정확히 확인하세요.

INP — Interaction to Next Paint

목표: 200밀리초 미만

INP는 2024년에 First Input Delay(FID)를 대체하여 반응성을 더 포괄적으로 측정합니다. 페이지 수명 주기 전반에 걸쳐 모든 사용자 상호작용(클릭, 탭 및 키보드 입력)의 지연 시간을 추적합니다.

낮은 INP 점수는 일반적으로 다음에서 비롯됩니다:

최적화 전략:

  1. 긴 작업 분할: 50ms 이상의 JavaScript 작업은 더 작은 청크로 분할해야 함
// 모든 것을 한 번에 처리하는 대신
function processItems(items) {
  items.forEach(item => heavyOperation(item));
}

// 청크로 분할
async function processItems(items) {
  for (let i = 0; i < items.length; i++) {
    heavyOperation(items[i]);
    if (i % 50 === 0) {
      await new Promise(resolve => setTimeout(resolve, 0));
    }
  }
}
  1. Web Workers 사용: 무거운 계산을 백그라운드 스레드로 오프로드
  2. 비용이 많이 드는 핸들러 디바운스: 빠른 사용자 입력 중 이벤트 핸들러가 실행되는 빈도 제한
  3. 타사 스크립트 최적화: 비동기적으로 로드하고 태그 관리자를 사용하여 실행 제어 고려
  4. requestIdleCallback 사용: 브라우저 유휴 시간 동안 중요하지 않은 작업 예약

CLS — Cumulative Layout Shift

목표: 0.1 미만

CLS는 페이지 로드 중 예기치 않은 레이아웃 이동을 추적하여 시각적 안정성을 측정합니다. 광고가 위에 로드되어 버튼을 클릭하려는 순간에 버튼이 이동하는 것만큼 사용자를 좌절시키는 것은 없습니다.

레이아웃 이동의 일반적인 원인:

최적화 전략:

  1. 항상 크기 지정: 모든 미디어에 명시적인 너비 및 높이 속성 설정
<img src="product.jpg" width="800" height="600" alt="Product">
<video width="1920" height="1080" poster="thumbnail.jpg">
  1. 동적 콘텐츠를 위한 공간 예약: CSS aspect-ratio 또는 min-height 사용
.ad-container {
  min-height: 250px;
  aspect-ratio: 16 / 9;
}
  1. 폰트 프리로드: 폰트 교체로 인한 레이아웃 이동 방지
  2. CSS containment 사용: 특정 요소에 대한 레이아웃 변경 격리
  3. 기존 콘텐츠 위에 콘텐츠 삽입 방지: 스크롤 아래에 새 요소 추가하거나 오버레이 사용

이미지 최적화 전략

이미지는 일반적으로 페이지 전체 무게의 50-70%를 차지하므로 성능 향상을 위한 가장 큰 기회입니다. 최신 이미지 최적화는 단순히 JPEG를 압축하는 것 이상입니다.

올바른 형식 선택

다양한 이미지 형식은 다양한 사용 사례에서 뛰어납니다. 다음은 포괄적인 비교입니다:

형식 최적 용도 압축 브라우저 지원
WebP 사진, 복잡한 그래픽 JPEG보다 25-35% 작음 96% (모든 최신 브라우저)
AVIF 사진, 고품질 이미지 JPEG보다 50% 작음 88% (Chrome, Firefox, Safari 16+)
JPEG 사진용 대체 기본 압축 100%
PNG 투명도, 단순 그래픽 무손실, 더 큰 파일 100%
SVG 아이콘, 로고, 일러스트 확장 가능, 매우 작음 100%

<picture> 요소를 사용하여 대체 옵션과 함께 최신 형식을 제공하세요:

<picture>
  <source srcset="hero.avif" type="image/avif">
  <source srcset="hero.webp" type="image/webp">
  <img src="hero.jpg" alt="Hero image" width="1200" height="600">
</picture>

반응형 이미지

모바일 사용자에게 동일한 2000px 이미지를 제공하는 것은 낭비입니다. srcsetsizes를 사용하여 브라우저가 최적의 이미지 크기를 선택하도록 하세요:

<img 
  srcset="small.jpg 400w, medium.jpg 800w, large.jpg 1200w"
  sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px"
  src="medium.jpg"
  alt="Responsive image">

이것은 브라우저에 다음과 같이 알려줍니다: "세 가지 버전이 있습니다. 최대 600px 너비의 화면에서는 400px 버전을 사용하세요. 최대 1000px의 화면에서는 800px를 사용하세요. 그렇지 않으면 1200px를 사용하세요."

압축 기술

적극적인 압축은 최소한의 품질 손실로 파일 크기를 60-80% 줄일 수 있습니다:

Image Optimizer를 사용하여 다양한 형식과 품질 설정을 일괄 처리하고 비교해 보세요.

빠른 팁: "Save-Data" 모드 감지를 활성화하여 느린 연결의 사용자에게 더 압축된 이미지를 제공하세요: if (navigator.connection?.saveData) { /* serve lower quality */ }

지연 로딩 구현하기

지연 로딩은 화면 밖 리소스의 로딩을 필요할 때까지 연기하여 초기 페이지 무게를 극적으로 줄이고 로드 시간을 개선합니다.

네이티브 지연 로딩

최신 브라우저는 간단한 속성으로 네이티브 지연 로딩을 지원합니다:

<img src="image.jpg" loading="lazy" alt="Description">
<iframe src="embed.html" loading="lazy"></iframe>

이것은 95% 이상의 브라우저 지원으로 이미지 및 iframe에 작동합니다. 브라우저는 리소스가 뷰포트에 접근할 때 자동으로 로드합니다.

즉시 로딩을 사용해야 하는 경우:

<img src="hero.jpg" loading="eager" fetchpriority="high" alt="Hero">

JavaScript 기반 지연 로딩

더 많은 제어 또는 이전 브라우저 지원을 위해 Intersection Observer API를 사용하세요:

const imageObserver = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src;
      img.classList.remove('lazy');
      observer.unobserve(img);
    }
  });
});

document.querySelectorAll('img.lazy').forEach(img => {
  imageObserver.observe(img);
});

HTML 구조:

<img data-src="actual-image.jpg" src="placeholder.jpg" class="lazy" alt="Description">

지연 로딩 모범 사례

코드 압축 및 번들링

압축은 기능을 변경하지 않고 코드에서 불필요한 문자를 제거하는 반면, 번들링은 HTTP 요청을 줄이기 위해 여러 파일을 결합합니다.

CSS 최적화

CSS 파일은 특히 프레임워크를 사용할 때 놀라울 정도로 클 수 있습니다. 최적화 방법은 다음과 같습니다:

  1. CSS 압축: 공백, 주석 및 중복 코드 제거
  2. 사용하지 않는 CSS 제거: PurgeCSS와 같은 도구로 사용하지 않는 스타일 제거
  3. 중요 CSS: 스크롤 위 스타일을 인라인으로 포함하고 나머지는 지연
<style>
  /* Critical CSS inlined here */
  .header { background: #38bdf8; }
  .hero { min-height: 400px; }
</style>
<link rel="preload" href="main.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="main.css"></noscript>

JavaScript 최적화

JavaScript는 처리하는 데 가장 비용이 많이 드는 리소스입니다—다운로드, 구문 분석, 컴파일 및 실행되어야 합니다.

압축 전략:

동적 가져오기를 사용한 코드 분할 예제:

// 모든 것을 미리 가져오는 대신
import { heavyLibrary } from './heavy-library.js';

// 필요할 때만 로드
button.addEventListener('click', async () => {
  const { heavyLibrary } = await import('./heavy-library.js');
  heavyLibrary.doSomething();
});

빌드 도구 구성

최신 빌드 도구는 압축을 자동으로 처리합니다. 다음은 샘플 Vite 구성입니다:

// vite.config.js
export default {
  build: {
    minify: 'terser',
    terserOptions: {
      compress: {
        drop_console: true,
        drop_debugger: true
      }
    },
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
          utils: ['lodash', 'date-fns']
        }
      }
    }
  }
}

프로 팁: Bundle Analyzer를 사용하여 JavaScript 번들을 시각화하고 최적화 기회를 식별하세요