리액트 프로젝트에서 아이콘 다루기

kkojae·2022년 9월 13일
3
post-thumbnail
post-custom-banner

줍줍 프로젝트는 슬랙 메시지를 아카이빙하는 서비스입니다.
프로젝트 github

이번 글에서는 React 프로젝트를 진행하는 경우 아이콘을 svg로 다루는 방법에 대해 소개하려고 한다. 아이콘을 다루는 방법은 다양하지만 왜 아이콘을 svg로 사용해야하는지에 대해 먼저 알아보도록 하자.

아이콘을 import해 사용할 수 있는 방법은 확장자를 png, svg 등으로 불러와 사용할 수 있다. 그럼 먼저 아이콘을 svg로 사용했을 경우와 png로 사용했을 경우의 차이점에 대해 알아보자.

아이콘을 SVG로 사용할 경우와 PNG로 사용할 경우의 차이점


우선 아이콘은 png로 사용하기보단 svg로 사용해야 많은 이점을 가지고 있다.

아이콘을 svg로 다룰경우 장점

홈 아이콘, 카테고리 아이콘 등 아이콘 이미지를 svg로 사용할 경우 좋은 점은 아래와 같다.

  1. 모든 크기의 브라우저를 원활히 지원할 수 있다. (아이콘의 크기가 확대되더라도 이미지가 깨지지 않는다.)
  2. svg의 일부를 스타일링 할 수 있다. (색상, 크기등을 프로젝트에 맞게 커스텀할 수 있다.)
  3. dom을 사용하여 svg를 실시간으로 수정할 수 있다.(클릭 이벤트에 따라 실시간으로 수정할 수 있다.)
  4. png보다 차지하는 용량이 작아 출력이 png보다 빠르다.

그러면 png를 사용해야하는 경우는 어떤 경우가 있을까?

프로젝트 내부에서 백그라운드 이미지와 같은 이미지를 백터화 하기 어려운 경우 위에서 설명한 svg의 장점을 활용할 수 없기 때문에 png를 사용해주는게 좋다. 요즘은 png보다는 압축률이 월등히 높은 webp를 많이 활용한다. 용량이 작으면 요청 후 응답 시간이 짧아지기 때문에 보다 좋은 사용자 경험을 제공할 수 있기 때문이다. webp를 지원하지 않는 브라우저에서는 jpg를 활용해주는게 좋다.

위와 같은 이유로 프로젝트 내부에서 아이콘을 다룰 경우 svg를 사용해주는 편이 좋다. 이제 svg를 다루는 다양한 방법에 대해 비교해보도록 하자.

1. img 태그에 src 속성을 사용하는 방법


해당하는 방법은 이미 알고 있겠지만, 우리가 이미지를 사용하는 경우 쉽게 떠올릴 수 있는 가장 보편적인 방법이 될 것 같다. 아래 코드를 보며 추가적으로 확인해보자.

import cartIcon from "@public/assets/images/cartIcon.svg";

function Cart() {
  return (
		<>
			{/* some code.. */}
			<img src={cartIcon}>
		</>
	);
}

img 태그에 src 속성값으로 import 해온 cartIcon을 넣어주면 원하는 사이즈의 cartIcon이 프로젝트 화면에 그려지는 것을 확인할 수 있다.

하지만, 이 방법에는 단점이 존재한다. 만약 검정색, 흰색, 녹색의 카트아이콘이 24px, 36px, 48px이 필요하다고 하면 어떻게 될까?

그러면 우리는 해당하는 사이즈와 색상에 맞는 cartIcon들을 새롭게 만들어 svg 파일을 만들어 줘야 한다.

import black24pxCartIcon from "@public/assets/images/black24pxCartIcon.svg";
import black36pxCartIcon from "@public/assets/images/black36pxCartIcon.svg";
import black48pxCartIcon from "@public/assets/images/black48pxCartIcon.svg";
import white24pxCartIcon from "@public/assets/images/white24pxCartIcon.svg";
import white36pxCartIcon from "@public/assets/images/white36pxCartIcon.svg";
import white48pxCartIcon from "@public/assets/images/white48pxCartIcon.svg";
import green24pxCartIcon from "@public/assets/images/green24pxCartIcon.svg";
import green36pxCartIcon from "@public/assets/images/green36pxCartIcon.svg";
import green48pxCartIcon from "@public/assets/images/green48pxCartIcon.svg";

function Cart() {
  return (
		<>
			{/* some code.. */}
			<img src={black24pxCartIcon}>
			<img src={black36pxCartIcon}>
			<img src={black48pxCartIcon}>
			{/* some code.. */}
		</>
	);
}

극단적인 상황이지만, import 구문이 반복이되고 svg 파일을 여러개 생성해서 사용해야하는 단점이 존재한다.

2. svg 코드를 component화 시켜 사용하는 방법


svg 파일을 열어 확인해보면 아래와 같은 코드를 확인 할 수 있다.

// cartIcon.svg
<svg 
	width="24px"
	height="24px"
	viewBox="0 0 51 44"
	fill="none"
	xmlns="http://www.w3.org/2000/svg"
>
	<path d="19.......24.75H40.3573Z" fill="#000000"/>
</svg>

svg도 tag와 속성으로 이뤄져있다면, 해당하는 코드를 component화를 시켜주면 된다. 어떻게 component화를 시킬지는 큰 고민을 해지 않아도 된다.

아래 코드를 먼저 확인해보자.

function CartIcon() {
  return (
    <svg
      width="500px"
      height="500px"
      viewBox="0 0 51 44"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path
        d="19.......24.75H40.3573Z"
        fill="red"
      />
    </svg>
  );
}

export default CartIcon;

이렇게 svg를 component화를 시켜준다면, 사용하는 곳에서 import 후 바로 사용할 수 있고 component와 동일하게 props로 속성값들을 내려주고 색상 및 사이즈를 자유롭게 수정할 수 있는 장점을 가지고 있다.

아래 코드는 props를 내려줘 custom 된 svg component를 생성할 수 있도록 변경한 코드이다.

function CartIcon({ width, height, fill }) {
  return (
    <svg
      width={width}
      height={height}
      viewBox="0 0 51 44"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path
        d="19.......24.75H40.3573Z"
        fill={fill}
      />
    </svg>
  );
}

export default CartIcon;

이처럼 코드를 수정한다면 필자가 처음 소개한 img 태그에 src 속성을 사용하는 방법의 단점이 보완된다.

import CartIcon from '@src/svg/CartIcon';

function Cart() {
  return (
		<>
			{/* some code.. */}
			<CartIcon width="24px" height="24px" fill="blue" />
			<CartIcon width="36px" height="36px" fill="green" />
			<CartIcon width="48px" height="48px" fill="red" />
			{/* some code.. */}
		</>
	);
}

같은 아이콘을 상황에 맞게 custom해서 하나의 컴포넌트로 재활용이 가능해졌다.

3. svg 파일 자체를 custom 가능하게 만드는 방법


두번째로 안내한 svg를 component화 시키는 방법과 유사하고 custom 해서 사용할 수 있어 img 태그에 src 속성을 사용하는 방법의 단점을 보완할 수 있는 방법이다.

해당하는 방법은 svg 파일 자체를 수정해 사용할 수 있다. 우선 svg 파일 내부에 custom 하고 싶은 속성의 값을 current로 설정해주면 된다.

// cartIcon.svg
<svg 
	width="current"
	height="current"
	viewBox="0 0 51 44"
	fill="none"
	xmlns="http://www.w3.org/2000/svg"
>
	<path d="19.......24.75H40.3573Z" fill="current"/>
</svg>

이렇게 svg 파일을 변경해줬다면, 사용해야할 컴포넌트에서 props로 custom할 속성들을 내려주면 쉽게 사용할 수 있다.

// 사용할 곳..!!
import CartIcon from "@public/assets/images/cartIcon.svg";

function Cart() {
  return (
    <>
      {/* some code.. */}
      <CartIcon width="24px" heigth="24px" fill="red" />
      <CartIcon width="36px" heigth="36px" fill="green" />
      <CartIcon width="48px" heigth="48px" fill="blue" />
      {/* some code.. */}
    </>
  );
};

위 방법을 사용할 경우 @svgr/webpack 패키지를 설치하고 d.ts에 svg를 선언해주어야 한다.

// custom.d.ts
declare module "*.svg" {
  const content: ({ fill, width, height }: SVGProps) => JSX.Element;
  export default content;
}

해당하는 방법의 단점은 @svgr/webpack 패키지를 설치하게 됨으로써 모듈의 사이즈가 증가한다는 점이다.

줍줍 프로젝트에서 SVG 파일을 어떻게 다뤘나?


이번 줍줍 프로젝트에서는 svg를 컴포넌트화 시켜 사용하는 방법을 선택했다.

svg 파일 자체를 custom 하는 방법과 svg를 컴포넌트화 시켜 사용하는 방법은 모두 확장성을 가지고 있어 사용하기 편하지만 @svgr/webpack 패키지를 설치한다는 점이 다른 부분이다. 따라서 svg를 직접 컴포넌트화 시켜 사용한다면 모듈 크기를 조금이라도 더 줄일 수 있다고 생각한다.

post-custom-banner

0개의 댓글