• [SVG] SVG 다루기

    2019. 9. 16.

    by. 나나 (nykim)

     

    1. SVG란?

     

    SVG는, 확장 가능한 벡터 그래픽(Scalable Vector Graphics)을 말합니다.
    2차원 그래픽을 표현하기 위해 만들어진 XML파일 형식의 마크업 언어인데요,
    텍스트 편집기에서 CSS나 JS로 수정이 가능하다는 점이 가장 큰 장점이라 할 수 있습니다.

    또, 확장이 가능하다는 점에서 확대해도 품질이 떨어지지 않습니다.
    레티나나 모바일에 대응하기 위한 추가 작업도 필요 없고, 시각 장애가 있는 사용자들이 웹을 확대하더라도 품질 저하의 문제가 없죠!

    단, 미지원 브라우저가 몇몇 있습니다. IE 8이라던가 IE 8이라던가 뭐 IE 같은 거요(ㅠㅠ)

     


     

    2. SVG 사용하기

     

    SVG는 도형과 선으로 이루어져 있고, 직접 path의 값을 입력해 뭔가를 그려낼 수도 있어요!

    하지만 그걸 배우고 있다가는 SVG를 써먹기도 전에 나가 떨어질 거 같아 여기선 다루지 않습니다.

    Adobe Illustration을 통해 만든 SVG를 웹페이지에 어떻게 삽입하는지 살펴보겠습니다.

     

    자, 여기 SVG를 하나 가져왔어요!

    이 이미지를 일러스트레이터로 열었을 때, 아트보드의 크기는 512*512네요.

     

     

     

     

    1) img 태그

    <img src="nana.svg" />

     

    SVG는 일반적인 이미지처럼 img 태그를 통해 삽입할 수 있습니다.

     

     

    이렇게 해놓고 웹페이지를 열어보면, SVG 이미지가 문서 전체 크기만큼 차지하고 있는 걸 볼 수 있습니다.

    그래서 img 태그에 width, height 값을 지정하거나 css로 width 값을 지정하여 크기 조절이 가능합니다.

     

    이 방식은 IE 8, 안드로이드 2.3 이상에서 지원됩니다.

    만약 이런 구닥다리 버전까지 지원해야 한다면? Modernizr를 통해 분기점을 만들고 png로 대체하는 등의 방법이 있겠습니다. (그럴 거면 그냥 SVG 안 쓰는 게 나을 거 같기도요...)

     

     

    2) background-image

    .nana {
      width: 300px;
      height: 120px;
      outline: 2px solid red;
      background-image: url("./potion.svg");
    }

     

    이것도 일반적인 이미지처럼 background-image 속성을 이용하는 방법입니다.

    width: 300px; height: 120px; 을 준 상태에서 브라우저를 열어봤더니...

     

     

    높이(120px)에 맞춰 이미지 크기가 줄어든 걸 확인할 수 있습니다.

    반복되는 걸 피하려면 no-repeat를 주거나, background-size를 지정하면 되겠네요.

     

    마찬가지로 IE 8과 안드로이드 2.3 이하 버전은 지원하지 않습니다.

    다만, background-image로 넣는 경우엔 Modernizr를 활용하기가 좀 더 수월합니다.

    .no-svg 같은 클래스를 html에다 붙이고 분기시키면 되거든요.

     

    .nana {
      background: url(nana.svg) no-repeat top left;
      background-size: contain;
    }
    
    
    .no-svg .nana {
      background-image: url(nana.png);
    }

     

    아니면 이렇게 하는 방법도 있습니다.

    SVG를 지원하는 브라우저가 이전 선언을 무시하게 만드는 거죠.

     

    .nanakkli {
      background: url(nana.png);
      background-image: url(nana.svg);
    }

     

    그런데... 이 두 가지 방법(img 태그와 bgimage)에는 아쉬운 점이 하나 있습니다.

    CSS로 SVG 내부를 제어할 수가 없다는 것입니다.

     

    그래서 이 두 가지 방법은, SVG 내부 코드를 제어할 필요가 없지만 이미지는 유연하게 반응형 처리하고 싶다! 할 때 쓰면 되겠습니다.

     

     

     

    3) 인라인

     

    위 2가지 방법 외에는 인라인으로 넣는 방법도 있습니다. HTML 상에 코드를 그대로 넣어주는 거에요.

    장점은 이미지 로드가 필요 없다는 거! 브라우저는 이미지를 불러올 때마다 HTTP 요청을 해야 하는데, 이 경우엔 요청-응답의 필요가 없기 때문에 로드되는 속도가 빠릅니다.

    단점은 HTML이 더러워지고😑 캐싱이 불가능합니다. 그래서 로드될 때마다 HTML내 SVG 코드를 다시 읽어야 해요.

     

    고전시절 브라우저에 대한 지원은 이렇게 합니다.

    fallback이라는 요소를 마크업 해두고, SVG 미지원 브라우저일 때는 png 이미지가 보이게끔 처리하는 방법입니다.

     

    <svg> ... </svg>
    <div class="fallback"></div>
    .fallback { 
      display: none;
    }
    .no-svg .fallback { 
      background-image: url(nana.png); 
    }

     

     

    4) object

     

    또는 object라는 방법도 있어요!

    type이 src가 아닌 data라는 데 주의합시다.

     

    <object type="image/svg+xml" data="./potion.svg" class="nana"></object>

     

    이 방법은 캐싱이 되지만 외부 CSS기능을 쓸 수 없습니다.

    즉, object에 대한 스타일링은 가능하지만, svg 내부 코드는 조작할 수가 없어요.

     

    SVG 파일 자체에 <style>을 박아야만 하죠.

     

    <svg>
      <style>
        .potion1 {
          fill: #ffeb3b;
        }
      </style>
      
      <path class="potion1" d="....."/>
    </svg>

     

    그렇다면 이미 존재하는 SVG의 스타일을 어떻게 바꿔볼 수 있을까요?

    외부 스타일을 꼭 쓰고 싶다면 이렇게 하는 방법도 있습니다.

    우선 HTML에서 외부 스타일시트를 연결하고...

     

    <link rel="stylesheet" href="style.css"/>
    
    <object type="image/svg+xml" data="./potion.svg" class="object"></object>

     

    SVG 파일을 연 다음, 최상단에 아래처럼 외부 CSS를 불러오는 코드를 삽입합니다.

     

    <?xml-stylesheet type="text/css" href="style.css"?> /* 외부 스타일시트 연결 */
    
    <svg>
      <path class="potion1" d="....."/>
      <path class="potion2" d="....."/>
    </svg>

     

    그런 다음 style.css 내부에서 스타일링해줍니다.

     

    .object {
      width: 300px;
      height: 300px;
    }
    
    .svg:hover .potion1 {
      fill: #eddd50;
    }
    
    .svg:hover .potion2 {
      fill: #ccbb23;
    }

     

     

    이 방식은 캐싱이 되고, HTML이 깔끔해지며, SVG 코드 조작이 가능하다는 장점이 있지만

    스타일시트를 한 번 더 연결해야하고, 링크가 안 걸린다는 단점이 있습니다.

    object를 a 태그로 감싸도 링크가 안 걸리거든요.

     

    그럴 땐 svg 코드 내에 a를 넣어주면 됩니다.

     

    <svg>
     <a xlink:href="https://nykim.work" target="_blank">
       <rect x="10" y="10" height="100" width="100"
             style="stroke:#009900; fill: gold"/>
     </a>
    </svg>

     

    아니면 이런 방식도 있어요.

    a태그를 absolute 시키는 방법입니다.

     

    <div class="parent">
      <a href="https://nykim.work">링크 영역</a>
      <object type="image/svg+xml" data="./potion.svg" class="object"></object>
    </div>
    .parent {
      position: relative;
      outline: 2px solid red;
      width: 300px;
      height: 300px;
    }
    
    .parent a {
      display: block;
      position: absolute;
      width: 100%;
      height: 100%;
      color: #fff;
      background: rgba(0, 0, 0, 0.411);
    }

     

     

     

    마지막으로 폴백처리는 이렇게 해주면 됩니다.

    (만약 IE 8 같은 유물을 지원해야 하면 말이죠!)

     

    .no-svg .nana {
      width: 152px;
      height: 152px;
      background-image: url(nana.png);
    }

     

     

    정리하자면 이정도가 되겠네요!

     

    나는 SVG가 필요하지만 이미지에 별다른 조작을 가하지 않을 것이다 👉<img/> 또는 background-image

    나는 SVG가 필요하고 이미지에 조작을 가할 것이다 👉인라인 또는 <object>

     

     

     

     


     

    3. CSS로 SVG 애니메이션 조작하기

     

    사실 우리가 하고 싶은 건 막 푸슝하고 슈숭하고 움직이는 그런 거잖아요?!

    그러니 지나가는 아무 SVG나 붙잡고 제가 한 번 조작해보겠습니다.

     

    저는 여기서 다운받은, 아까 그 포션 SVG를 사용하겠습니다.

    포션 병 근처의 하트가 움직이는 모션을 주려고요 ;)

     

    막 다운받은 SVG 코드는 좀 더럽기 때문에 SVGO 등을 통해 압축해 줍니다.

    웹이라면 SVGOMG를 통해서 손쉽게 압축할 수도 있습니다.

     

    <?xml-stylesheet type="text/css" href="style.css"?>
    <svg xmlns="http://www.w3.org/2000/svg" class="svg" viewBox="0 0 512.001 512.001">
    	<path class="heart1" d="M145.374 31.943c-52.434-58.261-99.042 0-75.739 46.608s75.739 64.086 75.739 64.086 52.434-17.478 75.739-64.086-23.305-104.868-75.739-46.608z" fill="#ffb1bb"/>
    	<path class="heart2" d="M95.189 275.054c-28.686-31.873-54.183 0-41.434 25.498s41.434 35.06 41.434 35.06 28.686-9.561 41.434-35.06c12.749-25.498-12.748-57.371-41.434-25.498z" fill="#ffd8dd"/>
    	<path class="heart3" d="M416.811 146.405c-28.686-31.873-54.183 0-41.434 25.498s41.434 35.06 41.434 35.06 28.686-9.562 41.434-35.06c12.749-25.498-12.749-57.371-41.434-25.498z" fill="#fe6a89"/>
    	<g class="flask-top" fill="#efecf1">
    		<path d="M195.114 158.72h128.649v32.162H195.114z"/>
    		<path d="M426.851 466.796l-127.21-187.469v-88.446h-80.405v88.446L92.024 466.796c-10.868 16.017.605 37.666 19.96 37.666h294.908c19.355 0 30.828-21.65 19.959-37.666z"/>
    	</g>
    	<path d="M243.357 287.368v-56.284c0-8.882 7.199-16.081 16.081-16.081h40.203v-24.122h-80.405v88.446l-48.877 72.03h29.385l43.613-63.989z" fill="#e0dae3"/>
    	<path d="M170.358 351.356l-78.334 115.44 78.334-115.44z" fill="#fe5578"/>
    	<path class="potion1" d="M348.518 351.356h-178.16l-78.334 115.44c-10.868 16.017.605 37.666 19.96 37.666h294.908c19.356 0 30.828-21.65 19.96-37.666l-78.334-115.44z" fill="#fe5578"/>
    	<path class="potion2" d="M137.501 442.674l62.241-91.317h-29.385L92.024 466.796c-10.868 16.017.605 37.666 19.96 37.666h294.908c14.175 0 24.111-11.615 24.15-24.122h-273.58c-19.356 0-30.828-21.65-19.961-37.666z" fill="#fe3f67"/>
    	<path fill="#fe5578" d="M348.518 351.356l78.333 115.44z"/>
    	<path class="flask-heart" d="M259.438 403.702c-28.686-31.873-54.183 0-41.434 25.497 12.749 25.498 41.434 35.06 41.434 35.06s28.686-9.561 41.434-35.06c12.749-25.497-12.749-57.37-41.434-25.497z" fill="#efecf1"/>
    </svg>

     

    그리고 우리가 흔히 하던 것처럼 CSS 애니메이션을 작성합니다.

     

    @keyframes fadeOut {
    
      0% {
        opacity: 1;
        transform: translate3d(0px, 35px, 0);
      }
    
      30% {
        opacity: 1;
      }
    
      100% {
        opacity: 0;
        transform: translate3d(0px, 0px, 0);
      }
    
    }
    
    
    .heart1 {
      animation: fadeOut 1s infinite;
    }
    
    .heart2 {
      animation: fadeOut 1.5s infinite;
    }
    
    .heart3 {
      animation: fadeOut 1.25s infinite;
    }

     

    음.... 막 푸슝하고 피융하는 그런 건 아니지만 아무튼 이미지를 조작할 수 있게 됐습니다! 〔´∇`〕

     

     




    4. JS로 SVG 애니메이션 조작하기

     

    CSS로 조작이 가능하다면, JS로도 물론 가능하겠죠!

    스크롤매직 라이브러리에서도 잘 써먹었던 GSAP을 가져다 써보겠습니다.

     

    한 가지 주의할 점은, 라인 애니메이션을 그리기 위해서는 shape가 아니라 open path여야 한다는 점입니다.

     

    (좌) Shape  / (우) Open path

     

    See the Pen eYOjPYb by NY KIM (@nykim_) on CodePen.

     

     

    잘 움직이네요! 😚

     

    'Study > Web Animation' 카테고리의 다른 글

    [SVG] The Gooey Effect  (0) 2019.09.18
    [SVG] SVG 다루기  (2) 2019.09.16

    댓글 2