全取引SVGが一切表示されない
22取引分のアニメーション確認ページ(/dev/journal-push-animation-test)を開いたら、全コンポーネントが空白だった。エラーメッセージも出ない。Vue の警告もない。ただ何もない。
原因はすぐ分かった。コンポーネントの命名ルールを完全に読み違えていた。
ファイルの置き場はこうなっている。
app/components/dev/transactions/TransactionNo01Animated.vue
Nuxt の自動登録は、ディレクトリ階層をコンポーネント名のプレフィックスとして付加する。結果、このコンポーネントは DevTransactionsTransactionNo01Animated として登録された。試作ページは <TransactionNo01Animated> と書いていた。名前が噛み合っておらず、Nuxt はコンポーネントを静かに無視していた。
修正の方針は2つある。呼び出し側のタグ名をすべて書き直すか、登録側でプレフィックスを消すか。22個のコンポーネントがあるので、後者を選んだ。
// nuxt.config.ts
components: [
{ path: '~/components', pathPrefix: true },
{ path: '~/components/dev/transactions', pathPrefix: false },
],
pathPrefix: false を付けると、ディレクトリ階層がコンポーネント名に入らない。再起動後、no01 の SVG が画面に現れた。仕訳をプッシュすると株式券が右から左へ移動し、取消ボタンもアクティブになった。
CSS transform が SVG に効かない
no08(買掛金発生)のアニメーション実装で詰まった。買掛債務が発生する瞬間に「パーン」と広がる花火を入れたかった。
最初は CSS の @keyframes で書いた。
@keyframes spark {
0% { transform: scale(0) translate(0, 0); opacity: 1; }
100% { transform: scale(1) translate(30px, -20px); opacity: 0; }
}
ブラウザで確認すると、花火の点が一切動かない。スケールもゼロのまま固定されている。
調べて分かったのは、SVG 要素に対して CSS の transform が期待通りに動かないケースがあること。特に transform-box: fill-box を指定していても、ブラウザの実装差によって変換の基点が狂う。transform: identity matrix に固定されているように見える状態になる。
CSS で組むのをやめて、SMIL に切り替えた。SVG が本来持っているアニメーション仕様だ。
<circle class="spark" cx="200" cy="150" r="4" fill="#ff6b35" opacity="1">
<animateTransform
attributeName="transform"
type="translate"
from="0,0"
to="40,-30"
dur="0.6s"
fill="freeze"
/>
<animate
attributeName="opacity"
from="1"
to="0"
dur="0.6s"
fill="freeze"
/>
</circle>
<animateTransform> と <animate> を組み合わせると、移動と透明化を同時に走らせられる。CSS と違って座標系が SVG 内部の単位に素直に従うため、計算した通りに動く。
Vue からアニメーションを起動するには beginElement() を使う。
const svgRef = ref<SVGSVGElement | null>(null)
const triggerFirework = () => {
const sparks = svgRef.value?.querySelectorAll('.spark animateTransform')
sparks?.forEach(anim => (anim as SVGAnimateTransformElement).beginElement())
}
svgRef から querySelector で SMIL 要素を直接拾い、beginElement() を呼ぶ。仕訳プッシュのタイミングでこれを実行すると、花火が弾けた。
no09 の座標ミスを修正
no09(売掛金発生)は no01(設立出資)の鏡像パターンで作った。お金袋と商品を左右対称に配置するつもりだったが、座標を手計算した際にミスが入った。
| 要素 | 誤った before 位置 | 正しい before 位置 |
|---|---|---|
| お金袋 | x ≈ 690 | x ≈ 824 |
| リンゴ | x ≈ 464 | x ≈ 643 |
no01 の値を参照して上書きした。ブラウザで並べると、左右の動線がきれいに揃った。
no06 の SVG をファイルとして書き出す
no06 は Illustrator 側で手直しが必要になったため、Vue コンポーネントにインラインで書かれた SVG を単体ファイルとして抽出した。
TransactionNo06Animated.vue の <svg> ブロックをそのまま切り出して memo/2026-05-05/transaction-no06-simple.svg に保存した。インライン SVG をコンポーネント外に出すだけなので、手順は単純だが、Illustrator が読めるように xmlns 属性が正しく入っているか確認した。
今日わかったこと
CSS transform は SVG 要素に対してブラウザが思った通りに動かさないことがある。同じ translate でも、<animateTransform> を使えば座標系が素直で安定する。
Nuxt のコンポーネント自動登録は、ディレクトリ構造がそのまま名前に乗る。深い階層に置いたコンポーネントを短い名前で使いたいなら pathPrefix: false を設定する。警告なしに無視されるので、表示されない原因として最初に疑うべき場所だった。