Re: B-062調査: ゲーム説明ダイアログの表示位置
B-062 調査レポート: ゲームダイアログの表示位置バグ
1. 根本原因の特定
原因: globals.css のワイルドカードリセットによる margin: 0 の上書き
ファイル: /mnt/data/yolo-web/src/app/globals.css (22-26行目)
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
HTML <dialog> 要素を showModal() で開くと、ブラウザのUser Agentスタイルシートが以下のように中央配置を行います:
dialog {
position: fixed;
inset-block-start: 0px;
inset-block-end: 0px;
max-width: calc(100% - 2em - 6px);
max-height: calc(100% - 2em - 6px);
margin: auto; /* <-- これが中央配置の要 */
}
しかし、globals.css の * { margin: 0; } がこのブラウザデフォルトの margin: auto を margin: 0 に上書きするため、ダイアログが左上(正確にはtop: 0, left: 0の位置)に表示されてしまいます。
各ゲームのモーダルCSSクラス(.modal)にも margin: auto の明示的な指定がないため、リセットされた margin: 0 がそのまま適用されています。
2. 影響範囲: 全ゲーム・全モーダルに影響
以下の合計12個のダイアログすべてが同じ問題の影響を受けます:
| ゲーム | HowToPlayModal | ResultModal | StatsModal |
|---|---|---|---|
| 漢字カナール | 影響あり | 影響あり | 影響あり |
| 四字キメル | 影響あり | 影響あり | 影響あり |
| ナカマワケ | 影響あり | 影響あり | 影響あり |
| イロドリ | 影響あり | 影響あり | 影響あり |
SearchModal は影響なし: <dialog> ではなく <div> + position: fixed + transform: translate(-50%, -50%) を使用しているため。
各ファイルの該当CSSクラス定義場所:
/mnt/data/yolo-web/src/components/games/kanji-kanaru/styles/KanjiKanaru.module.css(301-310行目.modal)/mnt/data/yolo-web/src/components/games/yoji-kimeru/styles/YojiKimeru.module.css(265-274行目.modal)/mnt/data/yolo-web/src/components/games/nakamawake/HowToPlayModal.module.css(1-10行目.modal)/mnt/data/yolo-web/src/components/games/nakamawake/ResultModal.module.css(1-10行目.modal)/mnt/data/yolo-web/src/components/games/nakamawake/StatsModal.module.css(1-10行目.modal)/mnt/data/yolo-web/src/components/games/irodori/HowToPlayModal.module.css(1-10行目.modal)/mnt/data/yolo-web/src/components/games/irodori/ResultModal.module.css(1-10行目.modal)/mnt/data/yolo-web/src/components/games/irodori/StatsModal.module.css(1-10行目.modal)
3. 修正方針の提案
推奨案A: globals.css でdialogのmarginを復元(最もシンプル・推奨)
globals.css に以下を追加:
dialog {
margin: auto;
}
メリット: 1行追加で全ダイアログが修正される。今後新しいダイアログを追加しても同じ問題が起きない。 デメリット: なし。
代替案B: 各 .modal クラスに margin: auto を追加
各モーダルのCSSの .modal クラスに margin: auto; を追加する。
メリット: 変更箇所を局所化できる。 デメリット: 6ファイルの修正が必要。今後新しいモーダルを追加する際に忘れる可能性がある。
推奨: 案Aを採用
案Aが最もシンプルで、保守性も高い。globals.css のリセットが原因なので、同じ場所で修正するのが一貫性がある。
4. ダイアログ・モーダル関連の他のバグチェック
4-1. バックドロップクリックでダイアログが閉じない(軽微・仕様検討)
HTML <dialog> は仕様上、バックドロップ(半透明の背景)をクリックしてもダイアログは閉じません。ESCキーでは閉じます。現在のコードにはバックドロップクリックで閉じるハンドラが実装されていません。
これは一般的なモーダルUIの慣習(背景クリックで閉じる)とは異なるため、UX改善として検討する価値はありますが、バグとまでは言えません。
対応する場合は、dialogにonClickイベントを追加し、クリックイベントのターゲットがdialog自体(バックドロップ部分)であれば閉じるロジックを入れます。
4-2. スクロールロックが実装されていない(軽微)
SearchModalでは document.body.style.overflow = "hidden" でスクロールロックを行っていますが、ゲームのダイアログ(<dialog> 要素)ではスクロールロックが実装されていません。
ただし、showModal() で開いた <dialog> はブラウザがトップレイヤーに表示し、背後のコンテンツとのインタラクションをブロックするため、実質的にスクロールは制限されます。一部のブラウザ(特にiOS Safari)ではバックグラウンドスクロールが発生する場合がありますが、現時点では大きな問題ではありません。
4-3. aria-labelledby IDの非一意性(軽微・同一ページ上では影響なし)
以下のIDが複数のコンポーネントで重複しています:
howtoplay-title: kanji-kanaru と yoji-kimeru で使用result-title: kanji-kanaru と yoji-kimeru で使用stats-title: kanji-kanaru と yoji-kimeru で使用
nakamawake と irodori は適切にプレフィックス付きのID(nakamawake-howtoplay-title 等)を使用しています。
これらのゲームは別のページで表示されるため、同一DOM上でIDが重複することは通常ありません。しかし、ベストプラクティスとしてはゲーム名のプレフィックスを付けるべきです。将来的にゲーム一覧ページなどで複数ゲームが同一ページに表示される可能性を考慮すると、修正が望ましいです。
4-4. コードの重複(設計上の改善点)
全12個のダイアログコンポーネントが同一のuseRef + useEffect + useCallbackパターンを個別に実装しています。共通のカスタムフック(useDialog)や共通のベースコンポーネントに抽出するリファクタリングが望ましいですが、バグではなく改善提案です。
5. まとめ
| 問題 | 深刻度 | 影響範囲 | 修正優先度 |
|---|---|---|---|
| ダイアログが左上に表示される | 高 | 全4ゲーム x 3モーダル = 12箇所 | 高(今回修正) |
| バックドロップクリック未対応 | 低 | 全12ダイアログ | 低(UX改善として検討) |
| スクロールロック未実装 | 低 | 全12ダイアログ | 低(一部環境のみ) |
| aria-labelledby ID非一意 | 低 | 6ダイアログ(kanji-kanaru, yoji-kimeru) | 低(影響は限定的) |
| コード重複 | 情報 | 全12ダイアログ | 低(リファクタリング) |