vivus.jsで手書きフォントのSVGパスアニメーション

リッチなフォントを使って手書きSVGアニメーションを行います

このサイトの「THOR」というテーマは、有料ですが、高機能で細かい部分の作りこみもしっかりされていて、自分で一から作る手間暇を考えると、時間とお金のない主婦にもとってもお得感抜群なのですが、ブロガー向けとあって、どうしてもトップページデザインがいまいちでした。

なので、トップページのヘッダー部分を変更してみました~。
とりあえず、今時のブロークンな感じで、CSSアニメーションを程よく入れて、・・・んーでもなんか物足りないかなぁ。
そうだ、SVGアニメを入れるか!

というわけで、SVG画像を使って、手書きで文字を書いてるようなアニメーションを入れることに。
ググってみると、単純なSVGパスを使ったアニメーションはCSSのみで実現可能ですが、vivus.jsを使えば、パスが複雑になったり、細かい設定をしたい時も、簡単に実現できることが分かりました。

SVGパスアニメーションの原理

まず、元となるSVGパスアニメーションの原理ですが、以下のようなSVGパス画像とCSSで実現します。

See the Pen ExYMBWR by asuiro (@asuiro) on CodePen.

パスアニメーションに必要なCSSは以下の部分です。

 stroke-dasharray: 661;
 stroke-dashoffset: 661;
 animation: h-path 3s forwards;

 @keyframes h-path {
  0% { stroke-dashoffset: 661; }
  100% { stroke-dashoffset: 0; }
 }

stroke-dasharrayは、線の間隔を指定するプロパティです。
stroke-dasharray:20 10;なら、20pxの線の後に10pxの間隔を空けて、また20pxの線、10pxの間隔・・・という風に指定します。値を一つしか設定しない場合は、その値で等間隔になります。

stroke-dashoffsetは、線の始まりの位置(オフセット)を指定するプロパティです。
stroke-dashoffset:40;なら、40px間隔を空けてから、線が開始されます。

実際の設定値は、stroke-dasharray: 661; stroke-dashoffset: 661; で、この661pxはパスの長さです。
stroke-dasharrayがパスの長さということは、線の長さ=パスの長さで、間隔がない状態、さらに、stroke-dashoffsetもその長さと同じということは、線の開始位置には何もない状態ということです。

@keyframes で、この状態(0%でオフセット661px)から、100%でオフセット0px(線が全部見える状態)まで、3秒かけて変化させる(つまり、ちょっとずつ線が表示される)というのが上記のCSSです。これがSVGパスアニメーションの原理です。
1パスだとすごく簡単なCSSでできますね。でもパスが多数あったり、そのパスの動きをそれぞれ変えたりする場合は、CSSだけだと結構大変です。そこで後述するjavascriptのライブラリ「vivus.js」が便利です。

フォントを使ったSVGパスアニメーション

今回の目的は、トップページを見映えよくすることなので、ただの線画ではなく、ちゃんとしたフォントを使ってかっこよく仕上げたい!と思い、以下のサイトを参考にさせて頂きました。
https://www.willstyle.co.jp/blog/1569/

原理は、手書きフォントのSVG画像の上に、それを覆う太さのSVGパスをかぶせ(マスク)、そのマスクをちょっとずつ見せていく感じです。

SVG画像の準備

1.表示用SVG画像の作成

Ilustratorで手書き風フォントの文字を入力します。
これをアウトライン化し、SVGで保存します。例えば、「font.svg」とします。

2.マスク用SVGパス画像の作成

次にマスク用パス画像を作成します。
1で作った表示用画像の上に新規レイヤーを作成し、ペンツールで文字の大体中央をなぞります。

パスの太さを調整し、下の文字が隠れるようにします。
端っこは、線オプションで先端や、角の形状を丸くするとよいです。

ちゃんと隠れたら、「ウインドウ」-「ドキュメント情報」を開き、パスの長さを調べておきます。

その後文字のレイヤーは消して、パスのレイヤーのみにし、SVGで保存します。
例えば、「font_mask.svg」とします。

SVGデータの編集

マスク用のパス画像(font_mask.svg)をテキストエディタで開きます。

まず、<svg>の上2行は必要ないので消します。

<style>~</style>部分は<head>内に移すか、任意のスタイルシートに記載します。
その際、2で調べたパスの長さ(端数は切り上げてOK)をstroke-dasharrayとstroke-dashoffsetに設定し、追記します。

.st0
{
 fill:none;
 stroke:#FFFFFF;
 stroke-width:12;
 stroke-linecap:round;
 stroke-linejoin:round;
 stroke-miterlimit:10;
 stroke-dasharray: 970;  ←追加
 stroke-dashoffset: 970; ←追加
}

<svg>のidは適当なものに変更し、不要なプロパティを削除します。
<path>部分は、マスクとして使うので、全体を<mask id=”clipmask” maskUnits=”objectBoundingBox”></mask>で囲みます。
<mask>で囲った上部に、今回表示したいフォント画像(font.svg)を<image>で読み込みます。
以上で、SVGデータは以下のようになります。

<svg version=”1.1″ id=”svg_001” xmlns=”http://www.w3.org/2000/svg” xmlns:xlink=”http://www.w3.org/1999/xlink” width=”100%” height=”auto” viewBox=”0 0 500 100″>
<image xmlns:xlink=”http://www.w3.org/1999/xlink” xlink:href=”/img/WebSite.svg” width=”500″ height=”100″ mask=”url(#clipmask)”>
</image>
<mask id=”clipmask” maskUnits=”objectBoundingBox”>
<path class=”st0” d=”M23.16,21.36L11.76,70.2c0,0,3.6,6.48,5.76,4.32s31.44-41.88,32.52-45.48s-8.76,39.72-8.76,39.72
s1.44,6.12,6.12,2.16s34.2-46.08,35.64-46.08s3.96-3.96,6.84-5.04″/>
<path class=”st0“・・・
  :
 (省略)
</mask>
</svg>
※SVG画像を複数使う場合は、<svg>のid、<mask>のid、<path>のclassは、それぞれ変える必要があります。

vivus.jsの設定

vivus.jsの詳細設定は、こちらのページをご覧ください。

今回は、</body>の直前に以下を挿入します。

<script src=”https://cdn.jsdelivr.net/npm/vivus@latest/dist/vivus.min.js”></script>
<script>
new Vivus(‘svg_001’, {type: ‘scenario-sync’,duration: 20,forceRender: false ,animTimingFunction:Vivus.EASE})
</script>

まず、最初にvivus.js本体を読み込みます。
次に個別設定した、Vivusオブジェクトのインスタンスを実行しています。
設定値の意味は下記です。

type: ‘scenario-sync’・・・前のパスが終わったら次のパスが開始(パス毎に時間設定可能)
duration: 20・・・パスの開始から終了までの時間
forceRender: false・・・パスが更新された場合に再レンダリングさせない(パフォーマンス改善)
animTimingFunction:Vivus.EASE・・・タイミング設定をゆっくりに

以上で、こんなアニメーションができました。
デモ

ちなみに、トップページは、文字色を変えて、3連チャンで入れてみました。
vivus.jsには、コールバック関数を呼び出すplayメソッドが用意されていて、1回呼び出す(2連チャン)のはできたのですが、さらに呼び出そうとして(3連チャン)上手くいかなかったため、別の方法(時間差でパスを開始)を使いました。
そもそもSVG画像を3つに分けないで、1つにしておけば、CSSで開始設定できるので、複数行の場合でも画像を一つにする方がよいかもしれません。

(追記)
※IE、Edge
で確認したところ、ページ表示時に文字の先端部分がしばらく表示され、vivus.js開始後に消えていました。
どうやら、CSSの<path>プロパティ stroke-linecap:round;とstroke-linejoin:round;がサポートされていない(もしくはバグ?)のが原因のようですが、文字表示後には、ちゃんと効いているので、vivus.jsである程度カバーしているのかなという感じです。

これ、文字が1行ならさほど気にならないのですが、3行にするとめちゃくちゃ気になるので、回避策をいろいろ試してみたのですが、うまい方法が見つからず、結局、IE、Edgeの場合は、stroke-linecap:round;stroke-linejoin:round; を設定しないようにしました。

【参考:IE、Edge対策】
前述のCSSで説明すると、.st0{}からstroke-linecap:round;stroke-linejoin:round;を抜いて、以下を記述

<?php
$ua = getenv(‘HTTP_USER_AGENT’);
if (strstr($ua, ‘Edge’) || strstr($ua, ‘Trident’) || strstr($ua, ‘MSIE’)){
}
else { ?>
<style type=”text/css”>
.st0 {stroke-linecap:round;stroke-linejoin:round}
</style>
<?php }?>

この設定でページ表示後のゴミみたいな表示はなくなりますが、代わりに文字が微妙にカクります・・
くぅ~、こんな落とし穴があるとは!

結論ですが、こんな対策をせずに、IE、Edgeでもきれいに表示させるには、以下につきますね。
文字を1行にすること(欲張らない!私か・・・)
太過ぎないフォントを使うこと(太いと一瞬見える先端の影響が大きいので)
以上、ご参考まで。

ホームページ制作なら「明日色Web」

集客効果の高いWordPressを使用したホームページの作成、ネットショップ開業支援、Webアプリ作成などを行っています。
愛知県尾張旭市、名古屋市(守山区、名東区他)、瀬戸市、長久手市、春日井市などへご訪問対応致します。
詳しくはこちら