本文へスキップ
chibiham/ developer & explorer

chibiham home page

Next.jsで作成した個人ホームページ。プロフィール、ポートフォリオ、ブログを掲載し、多言語対応・ダークモード・SEO・Markdownベースのコンテンツ管理を実装。2026年のデザイン改修では、カンプ作成からイメージのすり合わせ、細部調整、サイトへの反映まで取り組み、その後コントラストと星座ステッカーで再調整した。

next.jsverceltailwind-cssmarkdownmdxseoi18n

Next.jsで作成しているこのホームページについて。

概要

ちびはむのプロフィール、ポートフォリオやブログ等を掲載し、エンジニアとしてのプレゼンスを上げるために開発・運用している。

アーキテクチャ

アーキテクチャ図

  • Cloudflareでドメイン登録
  • Next.jsアプリで運用したかった点、フロント/バックエンド分離するつもりがなかったため、Vercelを選択
    • GitHubと連携するだけでブランチごとの自動デプロイが構成される
    • グローバルCDN、自動スケーリング、モニタリング、DDoS対策、環境変数の管理など、運用機能も充実。Next.jsでのSSG, SSRに対応できる
    • これらの機能を有しながらも、無料枠が充実しており、よほどのPVがない限り無料で運用可能
      • かなり余裕がある

Vercel使用量ダッシュボード

  • Markdownによるコンテンツ管理
    • content/blog/、content/portfolio/配下にMarkdownファイルを配置し、Gitで管理
    • gray-matterでfrontmatter解析、next-mdx-remoteでレンダリング
    • 以前はNotionをCMSとして使用していたが、シンプルなMarkdown管理に移行した(詳細は後述)
  • Resend
    • メール送信PaaS。コンタクトフォームのメール送信に使用。シンプルな使い心地で、無料枠も十分あり

技術スタック

  • Next.js
    • 静的なサイトとインタラクティブなサイトの両方を、SSGやSSRに対応することでユーザー体験とコストパフォーマンスよく提供できるため
    • フロントエンドとバックエンドを統合させつつ、Reactを使用したコンポーネントベースの開発が可能なため
    • 複雑なバックエンド処理は存在しないため、SSRとServer Actionsを使用し、簡素な作りに留めている
  • Tailwind CSS
    • SSGに対応させたかったため、また、Reactのコンポーネント開発においてデメリットの少ないユーティリティファーストなTailwindを選択

デザイン

開発初期のデザイン検討として、Figmaを使用。個人開発のためオンコードで調整した方が早い側面があるため細部には時間をかけていない。

  • Gridデザインを適用した画面全体のレイアウトの調整(約2h)
  • 背景、ロゴ、アイコン画像の作成(約2h)

Figmaでのグリッドデザイン検討

  • アイキャッチ画像はnijijourney(Midjourney)で作成
  • ちびはむのアイコンは、手書きイラストをnijijourneyによるi2iで作成後、Photoshopで細部調整

アイコン・ロゴ・背景デザイン

デザインの全面改修(2026年9月)

「テクノロジーとkawaii、信念」を軸に、トップページからサイト全体のデザインを見直した。薄紫と淡い青を中心に、ピンクを差し色として使用。淡い宇宙の雰囲気に、網点・幾何学模様・土星を重ね、柔らかさと理性的な印象を両立させることを目指した。

今回はCodexと対話しながら、動くカンプを比較し、ブラウザで見え方を確かめて実装へ進めた。

1. カンプ作成

最初に、配色・レイアウト・パターンの使い方が異なる複数のHTML/CSSカンプを作成した。静止画だけでなく、動きやスクロール時の印象、スマートフォンでの配置まで確認できる形にした。

2. イメージのすり合わせ

案を比較しながら、C案の構成にA案のグラデーションを取り入れ、MVのような網点や幾何学パターンの密度を加えて方向性を絞った。キャラクターの髪色を基準に色調を合わせ、既存のスライスハム風SVGロゴや土星も組み合わせた。

文章はプロフィールやブログの内容を踏まえて調整。「かわいい」という言葉で説明するのではなく、見た目で柔らかさを表現し、文章では「より良いものを探究し続けること」「変化に応え続けるアジリティ」を伝える構成にした。

3. 細部調整

ヒーロー中央のアバターは自己紹介の位置へ移し、中央に余白を残した「問い・設計・実装・記録」の星図へ変更。ABOUT CHIBIHAMの文字サイズ、アバターの大きさや画像、見出しと本文の間隔を実際の画面で繰り返し調整し、最終的にF案を採用した。

ヒーロー下部には、北斗七星・わし座・かに座・さそり座・はくちょう座など、実際の星の座標に基づくモチーフを配置。淡い配色のまま、ゆっくり流れて揺れる帯にした。

4. サイトへの反映

確定したカンプをNext.jsのコンポーネントとCSS Modulesへ反映。ヘッダー・フッター・配色・パターンは共通化し、プロフィール、制作物、ブログ、お問い合わせにも同じデザインを適用した。本文や制作物・記事へのリンクは、既存のコンテンツとつないでいる。

日本語・英語、PC・スマートフォン、ライト・ダークの各表示を確認し、動きを停止するボタンと端末の「動きを減らす」設定にも対応した。カンプで方向性を固めた後も、実際の文章やリンクを載せた状態で確認し、余白や文字の収まりを調整している。

デザイン改修後のトップページ。淡い紫と青の背景に、問い・設計・実装・記録の星図を配置

再調整:Sticker Cosmos(2026年9月)

全面改修から少し時間を置いて見直すと、配色は気に入っているものの、全体が「のっぺり」して見えた。原因を探ると、ラベンダー・淡い青・ピンクがどれも同じくらいの明るさに揃っていて、明暗の差がほとんどなかった。そこで、パレットは変えずにコントラストを上げ、「ごちゃついているけど、まとまりはある」画面を目指して再調整した。今回はClaude Codeと対話しながら進めた。

1. 3つの方向性を比較する

最初に、同じパレットのまま方向性の異なる3案をカンプにした。

  • G / Sticker Atlas:方眼の上に付箋・テープ・スタンプを重ねたZINE風。線の太さ・影・傾きを数種類に絞って揃える
  • H / Night Chart:濃紺の地に経緯線・目盛り・座標を敷き詰めた星図カタログ風
  • I / Pop Bento:色面のタイルに写真や巨大な文字を詰めた雑誌風

どの案にも共通させたのは「要素は増やす・ルールは減らす」という方針。パレットには、同じ色相で濃くした締め色と深いインク色だけを加え、明暗の差を作った。

2. 現行の星図に重ねる

G案のステッカーの手触りは気に入ったが、目指したいのは現行デザイン(F案)の延長だった。「科学を重視する堅さ」と「発想の柔軟さ」を同時に表したいという軸を言葉にし、F案の星図をベースにした J / Sticker Cosmos を作った。

  • 堅さ:星図の外周に5°刻みの目盛りと時角、黄道の破線、方眼、FIG.01のような図番号、座標、作品の標本ラベル(No. / DATE / STACK)、記事の観測番号(OBS.018)。等幅の文字と細い線で統一
  • 柔らかさ:付箋・カード・ボタン・ヘッダーを角丸にし、インクの輪郭の内側に白フチを入れた型抜きシール風に
  • コントラスト:インクの輪郭とベタ影、濃紺のパネルで明暗の差を付ける。見出しは現行と同じ文字サイズに抑えた

3. 星座ステッカーの形を決める

実在の星座のSVGをシールにする部分は、何度か作り直した。最初は光沢と丸みのある「ぷくぷく」したシールにしたが、最終的には、星座の線と星の形に沿って切り抜いたフラットなシールに落ち着いた。

形はSVGフィルターで自動的に作っている。星座の線と星をぼかしてから閾値で太らせ、「本体の色 → 白フチ → インクの輪郭 → ずらした影」の順に重ねる。星座ごとに型抜きの形を用意する必要がなく、星座を差し替えても形が追従する。

4. 重なりをつぶす

シールを散らすと、画面幅によって見出しやボタン、ラベルに重なる箇所が出てきた。固定の位置に置くのをやめ、シールをボタンやキャッチの並びの中に入れて一緒に折り返すようにした。見出し横のシールは文字が来ない角に留めている。1200px以下では星図を本文の下に回して1カラムにし、パターン図形を外した。390・700・1024・1440pxの各幅で重なりがないことを確認している。

5. サイトへの反映

色・線・影・角丸・白フチをCSS変数(トークン)にまとめ、共通のヘッダー・フッター・背景と、下層ページのパネル・カード・記事本文・フォームに一括で適用した。既存のクラス名はそのままに見た目だけを置き換えたため、各ページのコンポーネントにはほとんど手を入れていない。ホームはJ案の構成でコンポーネントを作り直し、星座シールは星座名と色を指定するだけで貼れる共通部品にした。

ダークモードはトークンの値を差し替える形で作った。パネルは濃紺にし、パステルのシール類はライトと同じ見た目のまま、夜空に貼ったように見せている。

再調整後のトップページ。目盛り付きの星図に、問い・設計・実装・記録のラベルと星座の形のシールを貼っている

ダークモードのトップページ。濃紺の地に、パステルのラベルと星座シールが浮かぶ

機能

Grid Designによるレスポンシブデザイン

Tailwind CSSのGridを使用し、レスポンシブデザインに対応。

ダークモード対応

CSS Modulesで色をトークン(CSS変数)として定義し、prefers-color-schemeに応じて値を切り替えている。ブラウザの設定によってダークモードが適用される。

多言語対応

i18next、next-i18n-routerを使用して多言語化対応。詳細は記事参照。

ブログやポートフォリオの記事コンテンツ自体は、ロケールごとにMarkdownファイルを用意することで多言語対応している。

SEO対策

検索エンジン最適化を多角的に実装している。

  • JSON-LD構造化データ: 各記事ページにArticleSchemaを埋め込み、Google Rich Resultsに対応
  • Open Graph / Twitter Cards: 記事ごとにタイトル・説明・カバー画像を動的に生成し、SNSシェア時の表示を最適化
  • 動的サイトマップ: sitemap.tsでブログ・ポートフォリオの全記事を含むXMLサイトマップを自動生成
  • canonical URL / hreflang: 各ページのcanonical URLとロケール別の代替URLを設定し、多言語サイトのSEOに対応

コンタクトフォーム

Next.jsのServer Actionsを使用したフォーム送信を実装。

  • Zodによるバリデーション。zod-i18n-mapを使用し、エラーメッセージもブラウザの言語設定に応じて日英で表示される
  • Resend + react-emailでリッチテキストメールを送信。送信者と管理者の双方にメールが届く
  • Reactコンポーネントでメールテンプレートを構築しているため、フロントエンドとほぼ同様の実装で多言語にも対応

メール送信確認画面

MDXカスタムコンポーネント

Markdownレンダリングにnext-mdx-remoteを使用し、以下のカスタムコンポーネントを実装している。

  • CodeBlock: rehype-prism-plusによるシンタックスハイライト
  • MermaidBlock: Mermaid図のクライアントサイドレンダリング。ダークモード切替時に自動で再レンダリングされる
  • Callout: 情報・警告などのコールアウトボックス
  • テーブル・引用・リスト等: 全Markdown要素にダークモード対応のスタイリングを適用

Atomic Designによるコンポーネント設計

コンポーネントをAtoms / Molecules / Organismsの3層で整理し、再利用性と保守性を確保している。

コンテンツ管理:Notion CMSからMarkdownへの移行

当初はNotionをCMSとして活用していた。Notion APIで取得した各Blockに対応するコンポーネントを一つ一つ用意し、Claude 3.7 Sonnetを活用してAPIの型に合わせたコンポーネントを生成・調整することで、ほぼ全てのブロックを約3hで実装した。

しかし、運用を続ける中でNotionをCMSとして使い続ける必要性が薄れ、シンプルなMarkdownファイルによる管理に移行した。

移行の背景:

  • 個人のナレッジ管理をNotionからObsidianに移行したことが最大の要因。記事の執筆・管理もObsidian vault内で完結させたかった
  • Obsidianで書いたMarkdownをそのままホームページのコンテンツとして使えるため、執筆からデプロイまでのフローがシンプルになる
  • Notion APIへの依存により、ビルド時の外部通信やキャッシュ管理が必要だった
  • ブロックごとのコンポーネント対応のメンテナンスコストがあった

現在の構成:

  • content/blog/{locale}/{slug}.md にMarkdownファイルを配置
  • YAML frontmatter(title, description, cover, date, tags等)でメタデータを管理
  • gray-matterでfrontmatter解析、next-mdx-remoteでMDXレンダリング
  • Mermaid図やKaTeX数式、コードブロックのシンタックスハイライトにも対応
  • ロケールごとのサブディレクトリ(ja/, en/)で多言語コンテンツを管理
  • Next.jsのgenerateStaticParams()によるビルド時静的生成
制作物の一覧へ