- 프로젝트: loplat UI, 채식 지도
- 키워드: picture tag, source tag, WebP, sprite image, naver map marker, image optimization
- 상황 1
- loplat UI의 Spinner 컴포넌트는 용량이 큰 sprite image와 css 애니메이션을 통해 구현했다.
(참고: css animation steps로 Spinner 구현하기)
- gif를 사용하지 않고 png로 구현했음에도 아직 이미지 용량이 크다는 생각이 들었다.
- WebP 형식을 사용하려다가 safari 브라우저에서 지원하지않아 보류했는데, 크롬에서라도 WebP 이미지를 지원하고자 한다.
- loplat UI의 Spinner 컴포넌트는 용량이 큰 sprite image와 css 애니메이션을 통해 구현했다.
- 해결방법 1
- picture tag를 사용하면 browser/display마다 최적의 이미지를 제공할 수 있다는 것을 알게 되었다.(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture)
- img tag(SpriteImage)만 있던 기존의 코드를 picture와 source를 이용하여 개선했다.
// before <SpriteImage src={Cube} alt="" duration={duration} steps={steps} /> // after <picture> <source srcSet={CubeWebp} type="image/webp" /> <SpriteImage src={Cube} alt="" duration={duration} steps={steps} /> </picture>
picture tag 안의 source에서 CubeWebp라는 webp 이미지를 srcset으로 넘겨준다. 이때, type="image/webp"를 꼭 명시해야한다.
브라우저가 WebP 형식을 지원하면 CubeWebp를 img의 src로 사용하고, WebP 형식을 지원하지 않으면 Cube를 src로 사용한다. - 크롬에서 개발자 도구를 통해 확인한 결과, current source에 WebP 이미지가 사용된 것을 확인했다.
- 사파리에서 네트워크를 확인한 결과, webp 이미지는 불러오지 않고 png 이미지만 다운로드된 것을 확인했다.
- picture tag를 사용하면 browser/display마다 최적의 이미지를 제공할 수 있다는 것을 알게 되었다.(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture)
- 상황 2
- 네이버 지도에 음식 Marker 이미지를 올리고자 한다.
- 수많은 종류의 마커 이미지를 하나하나 불러오면 용량이 크고 관리하기 불편하므로, 하나의 스프라이트 이미지 파일에 모든 마커를 담은 후 naver marker의 속성을 이용하여 필요한 부분만 렌더링해야한다.
(https://navermaps.github.io/maps.js/docs/naver.maps.Marker.html)
- 해결 방법 2
- 디자이너분에게 각 마커를 합친 sprite image를 요구하고 전달받았다.
- naver marker 가이드를 참고하여 특정 index의 음식 icon을 추출하는 함수를 작성한다.
(https://navermaps.github.io/maps.js/docs/tutorial-2-Marker.html)
필요한 정도의 scaled width와 height를 설정하고 size(표시할 마커 하나의 크기)와 scaledSize(사용할 이미지의 전체 크기) 속성에 넘겨준다. 그리고 사용할 음식 icon의 index에 의해 origin을 결정하면 하나의 음식 icon만 추출할 수 있다. (ex> 햄버거는 0번째, 샌드위치는 4번째)const MARKER_HEIGHT = 68; // 실제 아이콘 하나의 높이 const MARKER_WIDTH = 48; // 실제 아이콘 하나의 너비 const NUMBER_OF_MARKER = 10; // 아이콘 갯수 const SCALE = 2 / 3; // 줄이는 비율 const SCALED_MARKER_WIDTH = MARKER_WIDTH * SCALE; // 사용할 마커의 너비 const SCALED_MARKER_HEIGHT = MARKER_HEIGHT * SCALE; // 사용할 마커의 높이 export function generateStoreMarkerIcon(markerIndex: number): ImageIcon { return { url: 'images/markers.png', size: new naver.maps.Size(SCALED_MARKER_WIDTH, SCALED_MARKER_HEIGHT), scaledSize: new naver.maps.Size(SCALED_MARKER_WIDTH * NUMBER_OF_MARKER, SCALED_MARKER_HEIGHT), origin: new naver.maps.Point(SCALED_MARKER_WIDTH * markerIndex, 0), }; }
- 그 후 추출한 icon과 naver maps api를 이용하여 marker를 그린다.
marker = new naver.maps.Marker({ map, // naver map position: new naver.maps.LatLng(...coordinates), // 지도에서 마커의 위치 icon, // generate한 음식 icon });
- 원하는 위치에 원하는 아이콘이 그려진다.
- 디자이너분에게 각 마커를 합친 sprite image를 요구하고 전달받았다.
- 의의
- 1번 상황에서 WebP 이미지를 통해 Circle(51KB -> 14KB) 73%, Cube(28Kb -> 6Kb) 79% 용량 최적화를 했다.
- 2번 상황에서 스프라이트 이미지(24KB)를 통해 각 마커 이미지를 따로 받았을 때(3KB * 10)보다 20% 용량 최적화를 했다.
'프론트엔드' 카테고리의 다른 글
Storybook에서 user interactions 테스트하기 (2) | 2022.03.15 |
---|---|
JS library에서 cjs, esm format 모두 지원하기 (0) | 2022.03.09 |
chrome extension New Tab customizing을 위한 개발 환경 만들기 (0) | 2022.02.17 |
storybook에서 웹접근성 검사하기(feat. storybook-addon-a11y) (0) | 2022.02.11 |
웹접근성(web accessibility), SEO 개선하기 (0) | 2022.02.11 |