ギャラリーページをつくった
サイトにGalleryページを作った。
以前はWorksという名前だったのだけれど、少し大げさな気がしていたのでシンプルにGalleryにした。
VirtualとReal
ページは Virtual と Real の2セクションに分かれている。
VirtualはVRChatで撮った写真、Realは現実の写真だ。
両者を同じページに置くことにしたのは、わたしがそれをひとつながりの「写真」として捉えているからだ。媒体や撮影環境が違っていても、シャッターを切る動機も大きくは変わらないと思っている。人によっていろいろな考えがあるだろうが、おなじものだろうが違うものだろうが、わたしは並べてしまえばいい。
カテゴリナビ
PC では画面左に縦書きで Virtual / Real が浮かんでいる。スクロール位置に連動してアクティブなセクションのリンクがハイライトされる仕組みで、IntersectionObserver で現在表示されているセクションを検知している。
モバイルだと左サイドバーが邪魔になるので、同じナビを画面下部のフローティングピル型に切り替えた。backdrop-filter: blur でガラス質に仕上げている。CSS の @media で切り替えているだけなので実装はシンプルだ。
画像の最適化
OptimizedImage というコンポーネントを用意していて、Astro の astro:assets を使って画像を最適化している。最長辺を 2000px に抑えた上で、すべて WebP に変換・quality 85 で書き出す。元の縦横比を保ちながらリサイズするよう計算している。
サムネイルは aspect-ratio: 3 / 2 の枠に対して object-fit: cover で合わせているので、縦横比の違う画像が混在しても見た目が揃う。
ライトボックス
クリックすると拡大表示される、いわゆるライトボックスは GLightbox を使った。
Virtual と Real でそれぞれギャラリーグループを分けているので、開いたままキーボードや矢印で送ると同じセクションの写真だけを巡れる。タッチ操作も対応している。
フェードイン
ギャラリーのアイテムは初期状態で opacity: 0 にしておき、IntersectionObserver でビューポートに入ったタイミングで visible クラスを付けてフェードインさせている。連続してフェードインするよう、DOM 上のインデックスに応じて setTimeout でずらしている。
setTimeout(() => item.classList.add("visible"), index * 100);
シンプルだけれど、格子状にわっと現れる感じが気に入っている。
prefers-reduced-motion を指定しているユーザーに対してはアニメーションをすべて切っている。
データ管理とワークフロー
写真のメタデータは _works-data.json で管理している。ワールド名・ワールドの URL・制作者名・使用カメラ・レンズ・受賞情報などをここに書いておけば、ページ側が読み込んで figcaption に展開してくれる。
ただ、JSON を直接手で編集するのは面倒なので、works-ui というローカル管理ツールを作った。WSLで動作するAstro環境下で npm run works-ui で起動すると localhost に小さな管理 UI が立ち上がる。
galleryページに対してworks-uiという名前だが、これはもともとgalleryがworksだった時の名残り。公開される部分では何も見えない部分なのでいちいち変えなかった。
やれることは:
- 画像のアップロード(Virtual / Real 別)
- エントリのメタデータを入力・編集・削除するフォーム
- リスト上でのドラッグ&ドロップ並べ替え(↑↓ボタンでも動く)
- 「Generate Works」ボタン
最後の Generate を押すと generate-works.js が走る。sharp で元画像を WebP に変換(最長辺 2000px・quality 85)しつつ、exifr で EXIF を読んでカメラとレンズ情報を自動取得する。それらをまとめて _works-data.json に書き出したら Astro ビルドの入力になる、という流れだ。
写真を追加するときの手順はシンプルで、UI で画像をアップロードしてメタデータを入力し、Generate を叩いて npm run dev で確認するだけになった。
自分で使う写真を見せるためのページなので、とにかく手間になって萎えないようにするのを意識した。ナビもキャプションも控えめな色と字で、できるだけ邪魔をしないようにした。
しばらく使いながら、気になるところがあれば直していく。