• 티스토리 홈
  • 프로필사진
    홍유진
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
홍유진
  • 프로필사진
    홍유진
    • 분류 전체보기 (22)
      • Coding Test (0)
      • Web Frontend (19)
        • Problem Solving (0)
        • HTML_CSS (10)
      • Workflow (1)
      • Database (1)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
      등록된 댓글이 없습니다.
    • 최근 공지
        등록된 공지가 없습니다.
      # Home
      # 공지사항
      #
      # 태그
      # 검색결과
      # 방명록
      • 웹 성능 최적화: 이미지 및 폰트 최적화
        2024년 06월 07일
        • 홍유진
        • 작성자
        • 2024.06.07.:07

        문제

        웹 사이트이 성능은 사용자 경험에 큰 영향을 미치는다. 특히 웹 페이지의 로딩 속도는 사용자 이탈률을 줄이고 SEO 성능을 향상시키는데 중요하다. 그런데 최근 작업한 프로젝트에서 페이지 로딩 속도가 느리다는 피드백을 받았다. 

        네트워크를 확인해보니 속도가 414ms였다.

         

         

        PageSpeed Insights  사이트에 들어가서 확인해보니 웹 페이지의 가장 큰 문제는 1. 누적 레이아웃 이동(CLS) 2. 큰 이미지 파일로 인해 발생하는 로딩 지연이었다.

         

        해결 방법

        문제를 해결하기 위해 세 가지 접근 방식을 사용했다.

        1. 이미지 최적화 : 이미지 파일의 크기를 줄이고, 필요한 경우에만 로드되도록 설정한다.

        2. 폰트 최적화 : 웹 폰트 로딩 시 발생하는 레이아웃 이동을 방지한다.

        3. 이미지 프리로딩 : 주요 이미지를 미리 로드하여 사용자에게 더 빠르게 표시한다.

         

        1. 이미지 최적화

        • 차세대 이미지 형식(WebP) : 기존의 JPEG, PNG 형식보다 더 높은 압축률을 제공하여 파일 크기를 줄인다.
        • Lazy Loading : 사용자가 실제로 이미지를 볼 때 이미지를 로드한다.
        • 이미지 크기 명시 : 이미지 로드 전에 공간을 예약하여 레이아웃 이동을 방지한다.
        const WebtoonImage = styled.img`
          margin-bottom: 5px;
          width: 220px;  // 고정된 너비
          height: 285px; // 고정된 높이
          border-radius: 5px;
          border: ${props => props.theme.borderColor};
          object-fit: cover;
          cursor: pointer;
          border-radius: 5px;
        `;
        
        <WebtoonImage
          src={webtoon.img}
          alt="웹툰 이미지"
          onClick={() => window.open(webtoon.url, "_blank")}
          loading="lazy"  // Lazy Loading 적용
        />

        WebtoonImage 컴포넌트에 width, height 속성을 명시해 주고 loading='lazy' 속성을 추가해 줬다.

         

        2. 폰트 최적화

        웹 폰트를 로드할 때 텍스트가 이동하지 않도록 font-display: swap 속성을 사용하여 초기 로딩 시 시스템 폰트를 사용하게 한다.

         

        import { createGlobalStyle } from "styled-components"; 
        import reset from "styled-reset";
        
        export const GlobalStyle = createGlobalStyle`
        ${reset}
        
        @font-face {
          font-family: 'YourFontFamily';
          src: url('/path/to/your-font.woff2') format('woff2');
          font-display: swap;  // 폰트 최적화
        }
        
        body {
          background-color: ${({ theme }) => theme.bgColor};
          color: ${({ theme }) => theme.fontColor};
          font-family: 'YourFontFamily', sans-serif;  // 폰트 패밀리를 body에 적용
        }
        `;

        GlobalStyle 컴포넌트에 @font-face 규칙을 추가하여 폰트를 최적화하였다.

         

        3. 이미지 프리로딩

        이미지 프리로딩을 통해 주요 이미지를 백그라운드에서 미리 로드하여 사용자가 해당 이미지를 필요로 할 때 즉시 표시될 수 있도록 한다.

         

        const preloadImages = srcs => {
          const promises = srcs.map(
            src =>
              new Promise((resolve, reject) => {
                const img = new Image();
                img.src = src;
                img.onload = resolve;
                img.onerror = reject;
              })
          );
        
          Promise.all(promises)
            .then(() => setPreloadedImages(srcs))
            .catch(err => console.error("이미지 미리 로드 중 오류 발생:", err));
        };

        preloadImages 함수는 이미지 URL 배열을 받아서 모든 이미지를 비동기적으로 미리 로드한다.

        • srcs 배열을 받아서 : srcs는 미리 로드할 이미지 URL 배열이다.
        • Promise 배열 생성 : 각 이미지 URL에 대해 new Image()를 사용하여 이미지를 생성하고, img, src에 URL을 설정한다. 이때 img.onload와 img.onerror 이벤트 핸들러를 설정하여 이미지 로딩이 완료되거나 실패했을 때 각각 resolve와 reject를 호출한다.
        • Promise.all 사용 : 모든 이미지가 로드가 완료될 때까지 기다린다. 모든 프리로딩이 성공적으로 완료되면 setPreloadedImages를 호출하여 상태를 업데이트한다.
        • 오류 처리 : 프리로딩 중 오류가 발생하면 콘솔에 오류 메시지를 출력한다.

         

        결과

        before & after

         

        이러한 최적화를 통해 36점에서 55점으로 개선된 것을 알 수 있다.

        'Web Frontend' 카테고리의 다른 글

        Recoil 새로고침 랜더링 문제  (0) 2024.08.03
        react-Intersection-Observer 라이브러리를 이용해 무한스크롤 구현하기  (0) 2024.08.02
        ThemeProvider로 theme.ts에서 디자인 시스템 설정하기  (0) 2024.07.10
        IntersectionObserver를 활용한 Lazy Loading 적용  (0) 2024.06.23
        Promise.all을 활용한 페이지네이션 해결  (0) 2024.06.22
        다음글
        다음 글이 없습니다.
        이전글
        이전 글이 없습니다.
        댓글
      조회된 결과가 없습니다.
      스킨 업데이트 안내
      현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
      ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
      목차
      표시할 목차가 없습니다.
        • 안녕하세요
        • 감사해요
        • 잘있어요

        티스토리툴바