PNG Sprite vs SVG Sprite 비교
도입 배경
기존에는 아이콘 이미지를 PNG 포맷의 스프라이트로 관리하고 있었습니다. 같은 아이콘이라도 크기가 다르면 별도 이미지를 제작해야 했고, 화면 확대 시 이미지가 깨지는 문제가 있었습니다. 또한 개별 SVG 파일이 늘어날수록 HTTP 요청 수 증가에 따른 성능 이슈도 발생했습니다.
이를 해결하기 위해 벡터 기반 SVG 파일들을 하나의 스프라이트로 합쳐 관리하는 환경을 구축했습니다.
체크포인트 및 목표
- 같은 모양의 아이콘을 크기와 상관없이 사용 가능해야 함
- 화면 확대 시에도 깨짐이 없어야 함
- 기존 빌드 환경(Gulp 기반)에 자연스럽게 통합되어야 함
- 기존 PNG Sprite와 동일한 SCSS mixin 방식으로 사용 가능해야 함
- 서비스별로 독립 빌드가 가능해야 함
- 캐시 무효화를 위한 타임스탬프 적용 필요
기술 구현
빌드 파이프라인
Gulp 플러그인을 활용하여 서비스별 SVG 폴더의 개별 아이콘들을 하나의 스프라이트 이미지로 병합하는 태스크를 구성했습니다. 빌드 시 타임스탬프가 파일명에 자동 추가되어 캐시 무효화가 적용됩니다.
SCSS Mixin 자동 생성
Mustache 기반 템플릿을 제작하여 스프라이트 빌드 시 SCSS 파일이 자동 생성되도록 했습니다. 생성된 mixin은 아이콘명과 원하는 크기를 인자로 받아 스프라이트 내 위치와 크기를 자동 계산합니다.
// 기본 사용
.icon-logo {
@include get-sprite-서비스명('logo');
}
// 크기 변경
.icon-logo--large {
@include get-sprite-position-서비스명('logo', 71);
}
// 여러 아이콘 분기
.util-btn::before {
@include get-sprite-서비스명; // 기본 선언
}
.util-btn--share::before {
@include get-sprite-position-서비스명('ic-share', 20);
}
.util-btn--delete::before {
@include get-sprite-position-서비스명('ic-delete', 40);
}
폴더 구조
img/svg/sprites/
├── serviceA/ ← 입력: 개별 SVG 아이콘
│ ├── icon1.svg
│ └── icon2.svg
├── serviceB/
│ └── icon3.svg
├── sp_serviceA_*.svg ← 출력: 병합된 스프라이트
└── sp_serviceB_*.svg
scss/svg/
├── sp_serviceA.scss ← 출력: 자동 생성된 mixin
└── sp_serviceB.scss
벤치마킹 사례
도입 전 국내외 주요 서비스의 아이콘 관리 방식을 조사했습니다.
| 서비스 | 방식 | 특징 |
|---|---|---|
| 대형 쇼핑 라이브 | SVG Sprite | 확대 깨짐 방지 목적의 단일 스프라이트 |
| 대형 동영상 플랫폼 | SVG Sprite | 단일 스프라이트 파일로 아이콘 통합 관리 |
| 글로벌 스토어 | SVG inline + 단일 SVG | 인라인 태그와 개별 파일 혼용 |
| 글로벌 IT 기업 | Icon Font | 커스텀 심볼 폰트화, 디자이너-개발자 협업 |
성과
- 스프라이트 이미지 용량 56% 감소 (18KB → 8KB, 럭셔리 서비스 기준)
- 동일 아이콘의 크기별 이미지 제작 불필요 → 디자인 리소스 절감
- 고해상도 화면(Retina) 대응 자동 해결
- 서비스별 독립 빌드로 불필요한 아이콘 번들링 방지
- 기존 PNG mixin과 동일한 사용법으로 학습 비용 최소화