ページフッターのビューポートオーバーフローを修正

shoelace-style/webawesome

wa-pageslot="footer" があるページで、コンテンツが短い場合でもフッター分だけビューポートがはみ出し、不要なスクロールバーが表示されていました。今回の PR はレイアウトを CSS 主導に切り替えることで、フッターを正しくビューポート下部に固定し、ページ全体が期待通りに収まるように修正します。

背景

問題の概要: wa-page にフッターが配置されると、コンテンツ領域がヘッダー高さのみで計算され、フッター分が余分に加算されてページ高さがビューポートを超えていました。その結果、コンテンツがほとんど無くても垂直スクロールが常に発生し、ユーザー体験が低下していました。

再現手順: 短いコンテンツを持つ <wa-page>slot="footer" を設定し、ビューポートよりも高さが小さい画面で表示すると、フッターがビューポート下に隠れず、ページ全体がフッター分だけ長くなります。この挙動は PR が対象とした regression の中心です。

影響範囲: フッターを使用する全ての wa-page インスタンスに対して発生し、レイアウト崩れはデスクトップ・モバイルともに顕在化します。

技術的な変更

CSS レイアウトの見直し: packages/webawesome/src/components/page/page.styles.ts でグリッドボディの配置と高さ計算を修正しました。主な変更点は以下の通りです。

@@
   [part~='body'] {
-    min-height: 100%;
-    align-items: flex-start;
+    min-height: 100%;
+    align-items: start;
   }
@@
-    height: min(
-      var(--main-height, 100dvh),
-      calc(100dvh - var(--header-top) - var(--banner-top) - var(--subheader-top))
-    );
-    max-height: min(
-      var(--main-height, 100dvh),
-      calc(100dvh - var(--header-top) - var(--banner-top) - var(--subheader-top))
-    );
+    min-height: 0;
+    /** Allows the menu / aside to always be 100% of the height of the main content area */
+    align-self: stretch;
+    max-height: calc(100dvh - var(--header-top) - var(--banner-top) - var(--subheader-top));
   }
  • align-itemsflex-start から start に変更し、グリッド子要素が余分な余白なしで配置されるようにしました。
  • 高さ算出に使用していた min() 関数を除去し、min-height: 0max-height の固定計算に置き換えることで、メニュー・サイドバーがメイン領域の高さに自然に追従し、フッター分の余剰が排除されました。

不要になった JavaScript ロジックの削除: packages/webawesome/src/components/page/page.ts からビューポート高さ算出に使用していた updateAsideAndMenuHeights メソッドと、関連するスクロールリスナーの登録・解除が削除されました。

@@
-            if (entries.length > 0) {
-              this.updateAsideAndMenuHeights();
-            }
@@
-        document.addEventListener('scroll', this.updateAsideAndMenuHeights, { passive: true });
@@
-  updateAsideAndMenuHeights = () => {
-    const visiblePixels = this.visiblePixelsInViewport(this.main);
-
-    if (visiblePixels == null) {
-      return;
-    }
-
-    this.aside.style.setProperty('--main-height', `${Math.round(visiblePixels)}px`);
-    this.menu.style.setProperty('--main-height', `${Math.round(visiblePixels)}px`);
-  };
@@
-    document.removeEventListener('scroll', this.updateAsideAndMenuHeights);

削除により、ビュー高さの決定は純粋に CSS に委譲され、ランタイム計算のオーバーヘッドが排除されました。

設計判断

CSS 主導へのシフト: 本変更はレイアウトに関わるロジックを CSS に集約し、100dvh を基準にした高さ計算へ統一した点が特徴です。これにより、ブラウザのネイティブビューポート単位に依存し、JavaScript の手動計算による不整合リスクが低減されました。

後方互換性の維持: コンポーネントの公開 API は変更されておらず、wa-page の使用方法に差分はありません。CSS の内部実装が変わっただけなので、既存の実装はそのまま動作し、アップグレード時のリグレッションリスクは最小化されています。

トレードオフ: 高さ計算を CSS のみで行うため、極端に小さなビューポートでの微調整が必要な場合はカスタムプロパティ --main-height を上書きすることで対応可能です。柔軟性は保持しつつ、デフォルト動作はシンプル化されています。

まとめ

今回の PR は CSS によるビューポート基準のレイアウト見直し不要な JavaScript ロジックの除去 によって、wa-page のフッターがビューポートからはみ出す regression を根本的に解消しました。フッターは正しくビューポート底部に固定され、余計なスクロールが発生しなくなることで、ユーザー体験と保守性が向上します。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
0e4f76c6

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
リトライ後承認
Review Count:
2回 (改善を経て承認)
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文で要旨を示し、背景・技術的変更・設計判断の各セクションで詳細を展開、まとめで結論を提示しており、総論→各論→結論の構成が明確です。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

コードブロックは `言語:ファイルパス` 形式で正しく記述され、PRリンクは `[#番号](URL)` 形式で正しくハイパーリンク化されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

専門的な用語と実装詳細に焦点を当てており、エンジニア向けの内容となっています。初心者向けの余計な解説はありません。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションは総論パラグラフ・各論パラグラフ・結論パラグラフで構成され、段落はトピックセンテンスで始まり1段落1トピック、長さも適切に分割されています。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事中のコードブロックは提供されたDiffと完全に一致しており、削除・追加箇所が正確に反映されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

`align-items`, `min-height`, `100dvh` などの技術用語が正確に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

技術的な変更理由や影響が Diff と PR の記述に基づき正しく説明されています。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

全ての主張が PR タイトル・Description・Diff に裏付けられており、ハルシネーションは見られません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR 番号 #2537 だけが数値で使用されており、正確です。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルは PR の「fix page stretching」の内容(ページの伸びに関するバグ修正)を具体的に表現しており、一致しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

記事は PR に記載された情報以外の外部知識(バージョンサポート等)を付加していません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現のずれはなく、PR の記述と一致しています。