SVGでラインアニメーションを作る

今回は、 SVG と CSS でアニメーションを作る方法をご紹介します。

![ここで紹介するやり方を覚えれば Sekappy のロゴ画像をアニメーションさせることも可能です。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676048/fbf5b4e3-18a1-5d61-0626-bcbf5adff3f0.gif "アニメーションする Sekappy ロゴ")

# Step1. 破線を作る

まず簡単に、直線をアニメーションさせるところから始めましょう。SVG で線を引くには `<line>` 要素を使います。

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <style>
        .my-line {
            stroke: #000;
            stroke-width: 3;
            stroke-linecap: round;
        }
    </style>
</head>
 
<body>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 30">
     <line class="my-line" x1="10" y1="18" x2="300" y2="18" />
 </svg>
</body>
</html>
```

上記のコードをブラウザで実行すると、以下の直線が表示されます。

![横方向の実線が表示されるのが分かります。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676048/27dfba37-9567-f0d5-eb88-d5dc8c8e67ab.jpeg "SVG の直線")

この直線に `stroke-dasharray` を指定すると、破線になります。

![横方向の破線が表示されるのが分かります。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676048/01d24bb2-4d98-4d13-026b-52b2849fd647.jpeg "stroke-dasharray を指定した直線")

`stroke-dasharray: 10;` を指定すると、破線の実線部分（黒い部分）、ギャップの部分（白い部分）の長さがそれぞれ `10` になります。

ここから `stroke-dasharray` の値を大きくしていくと、破線の実線 / ギャップの長さも大きくなります。

![試しに stroke-dasharray の値を 50, 100, 200, 300 と大きくしていきます。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676048/d7ae3ac9-25b6-b138-9356-fa49d28fa37f.jpeg "stroke-dasharray の値を大きくしていく")

すると、 `stroke-dasharray: 300;` の時点で元の直線と同じ状態になりました。破線の実線部分の長さが、元の線の長さと一致してしまったのです。

# Step 2. 破線のオフセットを変える

次に、 `stroke-dashoffset` を指定していきます。これは破線の開始位置（オフセット）を変化させるものです。

![stroke-dasharray の値を 300 に固定したまま stroke-dashoffset の値を変えていきます。 0, 100, 200, 290, 300 と増えるに従い直線が短くなっていきます。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676048/90cc56a4-3a10-e13f-ea03-19bc62490bc4.jpeg "stroke-dashoffset の値を大きくしていく")

`stroke-dashoffset: 0;` では**元の直線がそのまま表示**され、`stroke-dashoffset: 300;` では**直線が消えた**のが分かります。

直線の開始位置と破線のギャップの開始位置が一致したので、長さ300のギャップが描画されました。見た目上は直線が消えてしまうのです。

## Step 3. オフセットを変えてアニメーションさせる

先ほどの画像をよく見てください。すでにアニメーションの片鱗が見えているのがわかりますか？ `stroke-dashoffset: 300;` で線が消え、そこから数字を減らしていくと、線がだんだんと描画されています。

では、 CSS アニメーションで `stroke-dashoffset` の値を変えていきましょう。

```css
.animated-line {
    stroke-dasharray: 300;
    stroke-dashoffset: 300;
    animation: line-animation 5s linear infinite;
}

@keyframes line-animation {
    0% {
        stroke-dashoffset: 300;
    }
    25% {
        stroke-dashoffset: 300;
    }
    50% {
        stroke-dashoffset: 0;
    }
    75% {
        stroke-dashoffset: 0;
    }
    100% {
        stroke-dashoffset: 300;
    }
}
```

![SVG で書いた直線に上記の CSS を適用すると、横方向に伸び縮みする直線が表示されます。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676048/86b9e4ad-fc58-c961-35a7-83a79cc6bea8.gif "アニメーションする直線")

おめでとうございます、これで SVG アニメーションが完成しました！

「動いたといっても、ただの直線でしょう？」とお考えの方もいるかも知れませんが、心配無用です。**この原理で複雑な線も動かすことができる**のです。

```html
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 100">
    <path id="my-path"
        class="my-line" fill="transparent"
        d="M10 10 c 10 30, 10 10, 30 10 c 80 -5, 10 50, 90 15 c 120 10, 100 -10, 70 -15 c 150 -10, 50 30, 90 -10"
    />
    <use href="#my-path" class="animated-path" y="50" />
</svg>
```

![上記のSVGではフリーハンドで書いた落書きのような曲線が表示されます。これに先ほどのアニメーションCSSを適用すると、曲線が伸び縮みするようになります。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676048/8fda0f68-2a44-56f1-0bca-fc15e624e97d.gif "アニメーションする複雑な線")

ただの落書きのような線だけではなく、冒頭でご紹介したような会社ロゴも動かすことが可能です。

![以下のサンプルコードを実行すると Sekappy のロゴ画像が表示されたり消えたりするアニメーションが表示されます。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676048/4220d294-72cc-5d26-55c4-25ea84df6dfc.gif "アニメーションする Sekappy ロゴ")

```html
<!DOCTYPE html>
<html lang="ja">
<head>
  <style>
      #logo {
        fill: #fff;
        stroke: #000;
        stroke-width: 1;
        stroke-linecap: round;
      }

      .logo-animated {
        stroke-dasharray: 1000;
        stroke-dashoffset: 1000;
        animation: line-animation 5s linear infinite;
      }

      @keyframes line-animation {
        0%   { stroke-dashoffset: 1000; }
        25%  { stroke-dashoffset: 1000; }
        50%  { stroke-dashoffset: 0; }
        75%  { stroke-dashoffset: 0; }
        100% { stroke-dashoffset: 1000; }
      }
  </style>
</head>

<body>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 327.12 87.02">
  <g id="logo" class="logo-animated">
    <path d="M65.2 48.19c-1.57 0-2.83 1.27-2.83 2.83 0 6.25-5.09 11.34-11.34 11.34s-11.34-5.09-11.34-11.34c0-1.57-1.27-2.83-2.83-2.83s-2.83 1.27-2.83 2.83c0 9.38 7.63 17.01 17.01 17.01 9.38 0 17.01-7.63 17.01-17.01-.02-1.56-1.29-2.83-2.85-2.83zm243.78 19.56H80.64c2.8-4.94 4.4-10.64 4.4-16.72 0-18.79-15.23-34.02-34.02-34.02S17.01 32.24 17.01 51.02c0 6.25 1.69 12.1 4.63 17.13.75 1.04 1.68 1.86 3.32 1.86h7.47c.78 0 1.42-.63 1.42-1.42v-.1c-.02-.18-.13-.64-.77-1.39-.01-.01-.01-.02-.02-.03a24.015 24.015 0 01-6.13-16.06c0-13.31 10.79-24.09 24.09-24.09 13.31 0 24.09 10.79 24.09 24.09 0 6.17-2.32 11.79-6.13 16.06-.01.01-.01.02-.02.03-.64.75-.75 1.21-.77 1.39v.1c0 .78.63 1.42 1.42 1.42h239.37a1.129 1.129 0 100-2.26z"/><path d="M171.25 36.58c-.23-.58-.02-.88.21-1.38l8.05-15.2c.19-.3 0-.61-.31-.61h-7.23c-.38 0-.63.12-.81.48l-7.17 14.8a.32.32 0 01-.28.16c-.12 0-.22-.07-.28-.16V20c0-.36-.25-.61-.62-.61h-6.92c-.38 0-.62.24-.62.61v40.06c0 .36.25.61.62.61h6.92c.38 0 .62-.24.62-.61v-10.3c0-.59.08-1.03.26-1.4l1.92-3.92c.06-.09.16-.16.28-.16.12 0 .22.07.28.16l5.99 15.81c.06.3.25.42.63.42h7.42c.31 0 .5-.3.38-.61l-9.34-23.48zm-57.16-.43l-2.65-.98c-3.43-1.29-4.14-2.28-4.14-5.42 0-2.83 1.1-4.18 3.36-4.18 2.33 0 3.41 1.53 3.49 4.49.01.37.37.57.71.57h6.6c.17 0 .32-.08.42-.21.11-.12.16-.27.16-.47.11-6.26-2.8-11.39-11.65-11.39-7.83 0-11.65 4.06-11.65 11.63 0 6.71 2.14 9.85 8.35 12.13l2.65.98c3.3 1.23 4.08 2.52 4.08 6.22 0 3.82-1.1 4.99-3.5 4.99-2.52 0-3.7-1.61-3.82-5.31 0-.37-.25-.61-.71-.61h-6.92c-.27.01-.54.29-.52.68 0 7.3 2.73 12.26 11.91 12.26 8.74 0 12.17-4.43 12.17-12.99.01-7.1-2.32-10.18-8.34-12.39zm33.45-16.76h-18.52c-.38 0-.62.25-.62.62v40.03c0 .38.25.62.62.62h18.52c.38 0 .62-.25.62-.62v-6.11c0-.37-.25-.62-.62-.62h-10.41a.56.56 0 01-.56-.56v-8.43c0-.31.25-.56.57-.56h8.98c.37 0 .62-.25.62-.62v-6.11c0-.37-.25-.62-.62-.62h-8.98a.56.56 0 01-.56-.56v-8.51c0-.31.25-.56.57-.56h10.41c.38 0 .62-.25.62-.62v-6.11c-.02-.41-.27-.66-.64-.66zm77.97 0h-9.98c-.37 0-.62.25-.62.62v40.03c0 .38.25.62.62.62h6.92c.37 0 .62-.25.62-.62V46.65c0-.31.25-.57.57-.57h1.86c7.55 0 12.47-3.74 12.47-13.34.01-9.67-4.73-13.35-12.46-13.35zm-.25 19.52h-1.61a.57.57 0 01-.57-.57V27.13c0-.31.25-.57.57-.57h1.61c3.18 0 4.55 1.37 4.55 6.17 0 4.81-1.37 6.18-4.55 6.18zm66.68-19.52h-6.77c-.44 0-.65.08-.81.62l-4.37 14.29c-.08.12-.2.2-.35.2s-.27-.08-.35-.2l-4.37-14.29c-.17-.55-.38-.62-.81-.62h-6.77c-.5 0-.71.25-.59.62l8.55 24.25c.1.33.24.88.24 1.48v14.29c0 .38.25.62.63.62h6.93c.38 0 .63-.25.63-.62V45.75c.01-.6.15-1.16.25-1.48l8.55-24.25c.13-.38-.09-.63-.59-.63zm-91.66.61c-.13-.36-.31-.61-.69-.61h-7.36c-.38 0-.56.24-.69.61l-9.23 40.06c-.06.36.13.61.5.61h6.92c.44 0 .62-.24.69-.61l1.35-6.99c.06-.32.35-.48.66-.48h6.96c.31 0 .6.16.66.48l1.35 6.99c.06.36.25.61.69.61h6.92c.38 0 .56-.24.5-.61L200.28 20zm-2.1 26.28h-4.52c-.31 0-.47-.16-.47-.48l2.38-12.35c.08-.12.2-.2.35-.2s.28.08.35.2l2.38 12.35c0 .31-.16.48-.47.48zm54.66-26.89h-9.98c-.37 0-.62.25-.62.62v40.03c0 .38.25.62.62.62h6.92c.37 0 .62-.25.62-.62V46.65c0-.31.25-.57.57-.57h1.86c7.55 0 12.47-3.74 12.47-13.34.01-9.67-4.73-13.35-12.46-13.35zm-.25 19.52h-1.61a.57.57 0 01-.57-.57V27.13c0-.31.25-.57.57-.57h1.61c3.18 0 4.55 1.37 4.55 6.17 0 4.81-1.37 6.18-4.55 6.18z"/>
  </g>
</svg>
</body>
</html>
```

アニメーションさせる画像を変更する場合は `stroke-dasharray` や `stroke-dashoffset` の値を調整する必要があります。線が長くなった分だけ、それらの値を大きくしましょう。

## まとめ

SVG は CSS を使って装飾することが可能です。`stroke-dasharray` や `stroke-dashoffset` を上手く使うと、 CSS だけで面白いアニメーションをすることができます。