今回は、SVGとCSSを使って、ペンで書いているような手書き風テキストアニメーションを作成します。
SVGの破線の定義するstroke-dasharray/stroke-dashoffsetプロパティとマスクをかける<mask>タグ・maskプロパティの使い方の理解が今回のポイントです。
手軽に作りたい方は、ライブラリ(vivus)も活用してみてくださいね。
もくじ
完成形
まずは、完成形の確認から始めましょう。
ペンで文字をスラスラと書いているように見えますね。
See the Pen 手書き風テキストアニメーション by Haruna Fujii (@haruna-f) on CodePen.
手順の確認
実装の手順を確認して、実際に作っていきましょう!
SVGで出力した画像にアニメーションを設定して、線を動かしていく仕組みです。
ソースコードの解説
① 画像を作成する
まず初めに、アニメーションさせるテキストの画像を作成します。
今回はAdobe XDを使用しますが、SVGで出力できればデザインソフトはお好みのものでOKです。
①-1. テキスト画像を作成する
テキストツールでアニメーションさせたい文字を入力しましょう。
画線の太いフォントがおすすめです。
テキストのままだと実装の際にフォントファミリーの影響を受けてしまうので、テキストをアウトライン化します。
Adobe XDでは、対象のテキストを選択した状態で、ツールバーから「オブジェクト→パス→パスに変換」を選択するとテキストがアウトライン化されます。

①-2. マスクオブジェクトを作成する
パスツールで書き順に沿って、①-1で作成したテキストをなぞります。
【図①-2-a】のオレンジ色の線がテキストをなぞった線です。
色の指定はCSSで行うので、この段階では色を気にせずに見やすい色で作業してくださいね。

次に、下にあるテキストが隠れるようにマスクオブジェクトのパスを太くします。
うまく隠れない場合は、再度パスも調整しましょう。
ここでは分かりやすいように、パスを透過して紹介しています。

①-3. SVGコードで画像を書き出す
①-1で作成したテキストオブジェクトには「text-path」と名前をつけて、text-pathオブジェクトのみでグループ化します。
グループには「text」と名前をつけておきます。
①-2で作成したマスクオブジェクトには「mask-line」と名前をつけます。
すべてのオブジェクトを選択した状態で、右クリックメニューを表示して「SVGコードのコピー」を選択しましょう。
これで画像の作成と書き出しができました。

書き出したコードは、次の通りです。※ 分かりやすいように改行しています。
<svg xmlns="http://www.w3.org/2000/svg" width="361.142" height="88.518" viewBox="0 0 361.142 88.518">
<g id="text" transform="translate(-87.681 -218.675)">
<path id="text-path"
d="M-166.95-28.6c0,1.7.7,2.9,2.5,2.9s2.6-1.6,2.6-4.2c0-5.4,16.1-17.7,26.6-17.7,1.8,0,3.1.8,3.1,3,0,3.4-3.2,11.4-8.6,23-13.1,2.4-17.4,7.9-17.4,9.7a2.241,2.241,0,0,0,2.2,2.3c1.6,0,1.9-1.5,2.4-2.3.5-.7,3.4-4,11-5.9-3.2,6.2-6.7,12.4-8.7,15.4-1.1,1.6-1.9,2.6-1.9,3.5a2.282,2.282,0,0,0,2.3,2.4c1.2,0,2-1.3,3.4-3.3a198.945,198.945,0,0,0,10.3-19,166.867,166.867,0,0,1,17.7-1.5c-5.7,12.6-9,23.9-9,30.1,0,1.8,2.1,2.9,3.4,2.9s1.3-1.4,1.3-2.3c0-7.4,3.2-17.3,9.5-30.7,4.3.1,7.9.4,10.3.4,2.7,0,3.3-.9,3.3-2.1,0-1.3-1.8-1.6-3.7-1.7-1.6,0-4.5-.2-8.2-.2,6.6-13,12.5-21.8,15-24.2,2-1.9,3.4-2.6,3.4-4a2.361,2.361,0,0,0-2.4-2.4c-.9,0-2.2.7-3.7,2.4-3.9,4.7-9.8,13.1-17.5,28.3a173.663,173.663,0,0,0-17.7,1.5c4.7-9.8,8.3-18.9,8.3-22.8s-2.9-7.1-6.3-7.1C-146.65-52.2-166.95-37.7-166.95-28.6Zm62.3,25.7a2.894,2.894,0,0,1-3-3c0-1,.1-1.6,1.9-2,6.2-1.4,14.9-7.2,14.9-12.3,0-1.9-2.2-3.5-4.1-3.5-5.1,0-11.8,3.8-15.9,13.3a3.007,3.007,0,0,0-1.7,2.4c0,1,.3,1.3.3,2.3,0,3.2,2.9,6.4,6,6.4,11.1,0,19.3-8.9,24.1-14.6,1.1-1.4,1.5-2,1.5-2.9a1.263,1.263,0,0,0-1.4-1.4c-1,0-1.9,1-3.1,2.5C-88.75-10.9-95.85-2.9-104.65-2.9Zm8.5-16.9c.8,0,1.2.2,1.2,1,0,2.1-7.9,7.7-11.4,7.8C-104.85-13.4-99.25-19.8-96.15-19.8Zm16.9,16.7c-2.2,0-3.3-1.8-3.3-4.7a27.4,27.4,0,0,1,3.2-10.7c4.4-3.5,9.1-6.8,15.6-15,7.2-9.2,8.8-15.3,8.8-18.2a4.39,4.39,0,0,0-3.9-4.1c-5.6,0-10.1,5.1-16.1,15.4-5.7,9.8-12.2,25.2-12.2,33.7A7.3,7.3,0,0,0-79.95.6c5.7,0,14.4-8.8,19.1-14.5,1.2-1.4,1.6-2,1.6-2.9a1.312,1.312,0,0,0-1.4-1.4c-1.1,0-1.9,1-3.1,2.5C-67.35-10.9-74.95-3.1-79.25-3.1Zm18.4-48.1c1,0,1.5.4,1.5,1.4,0,2.4-1.2,5.4-7.1,13.5-5.4,7.3-10.4,11.7-11.7,12.3.3-1.6,1.5-5.8,6.8-15.1C-66.25-48.4-62.15-51.2-60.85-51.2Zm3.6,48.1c-2.2,0-3.3-1.8-3.3-4.7a27.4,27.4,0,0,1,3.2-10.7c4.4-3.5,9.1-6.8,15.6-15,7.2-9.2,8.8-15.3,8.8-18.2a4.39,4.39,0,0,0-3.9-4.1c-5.6,0-10.1,5.1-16.1,15.4-5.7,9.8-12.2,25.2-12.2,33.7A7.3,7.3,0,0,0-57.95.6c5.7,0,14.4-8.8,19.1-14.5,1.2-1.4,1.6-2,1.6-2.9a1.312,1.312,0,0,0-1.4-1.4c-1.1,0-1.9,1-3.1,2.5C-45.35-10.9-52.95-3.1-57.25-3.1Zm18.4-48.1c1,0,1.5.4,1.5,1.4,0,2.4-1.2,5.4-7.1,13.5-5.4,7.3-10.4,11.7-11.7,12.3.3-1.6,1.5-5.8,6.8-15.1C-44.25-48.4-40.15-51.2-38.85-51.2Zm15.3,33.1c0-3.5-2.1-5.8-5.8-5.8-7,0-14.8,8.9-14.8,18.2,0,4.3,2.8,6.4,5.6,6.4C-29.65.7-23.55-11.6-23.55-18.1Zm-6.4-1.3a.265.265,0,0,1,.3.3,19.47,19.47,0,0,0-.3,2.2c0,1.3,1.5,1.8,1.5,2.1,0,3-5.1,12-9,12a2.651,2.651,0,0,1-2.5-2.9C-39.95-12.2-34.25-19.4-29.95-19.4Zm19-2.9c0,2.3,1.4,3.2,2.6,3.2,1.5,0,2.2-1.6,2.2-3.8,0-10,20.3-23.9,30.3-23.9,2.5,0,3.7,1.5,3.7,4.3,0,3.5-7.4,19.5-12.8,29.6C11.75-6.5,8.15-.2,8.15,1.9c0,2.2,1,3.6,2.4,3.6s4.2-3.4,6.5-5.7c9-9,19.3-19.1,23.8-23.8a60.788,60.788,0,0,0-3.2,17.9c0,4.4,1.9,8.8,5.7,8.8,10.1,0,26.2-21.2,26.2-47.3,0-6.3-3.3-10.1-5.9-10.1a2.652,2.652,0,0,0-2.8,2.9c0,2.8,4.4,2.1,4.4,8.7,0,20.9-13.9,41.4-19.8,41.4-2,0-2.9-1.7-2.9-5.7,0-10.5,6.7-23.7,6.7-25.4s-.9-2.4-2.2-2.4-2.2,1.3-4.4,3.9c-8.2,9.6-17.4,16.6-25.9,25.4,7.4-13,16-32,16-37.6a7.189,7.189,0,0,0-7.3-7.2C12.85-50.7-10.95-35-10.95-22.3Zm91-1.6c-7,0-14.8,8.9-14.8,18.2,0,4.3,2.8,6.4,5.6,6.4,7,0,11.6-7.9,13.7-13.9a23.225,23.225,0,0,0,8.7-1.7c3.3-1.5,4.6-2.7,4.6-3.7a1.71,1.71,0,0,0-1.8-1.7c-1,0-4.9,2.8-9,2.8-1.6,0-1.6-2.3-1.6-3.1C85.45-22.1,83.75-23.9,80.05-23.9Zm-.6,4.5a.265.265,0,0,1,.3.3,19.47,19.47,0,0,0-.3,2.2c0,1.3,1.5,1.8,1.5,2.1,0,3-5.1,12-9,12a2.651,2.651,0,0,1-2.5-2.9C69.45-12.2,75.15-19.4,79.45-19.4Zm18.4-4.7c-1.4,0-2.1,1.2-2.8,3.6a86.11,86.11,0,0,1-3.6,9.6c-1.5,3.7-3.1,8-3.1,9.1A2.759,2.759,0,0,0,90.65.5c.9,0,2.7-5.8,5-9.4,3.2-5,9.8-11.4,11.2-11.4.6,0,.9.3.9.7,0,.5-.7,1.7-.7,2.7a1.965,1.965,0,0,0,1.9,1.9c2.5,0,3.5-2.9,3.5-6a3.381,3.381,0,0,0-3.6-3.5c-2.5,0-5.4,2.2-9.1,6.1-.5.5-.8.8-1.2.8-.2,0-.2-.1-.2-.3,0-.9,1.4-3.5,1.4-4.7A1.79,1.79,0,0,0,97.85-24.1Zm23.1,21c-2.2,0-3.3-1.8-3.3-4.7a27.4,27.4,0,0,1,3.2-10.7c4.4-3.5,9.1-6.8,15.6-15,7.2-9.2,8.8-15.3,8.8-18.2a4.39,4.39,0,0,0-3.9-4.1c-5.6,0-10.1,5.1-16.1,15.4-5.7,9.8-12.2,25.2-12.2,33.7a7.3,7.3,0,0,0,7.2,7.3c5.7,0,14.4-8.8,19.1-14.5,1.2-1.4,1.6-2,1.6-2.9a1.312,1.312,0,0,0-1.4-1.4c-1.1,0-1.9,1-3.1,2.5C132.85-10.9,125.25-3.1,120.95-3.1Zm18.4-48.1c1,0,1.5.4,1.5,1.4,0,2.4-1.2,5.4-7.1,13.5-5.4,7.3-10.4,11.7-11.7,12.3.3-1.6,1.5-5.8,6.8-15.1C133.95-48.4,138.05-51.2,139.35-51.2Zm14.1,29.4c-.5,0-2-1.8-5.7-1.8-6.5,0-16.4,11.9-16.4,19.1a5.173,5.173,0,0,0,5,5.5c3.4,0,9.5-3.5,14-9.1v2.2c0,4,.7,9.8,5.2,9.8,2,0,3.6-1.1,3.6-1.9,0-.5-.7-.7-1.6-.8-2.8-.7-2.9-6-2.9-8.4a17,17,0,0,1,1.3-7.1c1.2-2.4,8.3-8.6,15-19.3,5.6-9,6.5-13.8,6.5-16.6s-1.6-4.8-4.4-4.8c-3.5,0-8.2,3.9-12.4,12.8A101.6,101.6,0,0,0,153.45-21.8Zm19-29.5c1.1.1,1.1,1.1,1.1,1.9,0,2.9-1.1,5.7-5.5,13.5a78.48,78.48,0,0,1-10.7,14.7s2.3-10.8,6.6-19.3S171.45-51.3,172.45-51.3Zm-24.7,31.8a2.08,2.08,0,0,1,2.2,1.7,1.455,1.455,0,0,0,1.5,1.4c.1,2.5-10,13.2-13.4,13.2a2.2,2.2,0,0,1-2.3-2.3C135.75-9.3,143.05-19.2,147.75-19.5Z" transform="translate(270 289)"
fill="#404040"
/>
</g>
<path id="mask-line"
d="M105.459,264.2s-2.6-8.594,11.519-18.185,19.5-7.959,22.688-5.122-7.921,27.159-7.921,27.159l-17.662,30.616S74.25,249.4,98.23,232.066s78.73.743,78.73.743A135.4,135.4,0,0,0,154.87,264.2a113.133,113.133,0,0,0-11.452,39.318s-24.753,3.321-32.718-2.6,1.433-20.645,1.433-20.645,1.031-5.828,11.488-10.048,43.692-3.019,43.692-3.019l-9.547,3.758s-3.612,7.186.874,9.309,22.621-7.528,18.321-12.218-22.683,10.5-15.559,18.062c2.586,2.744,14.97,2.686,25.763-15.154,14.013-10.016,31.393-32.047,24.513-35.49-10.8-5.406-33.071,46.722-23.6,51.843,3.893,2.1,14.15-5.8,24.811-19.262,13.432-10.142,27.2-28.512,19.8-32.581S199.709,281.7,209.419,287.31c6.25,3.608,15.409-8.29,15.409-8.29s-4.059-8.261,1.341-12.921,20.261-5.72,20.261-5.72-6.586,13.721-3.636,11.482,0-4.662,0-4.662-8.547.928-11.739,5.956-4.247,10.438-2.069,12.956,7.091.978,10.782-2.884,5.022-11.365,5.022-11.365,6.167,3.458,10.368,3.232,6.438-4.137,6.438-4.137-2.925-11.134,11.635-21.607,22.314-11.21,26.514-6.28-19.986,48.375-19.986,48.375v1.1L317.183,256.3s-12.787,25.665-4.567,32.837c7.167.911,15.59-5.156,22.8-28.763s-5.369-25.331-5.369-25.331.223-24.62,14.711-7.662,3.475,48.4,7.159,44.476-.784-5.418-.784-5.418-7.958,1.67-11.152,6.865-4.189,11.964-1.625,13.915,8.26.428,11.882-6.112,3.714-11.612,3.714-11.612l-2.818,1.1s-1.59.743,3.71,2.707,12.784-3.268,12.882-6.865-7.833,21.779-7.833,21.779a26.674,26.674,0,0,1,8.283-14.459c7.124-6.465,9.793-8.159,11.684-6.775s-5.542,14.679-6.111,11.951c11.107-1.877,47.512-36.2,38.166-42.162s-32.177,44.79-25.733,49.439,14.643-4.406,14.643-4.406,1.425-18.267,7.088-23.631,13.273,2.992,13.273,2.992-2.025,12.25,0,9-1.45-2.8-3.663-2.752-7.978,3.283-11.24,8.5-4.567,9.637-.74,11.845,13.453-6.821,23.938-19.659,21.083-28.6,14.571-32.136-15.684,18.947-19.913,35.814.019,23.281,10.1,18.919" transform="translate(-87.681 -218.675)"
fill="none"
stroke="#dba892"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="5.5"
/>
</svg>
② CSSでスタイルを指定する
①で書き出したSVGコードをhtmlに貼り付けましょう。
今回は、CSSファイルでスタイルを指定していくので、各タグにclass属性を追加しつつ、インラインで指定されているパスのスタイルに関わる属性をCSSファイルに書き写していきます。
HTMLファイル
- class属性の追加
- svgタグ:handwritingText
- pathタグ(#text-path):handwritingText__textPath
- pathタグ(#mask-line):handwritingText__maskLine
- 不要な属性の削除
- svgタグ:width/heightを削除
- #text-path:fill属性を削除して、CSSに書き写す
- #mask-line:fill / stroke / stroke-linecap / stroke-linejoin / stroke-width属性を削除して、CSSに書き写す
<div class="block">
<svg class="handwritingText" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 361.142 88.518">
<g id="text" transform="translate(-87.681 -218.675)">
<path id="text-path"
class="handwritingText__textPath"
d="M-166.95-28.6c0,1.7.7,2.9,2.5,2.9s2.6-1.6,2.6-4.2c0-5.4,16.1-17.7,26.6-17.7,1.8,0,3.1.8,3.1,3,0,3.4-3.2,11.4-8.6,23-13.1,2.4-17.4,7.9-17.4,9.7a2.241,2.241,0,0,0,2.2,2.3c1.6,0,1.9-1.5,2.4-2.3.5-.7,3.4-4,11-5.9-3.2,6.2-6.7,12.4-8.7,15.4-1.1,1.6-1.9,2.6-1.9,3.5a2.282,2.282,0,0,0,2.3,2.4c1.2,0,2-1.3,3.4-3.3a198.945,198.945,0,0,0,10.3-19,166.867,166.867,0,0,1,17.7-1.5c-5.7,12.6-9,23.9-9,30.1,0,1.8,2.1,2.9,3.4,2.9s1.3-1.4,1.3-2.3c0-7.4,3.2-17.3,9.5-30.7,4.3.1,7.9.4,10.3.4,2.7,0,3.3-.9,3.3-2.1,0-1.3-1.8-1.6-3.7-1.7-1.6,0-4.5-.2-8.2-.2,6.6-13,12.5-21.8,15-24.2,2-1.9,3.4-2.6,3.4-4a2.361,2.361,0,0,0-2.4-2.4c-.9,0-2.2.7-3.7,2.4-3.9,4.7-9.8,13.1-17.5,28.3a173.663,173.663,0,0,0-17.7,1.5c4.7-9.8,8.3-18.9,8.3-22.8s-2.9-7.1-6.3-7.1C-146.65-52.2-166.95-37.7-166.95-28.6Zm62.3,25.7a2.894,2.894,0,0,1-3-3c0-1,.1-1.6,1.9-2,6.2-1.4,14.9-7.2,14.9-12.3,0-1.9-2.2-3.5-4.1-3.5-5.1,0-11.8,3.8-15.9,13.3a3.007,3.007,0,0,0-1.7,2.4c0,1,.3,1.3.3,2.3,0,3.2,2.9,6.4,6,6.4,11.1,0,19.3-8.9,24.1-14.6,1.1-1.4,1.5-2,1.5-2.9a1.263,1.263,0,0,0-1.4-1.4c-1,0-1.9,1-3.1,2.5C-88.75-10.9-95.85-2.9-104.65-2.9Zm8.5-16.9c.8,0,1.2.2,1.2,1,0,2.1-7.9,7.7-11.4,7.8C-104.85-13.4-99.25-19.8-96.15-19.8Zm16.9,16.7c-2.2,0-3.3-1.8-3.3-4.7a27.4,27.4,0,0,1,3.2-10.7c4.4-3.5,9.1-6.8,15.6-15,7.2-9.2,8.8-15.3,8.8-18.2a4.39,4.39,0,0,0-3.9-4.1c-5.6,0-10.1,5.1-16.1,15.4-5.7,9.8-12.2,25.2-12.2,33.7A7.3,7.3,0,0,0-79.95.6c5.7,0,14.4-8.8,19.1-14.5,1.2-1.4,1.6-2,1.6-2.9a1.312,1.312,0,0,0-1.4-1.4c-1.1,0-1.9,1-3.1,2.5C-67.35-10.9-74.95-3.1-79.25-3.1Zm18.4-48.1c1,0,1.5.4,1.5,1.4,0,2.4-1.2,5.4-7.1,13.5-5.4,7.3-10.4,11.7-11.7,12.3.3-1.6,1.5-5.8,6.8-15.1C-66.25-48.4-62.15-51.2-60.85-51.2Zm3.6,48.1c-2.2,0-3.3-1.8-3.3-4.7a27.4,27.4,0,0,1,3.2-10.7c4.4-3.5,9.1-6.8,15.6-15,7.2-9.2,8.8-15.3,8.8-18.2a4.39,4.39,0,0,0-3.9-4.1c-5.6,0-10.1,5.1-16.1,15.4-5.7,9.8-12.2,25.2-12.2,33.7A7.3,7.3,0,0,0-57.95.6c5.7,0,14.4-8.8,19.1-14.5,1.2-1.4,1.6-2,1.6-2.9a1.312,1.312,0,0,0-1.4-1.4c-1.1,0-1.9,1-3.1,2.5C-45.35-10.9-52.95-3.1-57.25-3.1Zm18.4-48.1c1,0,1.5.4,1.5,1.4,0,2.4-1.2,5.4-7.1,13.5-5.4,7.3-10.4,11.7-11.7,12.3.3-1.6,1.5-5.8,6.8-15.1C-44.25-48.4-40.15-51.2-38.85-51.2Zm15.3,33.1c0-3.5-2.1-5.8-5.8-5.8-7,0-14.8,8.9-14.8,18.2,0,4.3,2.8,6.4,5.6,6.4C-29.65.7-23.55-11.6-23.55-18.1Zm-6.4-1.3a.265.265,0,0,1,.3.3,19.47,19.47,0,0,0-.3,2.2c0,1.3,1.5,1.8,1.5,2.1,0,3-5.1,12-9,12a2.651,2.651,0,0,1-2.5-2.9C-39.95-12.2-34.25-19.4-29.95-19.4Zm19-2.9c0,2.3,1.4,3.2,2.6,3.2,1.5,0,2.2-1.6,2.2-3.8,0-10,20.3-23.9,30.3-23.9,2.5,0,3.7,1.5,3.7,4.3,0,3.5-7.4,19.5-12.8,29.6C11.75-6.5,8.15-.2,8.15,1.9c0,2.2,1,3.6,2.4,3.6s4.2-3.4,6.5-5.7c9-9,19.3-19.1,23.8-23.8a60.788,60.788,0,0,0-3.2,17.9c0,4.4,1.9,8.8,5.7,8.8,10.1,0,26.2-21.2,26.2-47.3,0-6.3-3.3-10.1-5.9-10.1a2.652,2.652,0,0,0-2.8,2.9c0,2.8,4.4,2.1,4.4,8.7,0,20.9-13.9,41.4-19.8,41.4-2,0-2.9-1.7-2.9-5.7,0-10.5,6.7-23.7,6.7-25.4s-.9-2.4-2.2-2.4-2.2,1.3-4.4,3.9c-8.2,9.6-17.4,16.6-25.9,25.4,7.4-13,16-32,16-37.6a7.189,7.189,0,0,0-7.3-7.2C12.85-50.7-10.95-35-10.95-22.3Zm91-1.6c-7,0-14.8,8.9-14.8,18.2,0,4.3,2.8,6.4,5.6,6.4,7,0,11.6-7.9,13.7-13.9a23.225,23.225,0,0,0,8.7-1.7c3.3-1.5,4.6-2.7,4.6-3.7a1.71,1.71,0,0,0-1.8-1.7c-1,0-4.9,2.8-9,2.8-1.6,0-1.6-2.3-1.6-3.1C85.45-22.1,83.75-23.9,80.05-23.9Zm-.6,4.5a.265.265,0,0,1,.3.3,19.47,19.47,0,0,0-.3,2.2c0,1.3,1.5,1.8,1.5,2.1,0,3-5.1,12-9,12a2.651,2.651,0,0,1-2.5-2.9C69.45-12.2,75.15-19.4,79.45-19.4Zm18.4-4.7c-1.4,0-2.1,1.2-2.8,3.6a86.11,86.11,0,0,1-3.6,9.6c-1.5,3.7-3.1,8-3.1,9.1A2.759,2.759,0,0,0,90.65.5c.9,0,2.7-5.8,5-9.4,3.2-5,9.8-11.4,11.2-11.4.6,0,.9.3.9.7,0,.5-.7,1.7-.7,2.7a1.965,1.965,0,0,0,1.9,1.9c2.5,0,3.5-2.9,3.5-6a3.381,3.381,0,0,0-3.6-3.5c-2.5,0-5.4,2.2-9.1,6.1-.5.5-.8.8-1.2.8-.2,0-.2-.1-.2-.3,0-.9,1.4-3.5,1.4-4.7A1.79,1.79,0,0,0,97.85-24.1Zm23.1,21c-2.2,0-3.3-1.8-3.3-4.7a27.4,27.4,0,0,1,3.2-10.7c4.4-3.5,9.1-6.8,15.6-15,7.2-9.2,8.8-15.3,8.8-18.2a4.39,4.39,0,0,0-3.9-4.1c-5.6,0-10.1,5.1-16.1,15.4-5.7,9.8-12.2,25.2-12.2,33.7a7.3,7.3,0,0,0,7.2,7.3c5.7,0,14.4-8.8,19.1-14.5,1.2-1.4,1.6-2,1.6-2.9a1.312,1.312,0,0,0-1.4-1.4c-1.1,0-1.9,1-3.1,2.5C132.85-10.9,125.25-3.1,120.95-3.1Zm18.4-48.1c1,0,1.5.4,1.5,1.4,0,2.4-1.2,5.4-7.1,13.5-5.4,7.3-10.4,11.7-11.7,12.3.3-1.6,1.5-5.8,6.8-15.1C133.95-48.4,138.05-51.2,139.35-51.2Zm14.1,29.4c-.5,0-2-1.8-5.7-1.8-6.5,0-16.4,11.9-16.4,19.1a5.173,5.173,0,0,0,5,5.5c3.4,0,9.5-3.5,14-9.1v2.2c0,4,.7,9.8,5.2,9.8,2,0,3.6-1.1,3.6-1.9,0-.5-.7-.7-1.6-.8-2.8-.7-2.9-6-2.9-8.4a17,17,0,0,1,1.3-7.1c1.2-2.4,8.3-8.6,15-19.3,5.6-9,6.5-13.8,6.5-16.6s-1.6-4.8-4.4-4.8c-3.5,0-8.2,3.9-12.4,12.8A101.6,101.6,0,0,0,153.45-21.8Zm19-29.5c1.1.1,1.1,1.1,1.1,1.9,0,2.9-1.1,5.7-5.5,13.5a78.48,78.48,0,0,1-10.7,14.7s2.3-10.8,6.6-19.3S171.45-51.3,172.45-51.3Zm-24.7,31.8a2.08,2.08,0,0,1,2.2,1.7,1.455,1.455,0,0,0,1.5,1.4c.1,2.5-10,13.2-13.4,13.2a2.2,2.2,0,0,1-2.3-2.3C135.75-9.3,143.05-19.2,147.75-19.5Z" transform="translate(270 289)"
/>
</g>
<path id="mask-line"
d="M105.459,264.2s-2.6-8.594,11.519-18.185,19.5-7.959,22.688-5.122-7.921,27.159-7.921,27.159l-17.662,30.616S74.25,249.4,98.23,232.066s78.73.743,78.73.743A135.4,135.4,0,0,0,154.87,264.2a113.133,113.133,0,0,0-11.452,39.318s-24.753,3.321-32.718-2.6,1.433-20.645,1.433-20.645,1.031-5.828,11.488-10.048,43.692-3.019,43.692-3.019l-9.547,3.758s-3.612,7.186.874,9.309,22.621-7.528,18.321-12.218-22.683,10.5-15.559,18.062c2.586,2.744,14.97,2.686,25.763-15.154,14.013-10.016,31.393-32.047,24.513-35.49-10.8-5.406-33.071,46.722-23.6,51.843,3.893,2.1,14.15-5.8,24.811-19.262,13.432-10.142,27.2-28.512,19.8-32.581S199.709,281.7,209.419,287.31c6.25,3.608,15.409-8.29,15.409-8.29s-4.059-8.261,1.341-12.921,20.261-5.72,20.261-5.72-6.586,13.721-3.636,11.482,0-4.662,0-4.662-8.547.928-11.739,5.956-4.247,10.438-2.069,12.956,7.091.978,10.782-2.884,5.022-11.365,5.022-11.365,6.167,3.458,10.368,3.232,6.438-4.137,6.438-4.137-2.925-11.134,11.635-21.607,22.314-11.21,26.514-6.28-19.986,48.375-19.986,48.375v1.1L317.183,256.3s-12.787,25.665-4.567,32.837c7.167.911,15.59-5.156,22.8-28.763s-5.369-25.331-5.369-25.331.223-24.62,14.711-7.662,3.475,48.4,7.159,44.476-.784-5.418-.784-5.418-7.958,1.67-11.152,6.865-4.189,11.964-1.625,13.915,8.26.428,11.882-6.112,3.714-11.612,3.714-11.612l-2.818,1.1s-1.59.743,3.71,2.707,12.784-3.268,12.882-6.865-7.833,21.779-7.833,21.779a26.674,26.674,0,0,1,8.283-14.459c7.124-6.465,9.793-8.159,11.684-6.775s-5.542,14.679-6.111,11.951c11.107-1.877,47.512-36.2,38.166-42.162s-32.177,44.79-25.733,49.439,14.643-4.406,14.643-4.406,1.425-18.267,7.088-23.631,13.273,2.992,13.273,2.992-2.025,12.25,0,9-1.45-2.8-3.663-2.752-7.978,3.283-11.24,8.5-4.567,9.637-.74,11.845,13.453-6.821,23.938-19.659,21.083-28.6,14.571-32.136-15.684,18.947-19.913,35.814.019,23.281,10.1,18.919" transform="translate(-87.681 -218.675)"
/>
</svg>
</div>
CSSファイル
- .handwritingText
- width/heightを指定
- .handwritingText__textPath
- fillで描画色を指定
- .handwritingText__maskLine
- #mask-lineのfill /stroke / stroke-linecap / stroke-linejoin / stroke-width属性を書き写す
.handwritingText {
width: 100%;
height: auto;
&__textPath {
fill: #404040;
}
&__maskLine {
fill: none;
stroke: #DBA892;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 5.5;
}
}
この段階のプレビューは、マスクが上に重なってテキストが隠れた状態になっていればOKです。

③ アニメーションの仕組みを理解する
実装の前にアニメーションの仕組みを確認しておきましょう。
1000pxの長さの直線を例に解説していきます。

③-1. stroke-dasharrayプロパティ
stroke-dasharrayプロパティは、破線の間隔を指定します。
1000pxの直線に「stroke-dasharray: 200px;」と指定すると【③-1-a】のように200pxおきに線が描画されます。

直線いっぱいに描画ラインを作成したい場合は、stroke-dasharrayの値に直線の長さと同じ「1000px」と指定します。【③-1-b】

③-2. stroke-dashoffsetプロパティ
stroke-dashoffsetプロパティは、破線のスタート位置を指定します。
【③-1-b】の直線に「stroke-dashoffset: 400px;」と指定すると【③-2-a】のように、描画ラインが400px分マイナス方向に移動し、元の直線からはみ出た部分は見えなくなります。

直線の長さと同じ「1000px」をstroke-offsetに指定すると、1000px分マイナス方向に移動するので、描画ラインは見えない状態になります。

animationプロパティを使ってstroke-offsetの値を「2000px」から「0px」に変化させ、描画ラインを見えない状態から右方向に移動することで、線が描かれているように見えるのが手書き風アニメーションの仕組みです。

④ アニメーションを追加する
では、描画ラインとなるmask-line要素(.handwritingText__maskLineセレクタ)にアニメーションを追加していきましょう。
④-1. 描画ラインを作成する
.handwritingText__maskLineセレクタにstroke-dasharrayを指定して、描画ラインを作成します。
描画ラインの長さが分からないので、ひとまず「500px」と指定すると【④-1】のようになりました。
まだ長さが足りないようなので、要素全体に線が描画されるようにstroke-dasharrayの値を少しずつ値を大きくしていきましょう。

「stroke-dasharray: 2000px」で要素全体に線が描画されました。
【④-1-b】のようにプレビューが表示されていれば、OKです。

④-2. 描画ラインのスタート位置を指定する
描画ラインの長さと同じ分だけスタート位置をマイナス方向に移動させておきます。
描画ラインの長さは④-1でstroke-dasharrayに指定した「2000px」となるので、stroke-offsetの値にも「2000px」と指定しましょう。
ここまでのコードは、次の通りです。
.handwritingText {
width: 100%;
height: auto;
&__textPath {
fill: #404040;
}
&__maskLine {
fill: none;
stroke: #DBA892;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 5.5;
// ④-1. 描画ラインを作成する
stroke-dasharray: 2000px;
// ④-2. 描画ラインのスタート位置を指定する
stroke-offset: 2000px;
}
}
④-3. 描画ラインを動かす
まずは、@keyframesにアニメーションでどのように変化させるかを設定します。
描画ラインのスタート位置を動かすことで線が描かれているように表現するので、stroke-offsetを2000pxから0pxに変化するようにプロパティを指定しましょう。
アニメーション開始時点の0%は「stroke-offset: 2000px」、終了時点の100%は「stroke-offset: 0px」となります。
@keyframesの名前は「handwriting」としました。
// ④-3. アニメーションの設定
@keyframes handwriting {
0% {
stroke-offset: 2000px;
}
100% {
stroke-offset: 0px;
}
}
次に@keyframesで設定したアニメーションを実行します。
.handwritingText__maskLineセレクタにanimationプロパティで必要な値を指定して、描画ラインを動かしましょう。
.handwritingText {
〜省略〜
&__maskLine {
fill: none;
〜省略〜
// ④-3. アニメーションの実行
animation: handwriting 3s ease-out infinite;
}
}
この時点で、次のようにプレビューが表示されていれば、OKです。
⑤ テキストの形にマスクする
マスクオブジェクトを背景オブジェクトの形に切り抜いて、描画ラインの不要な部分が表示されないようにしていきます。
ここでは「#mask-line」要素がマスクオブジェクト、「#text」要素が背景オブジェクトととなります。
まず、マスクオブジェクトを<mask>タグで囲みます。
「#mask-line」要素がマスクオブジェクトなので、<path id=”mask-line” ….. />を<mask>タグで囲み、<mask>タグに「id=”mask”」と指定しておきます。
<div class="container">
<div class="block">
<svg class="handwritingText" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 361.142 88.518">
<g transform="translate(-87.681 -218.675)">
<g id="text">
<path id="text-path" class="handwritingText__textPath" d="M-166.95-28.6c0,1.7.7,2.9,2.5,2.9s2.6-1.6,2.6-4.2c0-5.4,16.1-17.7,26.6-17.7,1.8,0,3.1.8,3.1,3,0,3.4-3.2,11.4-8.6,23-13.1,2.4-17.4,7.9-17.4,9.7a2.241,2.241,0,0,0,2.2,2.3c1.6,0,1.9-1.5,2.4-2.3.5-.7,3.4-4,11-5.9-3.2,6.2-6.7,12.4-8.7,15.4-1.1,1.6-1.9,2.6-1.9,3.5a2.282,2.282,0,0,0,2.3,2.4c1.2,0,2-1.3,3.4-3.3a198.945,198.945,0,0,0,10.3-19,166.867,166.867,0,0,1,17.7-1.5c-5.7,12.6-9,23.9-9,30.1,0,1.8,2.1,2.9,3.4,2.9s1.3-1.4,1.3-2.3c0-7.4,3.2-17.3,9.5-30.7,4.3.1,7.9.4,10.3.4,2.7,0,3.3-.9,3.3-2.1,0-1.3-1.8-1.6-3.7-1.7-1.6,0-4.5-.2-8.2-.2,6.6-13,12.5-21.8,15-24.2,2-1.9,3.4-2.6,3.4-4a2.361,2.361,0,0,0-2.4-2.4c-.9,0-2.2.7-3.7,2.4-3.9,4.7-9.8,13.1-17.5,28.3a173.663,173.663,0,0,0-17.7,1.5c4.7-9.8,8.3-18.9,8.3-22.8s-2.9-7.1-6.3-7.1C-146.65-52.2-166.95-37.7-166.95-28.6Zm62.3,25.7a2.894,2.894,0,0,1-3-3c0-1,.1-1.6,1.9-2,6.2-1.4,14.9-7.2,14.9-12.3,0-1.9-2.2-3.5-4.1-3.5-5.1,0-11.8,3.8-15.9,13.3a3.007,3.007,0,0,0-1.7,2.4c0,1,.3,1.3.3,2.3,0,3.2,2.9,6.4,6,6.4,11.1,0,19.3-8.9,24.1-14.6,1.1-1.4,1.5-2,1.5-2.9a1.263,1.263,0,0,0-1.4-1.4c-1,0-1.9,1-3.1,2.5C-88.75-10.9-95.85-2.9-104.65-2.9Zm8.5-16.9c.8,0,1.2.2,1.2,1,0,2.1-7.9,7.7-11.4,7.8C-104.85-13.4-99.25-19.8-96.15-19.8Zm16.9,16.7c-2.2,0-3.3-1.8-3.3-4.7a27.4,27.4,0,0,1,3.2-10.7c4.4-3.5,9.1-6.8,15.6-15,7.2-9.2,8.8-15.3,8.8-18.2a4.39,4.39,0,0,0-3.9-4.1c-5.6,0-10.1,5.1-16.1,15.4-5.7,9.8-12.2,25.2-12.2,33.7A7.3,7.3,0,0,0-79.95.6c5.7,0,14.4-8.8,19.1-14.5,1.2-1.4,1.6-2,1.6-2.9a1.312,1.312,0,0,0-1.4-1.4c-1.1,0-1.9,1-3.1,2.5C-67.35-10.9-74.95-3.1-79.25-3.1Zm18.4-48.1c1,0,1.5.4,1.5,1.4,0,2.4-1.2,5.4-7.1,13.5-5.4,7.3-10.4,11.7-11.7,12.3.3-1.6,1.5-5.8,6.8-15.1C-66.25-48.4-62.15-51.2-60.85-51.2Zm3.6,48.1c-2.2,0-3.3-1.8-3.3-4.7a27.4,27.4,0,0,1,3.2-10.7c4.4-3.5,9.1-6.8,15.6-15,7.2-9.2,8.8-15.3,8.8-18.2a4.39,4.39,0,0,0-3.9-4.1c-5.6,0-10.1,5.1-16.1,15.4-5.7,9.8-12.2,25.2-12.2,33.7A7.3,7.3,0,0,0-57.95.6c5.7,0,14.4-8.8,19.1-14.5,1.2-1.4,1.6-2,1.6-2.9a1.312,1.312,0,0,0-1.4-1.4c-1.1,0-1.9,1-3.1,2.5C-45.35-10.9-52.95-3.1-57.25-3.1Zm18.4-48.1c1,0,1.5.4,1.5,1.4,0,2.4-1.2,5.4-7.1,13.5-5.4,7.3-10.4,11.7-11.7,12.3.3-1.6,1.5-5.8,6.8-15.1C-44.25-48.4-40.15-51.2-38.85-51.2Zm15.3,33.1c0-3.5-2.1-5.8-5.8-5.8-7,0-14.8,8.9-14.8,18.2,0,4.3,2.8,6.4,5.6,6.4C-29.65.7-23.55-11.6-23.55-18.1Zm-6.4-1.3a.265.265,0,0,1,.3.3,19.47,19.47,0,0,0-.3,2.2c0,1.3,1.5,1.8,1.5,2.1,0,3-5.1,12-9,12a2.651,2.651,0,0,1-2.5-2.9C-39.95-12.2-34.25-19.4-29.95-19.4Zm19-2.9c0,2.3,1.4,3.2,2.6,3.2,1.5,0,2.2-1.6,2.2-3.8,0-10,20.3-23.9,30.3-23.9,2.5,0,3.7,1.5,3.7,4.3,0,3.5-7.4,19.5-12.8,29.6C11.75-6.5,8.15-.2,8.15,1.9c0,2.2,1,3.6,2.4,3.6s4.2-3.4,6.5-5.7c9-9,19.3-19.1,23.8-23.8a60.788,60.788,0,0,0-3.2,17.9c0,4.4,1.9,8.8,5.7,8.8,10.1,0,26.2-21.2,26.2-47.3,0-6.3-3.3-10.1-5.9-10.1a2.652,2.652,0,0,0-2.8,2.9c0,2.8,4.4,2.1,4.4,8.7,0,20.9-13.9,41.4-19.8,41.4-2,0-2.9-1.7-2.9-5.7,0-10.5,6.7-23.7,6.7-25.4s-.9-2.4-2.2-2.4-2.2,1.3-4.4,3.9c-8.2,9.6-17.4,16.6-25.9,25.4,7.4-13,16-32,16-37.6a7.189,7.189,0,0,0-7.3-7.2C12.85-50.7-10.95-35-10.95-22.3Zm91-1.6c-7,0-14.8,8.9-14.8,18.2,0,4.3,2.8,6.4,5.6,6.4,7,0,11.6-7.9,13.7-13.9a23.225,23.225,0,0,0,8.7-1.7c3.3-1.5,4.6-2.7,4.6-3.7a1.71,1.71,0,0,0-1.8-1.7c-1,0-4.9,2.8-9,2.8-1.6,0-1.6-2.3-1.6-3.1C85.45-22.1,83.75-23.9,80.05-23.9Zm-.6,4.5a.265.265,0,0,1,.3.3,19.47,19.47,0,0,0-.3,2.2c0,1.3,1.5,1.8,1.5,2.1,0,3-5.1,12-9,12a2.651,2.651,0,0,1-2.5-2.9C69.45-12.2,75.15-19.4,79.45-19.4Zm18.4-4.7c-1.4,0-2.1,1.2-2.8,3.6a86.11,86.11,0,0,1-3.6,9.6c-1.5,3.7-3.1,8-3.1,9.1A2.759,2.759,0,0,0,90.65.5c.9,0,2.7-5.8,5-9.4,3.2-5,9.8-11.4,11.2-11.4.6,0,.9.3.9.7,0,.5-.7,1.7-.7,2.7a1.965,1.965,0,0,0,1.9,1.9c2.5,0,3.5-2.9,3.5-6a3.381,3.381,0,0,0-3.6-3.5c-2.5,0-5.4,2.2-9.1,6.1-.5.5-.8.8-1.2.8-.2,0-.2-.1-.2-.3,0-.9,1.4-3.5,1.4-4.7A1.79,1.79,0,0,0,97.85-24.1Zm23.1,21c-2.2,0-3.3-1.8-3.3-4.7a27.4,27.4,0,0,1,3.2-10.7c4.4-3.5,9.1-6.8,15.6-15,7.2-9.2,8.8-15.3,8.8-18.2a4.39,4.39,0,0,0-3.9-4.1c-5.6,0-10.1,5.1-16.1,15.4-5.7,9.8-12.2,25.2-12.2,33.7a7.3,7.3,0,0,0,7.2,7.3c5.7,0,14.4-8.8,19.1-14.5,1.2-1.4,1.6-2,1.6-2.9a1.312,1.312,0,0,0-1.4-1.4c-1.1,0-1.9,1-3.1,2.5C132.85-10.9,125.25-3.1,120.95-3.1Zm18.4-48.1c1,0,1.5.4,1.5,1.4,0,2.4-1.2,5.4-7.1,13.5-5.4,7.3-10.4,11.7-11.7,12.3.3-1.6,1.5-5.8,6.8-15.1C133.95-48.4,138.05-51.2,139.35-51.2Zm14.1,29.4c-.5,0-2-1.8-5.7-1.8-6.5,0-16.4,11.9-16.4,19.1a5.173,5.173,0,0,0,5,5.5c3.4,0,9.5-3.5,14-9.1v2.2c0,4,.7,9.8,5.2,9.8,2,0,3.6-1.1,3.6-1.9,0-.5-.7-.7-1.6-.8-2.8-.7-2.9-6-2.9-8.4a17,17,0,0,1,1.3-7.1c1.2-2.4,8.3-8.6,15-19.3,5.6-9,6.5-13.8,6.5-16.6s-1.6-4.8-4.4-4.8c-3.5,0-8.2,3.9-12.4,12.8A101.6,101.6,0,0,0,153.45-21.8Zm19-29.5c1.1.1,1.1,1.1,1.1,1.9,0,2.9-1.1,5.7-5.5,13.5a78.48,78.48,0,0,1-10.7,14.7s2.3-10.8,6.6-19.3S171.45-51.3,172.45-51.3Zm-24.7,31.8a2.08,2.08,0,0,1,2.2,1.7,1.455,1.455,0,0,0,1.5,1.4c.1,2.5-10,13.2-13.4,13.2a2.2,2.2,0,0,1-2.3-2.3C135.75-9.3,143.05-19.2,147.75-19.5Z" transform="translate(270 289)" />
</g>
// マスクオブジェクトを<mask>タグで囲む
<mask id="mask">
<path id="mask-line" class="handwritingText__maskLine" d="M105.459,264.2s-2.6-8.594,11.519-18.185,19.5-7.959,22.688-5.122-7.921,27.159-7.921,27.159l-17.662,30.616S74.25,249.4,98.23,232.066s78.73.743,78.73.743A135.4,135.4,0,0,0,154.87,264.2a113.133,113.133,0,0,0-11.452,39.318s-24.753,3.321-32.718-2.6,1.433-20.645,1.433-20.645,1.031-5.828,11.488-10.048,43.692-3.019,43.692-3.019l-9.547,3.758s-3.612,7.186.874,9.309,22.621-7.528,18.321-12.218-22.683,10.5-15.559,18.062c2.586,2.744,14.97,2.686,25.763-15.154,14.013-10.016,31.393-32.047,24.513-35.49-10.8-5.406-33.071,46.722-23.6,51.843,3.893,2.1,14.15-5.8,24.811-19.262,13.432-10.142,27.2-28.512,19.8-32.581S199.709,281.7,209.419,287.31c6.25,3.608,15.409-8.29,15.409-8.29s-4.059-8.261,1.341-12.921,20.261-5.72,20.261-5.72-6.586,13.721-3.636,11.482,0-4.662,0-4.662-8.547.928-11.739,5.956-4.247,10.438-2.069,12.956,7.091.978,10.782-2.884,5.022-11.365,5.022-11.365,6.167,3.458,10.368,3.232,6.438-4.137,6.438-4.137-2.925-11.134,11.635-21.607,22.314-11.21,26.514-6.28-19.986,48.375-19.986,48.375v1.1L317.183,256.3s-12.787,25.665-4.567,32.837c7.167.911,15.59-5.156,22.8-28.763s-5.369-25.331-5.369-25.331.223-24.62,14.711-7.662,3.475,48.4,7.159,44.476-.784-5.418-.784-5.418-7.958,1.67-11.152,6.865-4.189,11.964-1.625,13.915,8.26.428,11.882-6.112,3.714-11.612,3.714-11.612l-2.818,1.1s-1.59.743,3.71,2.707,12.784-3.268,12.882-6.865-7.833,21.779-7.833,21.779a26.674,26.674,0,0,1,8.283-14.459c7.124-6.465,9.793-8.159,11.684-6.775s-5.542,14.679-6.111,11.951c11.107-1.877,47.512-36.2,38.166-42.162s-32.177,44.79-25.733,49.439,14.643-4.406,14.643-4.406,1.425-18.267,7.088-23.631,13.273,2.992,13.273,2.992-2.025,12.25,0,9-1.45-2.8-3.663-2.752-7.978,3.283-11.24,8.5-4.567,9.637-.74,11.845,13.453-6.821,23.938-19.659,21.083-28.6,14.571-32.136-15.684,18.947-19.913,35.814.019,23.281,10.1,18.919"/>
</mask>
</g>
</svg>
</div>
</div>
次に、背景オブジェクトに切り抜く対象となるマスクオブジェクトをCSSのmaskプロパティで指定します。
指定方法は「mask: url(マスクオブジェクトのパス);」です。
背景オブジェクトの「#text」セレクタに、先ほど作成した<mask>タグのid「#mask」を指定しましょう。
「#text { mask: url(#mask); }」となります。
さらに、maskプロパティはマスクオブジェクトと背景オブジェクトの色を乗算して透過する特性があります。
意図した色で描画するために、マスクオブジェクトの色に「#FFFFFF」、背景オブジェクトの色に希望の描画色を指定しましょう。
ここでは、マスクオブジェクトの「.handwritingText__maskLine」セレクタに「stroke: #FFFFFF;」、背景オブジェクトに「fill: #404040;」を指定したことで、黒いライン(#404040)でテキストが描画されています。
これで、手書き風テキストアニメーションの完成です!
// テキスト要素にマスクオブジェクトを指定
#text {
mask: url(#mask);
}
.handwritingText {
width: 100%;
〜省略〜
&__maskLine {
fill: none;
// マスクオブジェクトの色を白にする
stroke: #FFFFFF;
〜省略〜
}
}
おわりに
今回は、SVGとCSSを使った手書き風テキストアニメーションの作り方を紹介しました。
SVGの破線とマスクをの使い方を理解できれば、アニメーションでロゴやイラストを描画したり、JavaScriptでトリガーを指定したり、様々な場面で応用できそうですね!
ぜひ、活用してみてください。
今日も最後までお読みいただき、ありがとうございました。