🌏

このポートフォリオブログの技術的な工夫点について

ShuyaShuya

Next.jsで構築したこのブログにおける,アクセシビリティ,パフォーマンス,UX向上のための細かな実装やこだわりを紹介します.


このポートフォリオ兼ブログサイトは,単なる情報の羅列ではなく,閲覧者にとって快適で,かつ技術的な遊び心を詰め込んだ場所になるよう設計しました. 開発にあたって工夫した点や,見えないところでのこだわりについて紹介します.

コンテンツ運用を支えるための工夫

ブログを継続的に運用するためには,書く側の体験も重要です.

効率的な OGP 画像の自動生成

記事に画像を設定しなくても,記事の markdown で絵文字を指定するだけで,記事タイトルと著者情報を組み合わせた専用の OGP 画像を自動生成する仕組みを構築しました.

Twemoji の API から絵文字データを取得し,Satori を使って SVG を生成,さらに Resvg で PNG 化するというパイプラインをビルド時に走らせています.

例えばこの記事のカバー画像は以下のようになります.

/og/portfolio-features ogp

絵文字ショートリンク

各記事には,通常の URL とは別に,短い絵文字ショートリンクが割り当てられています.

記事に設定した絵文字を yantan.dev/の後に配置するとそのブログのリンクになります.

  • 例: yantan.dev/🌏 -> www.yantan.dev/space/portfolio-features

実はこれ,DB レスで実装しています.

仕組みとしては,ビルド時に Next.js の SSG で各絵文字に対応した以下のような静的ページを生成し,アクセス時に対応するslugを解決してリダイレクトする仕組みです.

// app/[...slug]/page.tsx
// ...
// ここで絵文字に対応する記事を探す
let post = emojiMap.get(slugJoined);
 
if (!post) {
  // 絵文字がURLエンコードされている可能性があるので試してみる
  try {
    const decoded = decodeURIComponent(slugJoined);
    post = emojiMap.get(decoded);
  } catch (e) {
    console.log("Decode error:", e);
  }
}
 
// 見つかった場合はリダイレクトする
if (post) {
  return permanentRedirect(`/space/${post.slugAsParams}`);
}

PC 版は記事ページのサイドバーから,スマホ版はハーフモーダル内のボタンからワンクリックでコピー可能です.

外部記事のシームレスな統合

Zenn などの外部プラットフォームで書いた記事も,このポートフォリオの一部として扱えるよう工夫しています.

専用のスクリプトに URL を渡すだけで,そのページのメタデータを自動取得し,ここへのリンク用記事ファイルを一瞬で生成できます.

これにより,発信媒体が分散してもポートフォリオ上で一覧表示しやすくなります.

External Articles

UX とパフォーマンスの追求

「使いやすさ」と「速さ」は,ユーザー体験における最も重要な要素です.

タグフィルタリングの非同期処理とアニメーション

記事一覧のフィルタリング機能では,操作のレスポンスを最優先に考えました.

フィルタリングの際,タグを選択してからブログ一覧が表示されるまで若干遅延があったので,タグをクリックした瞬間データ取得を待たず即座にボタンの選択状態を反映させるようにしました.

その後,実際のリスト更新処理は非同期で行い,連続押下対策のデバウンス処理を組み合わせることで,スムーズな操作感を実現しました.

一覧の切り替え時にはフェードアニメーションを行い,唐突な画面変化を防いでいます.

Blog Tag Filtering

レイアウトシフトの防止

一覧のフィルタリングによってコンテンツの高さが変わると,スクロールバーが出たり消えたりして画面全体がガクッと横にずれることがあります.

これを防ぐため,scrollbar-gutter: stable を設定し,スクロールバーの有無に関わらず常に領域を確保することで,安定した見た目を維持しています.

GitHub API と ISR による最新情報の同期

GitHub の issues には read の api が提供されています.

以下のエンドポイントを叩くことで issues に登録した様々な情報を取得することができます.

https://api.github.com/repos/syuya2036/syuya2036/issues

これを利用してProjects ページのプロジェクト一覧を取得していますが,毎回リクエストを送ると遅延の原因になります.

そこで Next.js の ISR を使用し,結果を一定時間キャッシュすることで,情報の新しさとページの表示速度のバランスを最適化しています.

GitHub Issues Projects

アクセシビリティと構造への配慮

モバイル全盛の現代において,スマートフォンでの操作性や,スクリーンリーダー利用者への配慮は欠かせません.

構造化されたモバイルメニュー

モバイル版のナビゲーションは,よくあるハンバーガーメニューではなく下から出現するハーフモーダルを使用しました.

スマホは片手で操作する人が多く,ハンバーガーメニューだとボタンが上に寄るのでこのような対応にしました.

また,ブログを開いた状態でハーフモーダルを開くと目次が表示されるようにしました.

目次セクションでは,記事の構造をそのままリストとしてメニュー内に展開しており,目次を押したらモーダルが閉じるようにしました.

← 通常のハーフモーダル

→ ブログ記事の目次表示

NormalBlog

細部へのこだわり

Markdown Raw 出力

技術ブログとして,記事のソースコードそのものを参照したい需要に応えるため,ブログ記事のリンクの末尾に.md を付与すると markdown のソースが表示されるようにしました.

スマホ版でも簡単に取得できるよう,ハーフモーダル内に"View MD"ボタンを用意しています.

動的な数値表示の揺れ防止

Tools ページにある「Unix タイムスタンプ変換」ツールなど,秒単位で数値が目まぐるしく変わる UI では,数字の桁ごとの幅が異なると表示がガタついて見にくくなります. これを防ぐため,変動する数値部分には tabular-numsフォント設定を適用し,桁が変わってもレイアウトが崩れないよう配慮しています.

まとめ

ただの個人サイトで終わらせないよう,また AI 時代で技術力以外の配慮の部分で差別化できるよう,工夫して開発してみました.