このサイトの「THOR」というテーマは、有料ですが、高機能で細かい部分の作りこみもしっかりされていて、自分で一から作る手間暇を考えると、時間とお金のない主婦にもとってもお得感抜群なのですが、ブロガー向けとあって、どうしてもトップページデザインがいまいちでした。
なので、トップページのヘッダー部分を変更してみました~。
とりあえず、今時のブロークンな感じで、CSSアニメーションを程よく入れて、・・・んーでもなんか物足りないかなぁ。
そうだ、SVGアニメを入れるか!
というわけで、SVG画像を使って、手書きで文字を書いてるようなアニメーションを入れることに。
ググってみると、単純なSVGパスを使ったアニメーションはCSSのみで実現可能ですが、vivus.jsを使えば、パスが複雑になったり、細かい設定をしたい時も、簡単に実現できることが分かりました。
SVGパスアニメーションの原理
まず、元となるSVGパスアニメーションの原理ですが、以下のようなSVGパス画像とCSSで実現します。
See the Pen ExYMBWR by asuiro (@asuiro) on CodePen.
パスアニメーションに必要なCSSは以下の部分です。
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に設定し、追記します。
{
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データは以下のようになります。
<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>
vivus.jsの設定
vivus.jsの詳細設定は、こちらのページをご覧ください。
今回は、</body>の直前に以下を挿入します。
<script>
new Vivus(‘svg_001’, {type: ‘scenario-sync’,duration: 20,forceRender: false ,animTimingFunction:Vivus.EASE})
</script>
まず、最初にvivus.js本体を読み込みます。
次に個別設定した、Vivusオブジェクトのインスタンスを実行しています。
設定値の意味は下記です。
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;を抜いて、以下を記述
$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 }?>
この設定でページ表示後のゴミみたいな表示はなくなりますが、代わりに文字が微妙にカクります・・
くぅ~、こんな落とし穴があるとは!
・文字を1行にすること(欲張らない!私か・・・)
・太過ぎないフォントを使うこと(太いと一瞬見える先端の影響が大きいので)