SVG 스프라이트 기법으로 사이트 성능 향상시키기(리액트에서 스프라이트 SVG 사용하기)

정수현·2023년 1월 10일
9

React

목록 보기
3/8
post-thumbnail

프로젝트 배포가 끝났다. 첫 배포 후 라이트하우스에서 성능을 측정해보니 성능 65점, 접근성 86점으로 개선해야 하는 수치가 나왔다. 성능과 접근성 면에서 여러 가지 방법으로 리팩토링을 시도해볼 예정인데, 첫번째 시도는 이미지 스프라이트를 사용하여 Peformance 점수를 향상 시켜보는 것이다.

문제 상황

많은 아이콘 이미지들이 한 페이지에서 동시에 불려지고 있는데, 레티나 디스플레이 대응을 위해 2배 크기의 이미지로 저장해두었더니 용량도 용량이고 아이콘 이미지 호출 횟수가 많은 것을 확인해볼 수 있다.

문제 해결을 위한 방법

이미지 스프라이트

이미지 스프라이트 기법이란 하나의 이미지 파일에 페이지에서 사용할 여러가지 이미지들을 넣어 좌표와 범위를 통해 특정 이미지를 불러오는 기법을 말한다. 한번의 이미지 로딩을 통해 여러가지 이미지를 불러올 수 있어 이미지 호출을 하는 성능 최적화에 장점이 있다. 자주 교체되지 않는 아이콘들을 모아 스프라이트 이미지로 제작하고 각 위치에서 해당하는 이미지만 잘라 사용하여 이미지 호출 횟수를 대폭 줄여 성능을 향상시켜보고자 한다.

SVG 사용

스프라이트 이미지를 제작하다가 좀 더 욕심이 나서 이미지를 SVG로 교체하고 이를 스프라이트 이미지로 제작하여 사용해보려고 한다. 조금이라도 성능 향상에 기여하길 기대해본다.

SVG(Scalable Vector Graphics)는 2차원 벡터 그래픽을 서술하는 XML 기반의 마크업 언어입니다. SVG는 텍스트 기반의 열린 웹 표준 중 하나로, 모든 사이즈에서 깔끔하게 렌더링 되는 이미지를 서술하며 CSS, DOM, JavaScript, SMIL (en-US) 등 다른 웹 표준과도 잘 동작하도록 설계됐습니다. SVG는 달리 말하자면 HTML과 텍스트의 관계를 그래픽에 적용한 것입니다. -MDN

SVG의 장점

  • 로딩 속도가 빠르고
  • 크기에 따라 이미지가 왜곡되거나 품질이 떨어져 보이지 않는다.
    • 고려했던 레티나 디스플레이에서도 품질 저하없이 볼 수 있다.
  • CSS로 디자인을 수정할 수 있다.

해결 방법 도입(SVG Sprite)

SVG 파일로 Sprite 이미지를 제작하기 위해

Spritebot 이라는 툴을 사용했다.

Spritebot 사용 방법

사용 방법은 간단하다. SVG 파일들을 드래그 앤 드롭하여 스프라이트 이미지를 생성하면 된다.

파일을 넣고 Save Sprite Sheet 버튼을 클릭하여 스프라이트로 제작된 SVG 파일을 export할 수 있다.

간단한 예시로 사용방법으로 정리하기 위해 소셜 로그인 아이콘만 스프라이트로 제작한 SVG 파일을 활용해보려고 한다.
export 하면 이런 식으로 각각의 SVG 파일이 <symbol> 태그로 묶여있는 모습을 확인할 수 있다.

<svg xmlns="http://www.w3.org/2000/svg">
<symbol id="facebook" viewBox="0 0 24 24">
    <path fill="#2D9CDB" d="M17 2h-3a5 5 0 0 0-5 5v3H6v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3V2z"/>
</symbol>
<symbol id="google" viewBox="0 0 24 24">
    <path fill="#4285F4" d="M21 12.207c0-.606-.054-1.18-.146-1.74h-8.659v3.456h4.958c-.222 1.134-.873 2.092-1.839 2.744v2.298h2.958C20.004 17.364 21 15.004 21 12.207z"/><path fill="#34A853" d="M12.195 21.195c2.483 0 4.56-.827 6.077-2.23l-2.958-2.298c-.827.551-1.877.889-3.119.889-2.398 0-4.429-1.617-5.157-3.801h-3.05v2.368c1.51 3.003 4.614 5.072 8.207 5.072z"/><path fill="#FBBC05" d="M7.038 13.755A5.336 5.336 0 0 1 6.748 12c0-.613.106-1.203.29-1.755V7.877h-3.05a9.089 9.089 0 0 0 0 8.246l3.05-2.368z"/><path fill="#EA4335" d="M12.195 6.444c1.357 0 2.567.468 3.525 1.38l2.621-2.62c-1.586-1.488-3.663-2.4-6.146-2.4-3.593 0-6.697 2.07-8.206 5.073l3.05 2.368c.727-2.184 2.758-3.8 5.156-3.8z"/></symbol>
<symbol id="kakao" viewBox="0 0 24 24">
    <path fill="#F2C94C" d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></symbol>
</svg>

다음은 Spritebot에서 제공하는 사용 방법이다.

<svg><use xlink:href="[스프라이트 이미지.svg]#facebook" /></svg>

이렇게 알려주는 대로 사용해봤는데 에러가 났다. 리액트에서는 저 xlink가 작동하지 않는 문제가 있어서 빼고 다음과 같이 써주어야 했다.

<svg><use href="[스프라이트 이미지.svg]#facebook" /></svg>

SVG 아이콘을 사용하는 컴포넌트 제작

SVG 아이콘을 사용하는 컴포넌트를 다음과 같이 만들어주었다.

import SocialSpriteSVG from "../../assets/icon/social_icons.svg"

const SocialSVG = ({id, color, size=24}) => (
    <svg fill={color} width={size} height={size}>
        <use href={`${SocialSpriteSVG}#${letter}`} />
    </svg>
)

SocialSVG 컴포넌트 사용

사이즈는 기본 값인 24를 그대로 사용할 것이기 때문에 다음과 같이 id만 넘겨서 사용해주었다.

<SocialSVG id="facebook"/>
<SocialSVG id="google"/>
<SocialSVG id="kakao"/>

사이즈를 다르게 주고 싶으면 다음과 같이 사용할 수 있다.

<SocialSVG id="kakao" size=20/>

결과


이제 네트워크 탭을 확인해보니 아이콘을 제외한 사용자 프로필 이미지나 사용자가 업로드한 게시물의 사진만을 잘 불러오고 있다.

기존 2배 크기의 png 아이콘을 사용했을 때와 SVG 스프라이트를 사용했을 때의 성능을 비교해보고자 한다.

파일 용량

스프라이트 페이지

57%의 이미지 용량을 줄일 수 있었다!!

스프라이트 제외 페이지들

89%의 이미지 용량을 줄일 수 있었다!!

Lighthouse 결과

우왕!!! 이렇게 많이 오르는건 예상하지 못했는데 성능 면에서 20점 가까이 상승했다!!!
다음은 이미지 압축을 통해 성능을 90점 이상으로 끌어올려보도록 시도해보려고 한다😋

4개의 댓글

comment-user-thumbnail
2023년 2월 9일

단순히 개념 및 방법을 적은게 아니라 해당 사진과 함께 단계별로 설명해주셔서 이해가 정말 잘돼요! 썸네일도 너무 귀엽네요 좋은 글 감사합니다 :)

1개의 답글
comment-user-thumbnail
2023년 3월 15일

탐나는 인재네요 흑..
저희도 프론트 개발자 뽑아요 -

답글 달기
comment-user-thumbnail
2024년 2월 25일

좋은 글 감사해요!

답글 달기