はじめに
Astroのサイト構築に関する備忘録メモです。
大まかなサイトデザインは、AIに任せると可能なのですが、細かくカスタムしようとすると、特にスマホデザインでレイアウトが崩れたり、そもそも想定して作って無かったりして、AIの修正でも直らない為、手動で設定しつつ少しずつ進めています。
また、Three.jsのプロジェクトをTOPに表示する際に、そちらのCSSのカスタムも必要だったりと、やる事が多くかなり大変です。
前回の記事:
[Astro #03] Pagefind検索と動的目次(TOC)の実装
HugoからAstroへの移行最終局面。全記事のビルドエラーを解消し、クライアントサイド検索と自動目次生成機能を導入した開発記録。
https://humanxai.info/posts/astro-03-toc-pagefind-implementation/1. Astro プロジェクトの基本ツリー構成
Astroでモダンなサイトを構築する際、ディレクトリ構成の理解は不可欠だ。ここでは本サイト(PROTOCOL.LAIN)の実際の構成を例に、各ディレクトリの役割を解説する。
/
├── public/ # 静的資産(画像、Three.jsのギャラリー等)
├── src/
│ ├── components/ # 再利用可能なUIパーツ(Navigation, Footer)
│ ├── content/ # Markdown記事(Hugoからの移行先)
│ │ └── blog/ # ブログ記事のデータ
│ ├── layouts/ # 共通テンプレート(BaseLayout.astro)
│ └── pages/ # 実際のURLになるファイル(index.astro)
├── astro.config.mjs # Astroの設定ファイル
└── package.json # 依存関係
-
public/ (静的資産ディレクトリ)
[cite_start]Astroのビルドプロセスを通さず、そのままルートディレクトリに公開されるファイルを配置する場所。FaviconやWebフォントだけでなく、本サイトのように独立したThree.jsのHTMLプロジェクト(ProceduralWindFlowなど)を格納し、トップページからiframeで安全に呼び出す際にも重宝する [cite: 1, 6]。 -
src/components/ (コンポーネント)
[cite_start]サイト内で使い回す独立したUIパーツを格納する。ヘッダー(Navigation.astro)やフッター(Footer.astro)など、各ページで共通して使用する要素をここで部品化する [cite: 70, 84, 100]。CSSはそのコンポーネント内にスコープされるため、他のデザインを破壊する心配がない。 -
src/content/ (コンテンツコレクション)
Astro v2から導入された、Markdownファイルを型安全に管理するための強力なディレクトリ。旧環境(Hugo等)で管理していた膨大なブログ記事データはここに移行する。スキーマを定義することで、フロントマターの記述漏れや型エラーをビルド時に検知できるようになる。 -
src/layouts/ (レイアウトテンプレート)
[cite_start]ページの骨組み(HTML構造)を定義する場所。本サイトの BaseLayout.astro では、全体のメタデータ、ナビゲーションバーの読み込み、SPAのような滑らかなページ遷移を実現する ClientRouter の設定を一括で管理している [cite: 70, 73, 76]。 -
src/pages/ (ページルーティング)
[cite_start]ここに配置したファイルが、そのままサイトのURLパスとしてマッピングされるファイルベースルーティングの中核。例えば src/pages/index.astro はトップページ(/)として機能する [cite: 1]。
2. スマホ表示の「最終防衛ライン」:dvh と clamp() によるレイアウト制御
Astroでサイトを構築する際、PC環境では完璧に機能していても、実機のモバイルブラウザ特有の仕様(特にアドレスバーの動的な挙動)によってレイアウトが容易に崩壊する。ここでは、モダンなCSSを用いた実践的な解決策を解説する。
-
100vw の罠と width: 100% への統一 画面幅いっぱいに要素を広げる際、width: 100vw を指定すると、OSの縦スクロールバーの幅まで計算に含まれてしまい、意図しない横スクロールが発生する原因になる。コンテナの幅は基本的に width: 100% とし、親要素の枠内で制御するのが定石だ。
-
vh ではなく dvh (Dynamic Viewport Height) を使う スマホブラウザ最大の障壁が「スクロールによるアドレスバーの伸縮」だ。従来の 100vh ではこの伸縮が考慮されず、アドレスバーが表示されている間はUIの下部が画面外に押し出されてしまう。これを解決するのが dvh という単位だ。height: calc(100dvh - 75px) (ナビゲーションとフッターの高さを引く)のように指定することで、アドレスバーの有無に関わらず、常に「今実際に見えている範囲」に要素をピタッと収めることができる。
-
clamp() による流動的かつ安全なフォントサイズ制御 レスポンシブ対応として font-size: 1vw のような相対指定のみを行うと、画面幅が約400pxのスマートフォンでは文字がわずか4px相当になり、視認性が完全に失われる。これを防ぐには clamp() 関数が有効だ。 font-size: clamp(12px, 2vw, 0.8rem) のように記述することで、「最小12pxを死守しつつ基本は画面幅(vw)に連動させ、最大でも0.8remで止める」という、安全で読みやすい可変フォントを実現できる。
3. 実践トラブルシューティング・ログ
今回のAstro移行およびUI構築プロセスで直面した具体的なバグと、その解決策を記録しておく。似たような構成を作る開発者の参考になれば幸いだ。
-
ナビゲーションの文字が重なる・押し出される
- 原因: 狭い画面幅で gap と文字サイズが固定されたまま、ロゴとメニュー要素が押し合っていた。
- 解決策: メニューの文字サイズに clamp() を用いて最小サイズを確保しつつ、ロゴ部分に flex-shrink: 0 と white-space: nowrap を指定。これでロゴが圧縮されたり改行されたりするのを完全に防ぎ、安全に右寄せメニューと分離できた。
-
ブログの検索機能が動かなくなる(スクロール競合)
- 原因: 全画面表示を強制するために BaseLayout の html, body に対して overflow: hidden をグローバル適用した結果、スクロールを検知して動くライブラリや検索機能が死んでしまった。
- 解決策: グローバル設定での固定は撤廃。トップページのメインコンテナ(.copland-container)内に限定して overflow: hidden を適用するようスコープを切り分け、影響範囲を最小化した。
-
UIとフッターのめり込み
- 原因: フッターを絶対配置(position: absolute)にしていたため、画面サイズが変わるとコンテンツ領域にめり込む事態が発生した。
- 解決策: フッターを position: fixed に変更し、メインコンテナの高さ計算 calc() からフッターの高さ分を明示的に差し引くことで干渉を回避した。
-
検索導線の欠如(UI設計の考慮漏れ)
- 原因: 移行時のヘッダー設計において、検索ページへの導線が確保されていなかった。
- 解決策: Navigation.astro 内のメニュー項目を右寄せのグループ(.nav-right-group)としてまとめ、その先頭に [ 🔍 ] リンクを配置。デザインを崩すことなく機能を追加した。
💬 コメント