SVGで作るすごいもの
(fuma-nama.vercel.app)- SVGは単なるアイコン形式を超えて、mask、
path、CSSアニメーションを組み合わせることで、線に沿って流れるワイヤー効果やTOCのハイライトを作れる - 中核となる実装は、
lineまたはpathで作った線を直接見せるのではなく、マスク領域として使ってアニメーションするブロックの表示範囲を制限する方式 - Animated Wiresは
rectにmask="url(#...)"を適用し、@keyframesでtranslateYを動かしつつ、linearGradientやCSS変数で視覚スタイルを拡張する - FumadocsのClerkスタイルTOCは、SSR互換性のためにアウトラインはサーバーでレンダリングし、アクティブな位置を示すthumbはブラウザーの位置情報を使ってクライアントでレンダリングする
- SVG
<path>のd属性は自動生成された文字列ではなく命令の一覧なので、サーバーレンダリングされたTOCアウトラインと同じ形のマスク画像をクライアントで再構成できる
SVGマスクで作るAnimated Wires
- サンプルコードは通常のHTMLではなく、JSXまたはReact構文を前提としている
- 基本の線はSVGの
lineまたはpathで作れる- 例では
viewBox="0 0 50 50"の中に縦のlineを配置している
- 例では
- 線を画面に直接描く代わりに、
maskとして使って別の図形が見える範囲を制限するrectにmask="url(#line)"を適用し、maskの内部には白いlineを置く
- 動きは
rectにCSSanimationを適用して作る@keyframes to-downはtranslateY(-10px)からtranslateY(50px)まで移動する
- 視覚スタイルは背景線、より太いマスク線、
linearGradient、CSS変数--heightを組み合わせて拡張する@keyframes to-down-2はcalc(var(--height) * -1)から100%まで移動する
- この種の似た効果の多くは、アニメーションするブロックをマスクで切り抜く方式を使っている
- 一部のデザインはFigmaやほかのSVGエディターで作成できる
- Unkeyのランディングページがこの方式の一例
FumadocsのClerkスタイルTOC
- FumadocsにはClerkスタイルの**目次(TOC)**が実装されている
- SSRと互換性を持たせるには、クライアントJavaScriptなしでサーバー側でTOCアウトラインをレンダリングする必要がある
- サーバーでは要素の正確な位置はわからない
- 実装では
absolute配置を使い、アウトラインを複数のコンポーネントのようにレンダリングしてからつなぎ合わせる
- アクティブ項目やビューポート内に見えているheadingに対応するアウトラインの一部はthumbとして表示される
- thumbはアニメーションする必要があるため、単にアウトラインコンポーネントの色だけを変える方法では不十分
- インタラクション対象であるthumbはクライアント側でレンダリングされる
- ブラウザーから得た位置情報をもとに、クライアント側でマスクマップを構築する
- このマスクマップの作成にはSVGを使う
- SVG
<path>のd属性は命令の一覧であり、点をつないだ線をレンダリングできる - 関連ドキュメントはMDN Web DocsのSVG Pathsで確認できる
- こうして作られたSVGは、サーバーで事前レンダリングされた元のTOCアウトラインと同じ形になる
- Animated Wiresと同様に、CSS
mask-imageにSVGをデータURLとして入れ、アニメーションするdivブロックをマスクしてハイライトされたthumbをレンダリングする- 内部の
divはwidth: 1、height: thumb.height、transform: translateY(${thumb.top}px)、transition: "all 500ms"、backgroundColor: "white"のような値を使う
- 内部の
- React.js実装はtoc-clerk.tsxのソースコードで確認できる
2件のコメント
かっこいいのは確かですが、今の項目を1つだけはっきり強調するほうが、目にはより留まりやすいですね。
Hacker News のコメント
8年前の資料ではあるけれど、Sarah Drasner の有名な「SVG Can Do That?」という発表はいまでも多くの人の目を開かせてくれる
その後 CSS はものすごく成熟したし、SVG 自体がそこまで変わったかはよく分からないけれど、とにかく強くおすすめする
スライド: https://slides.com/sdrasner/svg-can-do-that
動画: https://youtu.be/ADXX4fmWHbo?si=6YPZkopyEDc8PSte
SVG ファイルでできる面白いことの一つは、インライン DTD のエンティティを使って、ファイル内の複数箇所で共有する定数を定義すること
David Ellsworth の「Squares in Squares」ページにある SVG で、優れた例を見ることができる
主要ブラウザでは問題ないが、Inkscape のような一部のツールは DTD をパースもせず、エンティティ展開もしない
[0] https://kingbird.myphotos.cc/packing/squares_in_squares.html
&refのようなエンティティ参照で任意の構文内容を定義して再利用する SGML/XML の仕組みの名前SVG では図形やパスなどを
defsの下に置いてidを付け、本文の SVG で再利用する方式で、リンク先のページも各 SVG 内でその方式を使っているように見える複数の図の間で四角形を共有しているわけではなく、それぞれ別々の DOM として入るから
SVG の初期設計者たちが、なぜエンティティの仕組みを一時的に再実装する必要があると考えたのか気になる
使用箇所でレンダリング属性を上書きできることと関係しているのかもしれないし、当時 SVG は W3C の XHTML/XML 移行の流れの中にあったので、ブラウザがエンティティ定義や文書プロローグ/DOCTYPE を無視するという前提もまだ確立されていなかったのだろう
!doctypeや!elementが見つからない単に SVG の
defsとuseのことを言っているなら、それは DTD ではないhttps://developer.mozilla.org/en-US/docs/Web/SVG/Reference/E...
例えば Billion laughs attack がある
https://en.wikipedia.org/wiki/Billion_laughs_attack
Nanda Syahrasyad の「A Deep Dive Into SVG Path Commands」は、SVG パスがどのように構成されるかを理解するのに本当に良い
ほぼ 2 年前の記事だが、SVG に何ができるのか、そしてそれを正確にどうやるのかについて目を開かせてくれた
[0] https://www.nan.fyi/svg-paths
SVG でこういう面白いことをするプロジェクトをやったことがある
React で作り、複数の静的イラストにアニメーション要素を入れ、色は CMS で制御していた
フロントエンドは API を呼び出して正しい色が入った SVG 画像を受け取り、アニメーションは SVG 要素を隠したり表示したりする形で処理していた
例はここで見られる: https://web.archive.org/web/20221020133516im_/https://uncrow...
Macromedia Flash が本当に懐かしい
Flash と SWF 形式のように、別途ダウンロードしなくても Flash Player さえあれば無数のインディーゲームやアニメ映画を楽しめる技術はなかった
参入障壁も非常に低かった
SVG にも SWF がやっていたことをすべて行える潜在力はあるが、Flash のようなエディタや、ActionScript のようなシーン/オブジェクトベースのコーディング方式がない
ブラウザごとの癖もあるので、単純な SVG だけがどこでも正しく表示されると保証されている
そもそも SVG と Flash を比較するのは、リンゴとオレンジの比較のように見える
SVG 形式が Flash のしていたことをすべて直接行う必要はなく、ブラウザ内の他の技術に依存できる
例えば Unity、Unreal、Godot はブラウザ向けにかなり簡単にコンパイルできる
問題は、こうしたアプリはかなり肥大化しがちで、普通は 1 桁 MB ではなく数十 MB 規模になりやすいこと
複雑なアニメーション SVG は動かしてみると楽しいが、SMIL の奥深くに入ると、Safari が浮動小数点数の前の 0 が一つ抜けているだけでスマホを固まらせたり、妙なことが起きたりする
JavaScript で SVG を動的かつ創造的に作っていて、仕事を探しているなら DM してもよい
線の濃度を許容する SVG 拡張があるのか気になる
ペンを上げ下げできるプロッターがあり、SVG ファイルで駆動される
手書きでよくやるように、線を描いている途中でペンを下げられるとよい
ちなみに Evil Mad Scientist Labs の Axidraw で、素晴らしい装置だし、作っている人たちも素敵だ
例えば多目的レーザーカッター/プロッターを使っているが、不透明度はレーザー出力、線幅は移動速度、緑チャンネルは反復回数、青チャンネルは Z 軸の高さ、赤チャンネルはペン下げやレーザーオフなどに使っている
この種の作業をここでやってきている
https://github.com/WillAdams/gcodepreview
自分でアイコンやロゴを作ってみるまでは、SVG に**変換(transform)**が入っているのはいつも変だと思っていた
曲線をきちんと合わせるのは難しい
2 つ目のロゴを仕上げてみたら平坦すぎて見えたので、10° 傾けたくなり、そのすべての線と曲線を書き直すことを考えると、回転の方がずっと良い選択に見えた
幸いテキストの横に置くと変だったので、カーニングが合って見えるように角度をさらに何度か変えることになった
最近、趣味で小さなゲームを作り、レンダリングには主に CSS アニメーション SVG タイルを使った: https://pipeline-panic.vercel.app/
https://boardgamegeek.com/boardgame/333/waterworks