<svg> 사용

박상은·2022년 9월 20일
1

해당 포스트는 인프런 - 1분코딩 SVG 마스터강의를 들으면서 정리한 포스트입니다.

해당 포스트에서 작성한 속성은 대부분 css에서 적용할 수 있습니다.

SVG

확장 가능한 벡터 그래픽

벡터 그래픽: 점과 점 사이의 계산을 이용한 그림

이미지와의 차이점은 픽셀을 사용하는 것이 아닌 계산을 이용해서 그리는 것이므로 크기에 따라서 화질이 변하지 않습니다.

이미지의 경우 화질이 높을수록 픽셀의 수가 많아집니다. 따라서 용량이 고화질일수록 커지게 됩니다.
하지만 SVG는 크기에 상관없이 현재 크기에 맞게 계산을 통해서 그리는 것이므로 크기에 영향을 받지 않고 항상 좋은 화질을 유지합니다.
하지만 계산이 필요하기 때문에 복잡할수록 용량이 커지게 되기 때문에 간단한 아이콘에 주로 사용합니다.

계산을 통해 그려지기 때문에 html 속성을 변경시키면 그것에 맞게 색상이나 모양을 쉽게 바꿀 수 있습니다.

SVG 사용 방법

  1. css bakcground-image: url("...경로")
  2. inline <svg></svg>
  3. <object data="...경로" type="image/svg+xml"></object>
  4. <img src="경로" />

SVG 속성

viewBox: 실제 크기와 관계없이 <svg> 내부에서 보여줄 크기를 지정

아래 예시처럼 선언되어 있다면 실제 <svg>의 크기는 가로/세로가 400px입니다.
하지만 <svg> 내부에서 그려지는 크기는 가로/세로가 200px이라고 생각하고 그려지기 때문에 <rect>50px의 크기로 그려지게 됩니다.

실제 크기는 400px, <svg>의 내부에서 그려지는 크기는 200px
400px의 도화지에 100px짜리 사각형을 그리라고 했으나, 실제로는 200px의 도화지이기 때문에 50px로 축소해서 그립니다.

<svg
  width="400"
  height="400"
  viewBox="0 0 200 200"
>
  <rect x="0" y="0" width="100" height="100" />
</svg>

css, js 적용하기

<defs>: 나중에 사용할 그래픽 객체, css, js들을 작성하는 공간

<defs> 내부에서의 작성 방식은 html에서 inline으로 작성하던 방식대로 작성하면 됩니다. ( <style>, <script> )

<svg
  id="face"
  xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  x="0px"
  y="0px"
  viewBox="0 0 40 40"
>
  <defs>
    <style>
      @keyframes eye-ani {
        100% {
          transform: scaleY(0.2);
        }
      }

      #eye.start {
        transform-origin: 50%;
        animation: eye-ani 0.5s infinite alternate;
      }
    </style>
    <script>
      window.addEventListener("DOMContentLoaded", () => {
        const $face = document.querySelector("#face");

        $face.addEventListener("click", () => {
          const $eye = document.querySelector("#eye");
          $eye.classList.toggle("start");
        });
      });
    </script>
  </defs>

	<path id="contour" d="M20,8c6.6,0,12,5.4,12,12s-5.4,12-12,12S8,26.6,8,20S13.4,8,20,8 M20,6C12.3,6,6,12.3,6,20s6.3,14,14,14s14-6.3,14-14
			S27.7,6,20,6L20,6z"/>
	<g id="eye">
		<path d="M14,18c-1.1,0-2,0.9-2,2s0.9,2,2,2s2-0.9,2-2S15.1,18,14,18L14,18z"/>
		<path d="M26,18c-1.1,0-2,0.9-2,2s0.9,2,2,2s2-0.9,2-2S27.1,18,26,18L26,18z"/>
	</g>
	<path id="mouth" d="M28.3,24.6c-1.7,3-4.9,4.9-8.3,4.9s-6.6-1.9-8.3-4.9l-0.9,0.5c1.9,3.3,5.4,5.4,9.2,5.4c3.8,0,7.3-2.1,9.2-5.4
		L28.3,24.6z"/>
	<path id="hair" class="st0" d="M30.8,8.1c-0.9-2-3.6-3.5-6.8-3.5c-0.3,0-0.5,0-0.8,0c-1.2-0.6-2.7-1-4.4-1c-1.6,0-3.2,0.4-4.4,1
		c-0.3,0-0.6,0-0.9,0c-3.4,0-6.3,1.7-7,3.9C4.2,9.4,2.6,11.1,2.6,13c0,2.8,3.2,5,7.2,5c1.9,0,3.5-0.5,4.8-1.3c0.1,0,0.2,0,0.3,0
		c1.3,0.7,2.9,1.2,4.7,1.2c1.9,0,3.6-0.5,4.9-1.4c1.3,0.9,3.1,1.5,5.1,1.5c4,0,7.2-2.2,7.2-5C36.8,10.5,34.2,8.5,30.8,8.1z"/>
</svg>

그리기

속성을 inline-style로 사용하지 않고 css(<style> or xxx.css파일 )을 이용해서 지정할 수 있습니다.
우선순위 css > inline-style

  • 속성
    1. x, y: 시작점 위치
    2. width, height: 사각형 크기
    3. fill: 색상
    4. stroke: 테두리 색상
    5. stroke-width: 테두리 굵기
    6. stroke-linecap: 선의 마무리 형태 ( butt, round , square )
    7. stroke-linejoin: 모서리 형태 ( miter, round , bevel )

1. 사각형 ( <rect> )

  • 속성
    1. rx, ry: 모서리 둥글림 정도
<svg width="600" height="400" style="background-color: #ddd;">
  <rect
    x="40"
    y="40"
    width="200"
    height="200"
    fill="purple"
    stroke="black"
    stroke-width="20"
    
    stroke-linejoin="round"

    rx="20"
    ry="40"
  />
</svg>

2. 원 ( <circle> )

  • 속성
    1. cx, cy: 원의 중점
    2. r: 반지름
<svg width="600" height="400" style="background-color: #ddd;">
  <circle
    cx="400"
    cy="120"
    r="80"
    fill="purple"
    stroke="black"
    stroke-width="20"
  />
</svg>

3. 타원 ( <ellipse> )

  • 속성
    1. cx, cy: 원의 중점
    2. rx, ry: x/y축 반지름
<svg width="600" height="400" style="background-color: #ddd;">
  <ellipse
    cx="400"
    cy="320"
    rx="30"
    ry="60"
    fill="purple"
    stroke="black"
    stroke-width="20"
  />
</svg>

4. 직선 ( <line> )

  • 속성
    1. x1, x2: x축의 시작/끝 점
    2. y1, y2: y축의 시작/끝 점
<svg width="600" height="400" style="background-color: #ddd;">
  <line
    x1="100"
    x2="200"
    y1="300"
    y2="350"
    stroke="purple"
    stroke-width="20"
  />
</svg>

5. 선 ( <polyline> )

  • 속성
    1. points: x, y축의 시작과 끝점들을 ,로 구분해서 작성
<svg width="600" height="400" style="background-color: #ddd;">
  <polyline
    points="20 260, 20 370, 250 370, 220 280"
    stroke="blue"
    stroke-width="20"
    fill="transparent"
  />
</svg>

6. 다각형 ( <ploygon> )

  • 속성
    1. points: x, y축의 시작과 끝점들을 ,로 구분해서 작성
<svg width="600" height="400" style="background-color: #ddd;">
  <ploygon
    points="20 260, 20 370, 250 370, 220 280"
    stroke="blue"
    stroke-width="20"
    fill="transparent"
  />
</svg>

7. 자유 그리기 ( <path> )

  • 속성
    1. d
      1-1. M: 시작점
      1-2. L: 직선 ( 시작점, 끝점 )
      1-3. H: 가로 직선 ( 이동할 x위치 )
      1-4. V: 세로 직선 ( 이동할 y위치 )
      1-5. Z: 현재 위치와 시작점 잇기
      1-6. C: 곡선 ( 시작점, 휘어짐 정도, 끝점 )
<svg width="600" height="400" style="background-color: #ddd;">
  <path
    d="M300 200 L 500 100 H 200 V 200 Z C 350 250, 200 300, 400 300"
    stroke="blue"
    stroke-width="10"
    fill="transparent"
  />
</svg>

8. 텍스트

  • 속성
    1. x, y: 시작과 끝위치
<svg width="600" height="400" style="background-color: #ddd;">
  <text
    x="20"
    y="100"
    font-size="2rem"
    font-weight="bold"
    fill="blue"
  >
    Hello, SVG
  </text>
</svg>

특수한 효과들

1. 그레디언트

  1. <linearGradient>: 직선 형태의 그레디언트 ( 좌 -> 우 )
  2. <radialGradient>: 원형 형태의 그레디언트 ( 상, 하, 좌, 우 -> 중간 )
<svg width="600" height="400" style="background-color: #ddd;">
  <defs>
    <linearGradient id="my-gradient">
      <stop offset="0%" stop-color="red" />
      <stop offset="50%" stop-color="green" />
      <stop offset="100%" stop-color="blue" />
    </linearGradient>
  </defs>

  <text
    x="20"
    y="100"
    font-size="2rem"
    font-weight="bold"
    fill="url(#my-gradient)"
  >
    Hello, SVG
  </text>
</svg>

2. 패턴 ( <pattern> )

반복할 요소의 크기 * 반복 횟수 === <svg>의 크기가 맞지 않으면 의도한 모양의 패턴과 다른 모양이 됩니다.
아래 예시는 원크기(80) * 반복 횟수(10) === <svg>크기(800)

  • 속성
    1. x, y: 패턴의 시작 위치
    2. width, height: 가로/세로 반복할 개수 ( 1: 1개, 0.5: 2개, 0.1: 10개 ... )
    3. <pattern> 내부: 반복할 요소
<svg width="100%" height="100%" viewBox="0 0 800 800" style="background-color: #ddd;">
  <defs>
    <pattern
      id="my-pattern"
      x="0"
      y="0"
      width="0.1"
      height="0.1"
    >
      <circle cx="40" cy="40" r="40" fill="blue" />
    </pattern>
  </defs>

  <rect
    x="0"
    y="0"
    width="100%"
    height="100%"
    fill="url(#my-pattern)"
  />
</svg>

3. 마스크 ( <mask> )

특정 영역만 보이게 하는 효과입니다.

<mask> 내부의 요소가 흰색에 가까울수록 진하게 보이게 됩니다.

<svg
  x="0"
  y="0"
  width="100%"
  height="100%"
  viewBox="0 0 400 400"
>
  <defs>
    <mask id="my-mask">
      <circle id="circle" cx="20" cy="80" r="60" fill="#fff"/>
    </mask>

    <style>
      @keyframes move {
        0% { cx: 20; }
        100% { cx: 140; }
      }

      #circle {
        animation: move 1s infinite alternate;
      }
    </style>
  </defs>

  <g mask="url(#my-mask)">
    <text x="20" y="40" font-size="2rem" font-weight="bold" fill="red">
      Hello, SVG
    </text>
    <text x="20" y="80" font-size="2rem" font-weight="bold" fill="green">
      Hello, Next.js
    </text>
    <text x="20" y="120" font-size="2rem" font-weight="bold" fill="blue">
      Hello, Velog
    </text>
  </g>
</svg>

4. 텍스트 부분 스타일링 ( <tspan> )

<svg width="600" height="400" style="background-color: #ddd;">
  <text
    x="20"
    y="100"
    font-size="2rem"
    font-weight="bold"
    fill="blue"
  >
    Hello, <tspan fill="green">SVG</tspan>
  </text>
</svg>

5. 선 위에 글자 입히기 ( <textPath> )

<svg width="1000" height="800" style="background-color: #ddd;">
  <defs>
    <path
      id="my-text"
      d="M 50 400 C 50 400, 300 500, 400 400 C 400 400, 600 170, 700 300"
      fill="transparent"
      stroke="red"
      stroke-width="10"
    />
  </defs>
  
  <text
    x="20"
    y="100"
    font-size="2rem"
    font-weight="bold"
    fill="blue"
  >
    <textPath href="#my-text">
      Hello, SVG Lorem ipsum dolor, sit amet consectetur
    </textPath>
  </text>
</svg>

마무리

svg는 대부분 툴을 이용해서 만들어진 상태로 사용하기 때문에 직접적으로 코드를 작성하거나 수정할 경우는 거의 없다고 생각합니다.

저도 heoricon, fontawesome 같은 사이트에서 사용할 아이콘을 찾아서 복사 붙여넣기를 이용해서 사용했지만 사용했습니다.

하지만 이게 어떤 코드인지 모르고 사용했기 때문에 불안했기도 했고, 아이콘에서 색상, 크기, 애니메이션 같은 작은 부분을 수정하는데도 검색을 통해서 찾고 테스트하는 과정을 계속하면서 그때만 대충 이해하고 넘어갔던 부분을 하나하나 공부하면서 원리를 이해할 수 있어서 도움이 많이 됐습니다.

물론 위의 코드들을 모두 외우거나 실제로 작성하는 일은 없겠지만 최소한 어떤 코드에 어떤 동작을 하는지 얕게 이해하고 있으니 다음 문제가 생겼을 때 시간 낭비를 줄이고 금방 해결할 수 있을 것 같습니다.

0개의 댓글