マスター/詳細2ペイン
左に一覧、右に詳細を並べるマスター/詳細レイアウト。項目クリックで右ペインが切替わり、狭い画面では1ペイン表示に自動で切替わり戻るボタンで一覧へ戻れる。
ライブデモ
コード
HTML
<!-- マスター/詳細2ペイン:左のリストを選ぶと右の詳細が切り替わる。狭幅では1ペイン+戻るボタン -->
<div class="mdx" id="mdxRoot">
<aside class="mdx__list" aria-label="メッセージ一覧">
<div class="mdx__list-head">
<h2>受信トレイ</h2>
<span class="mdx__count">6件</span>
</div>
<ul class="mdx__items">
<li>
<button class="mdx__item is-active" data-target="d1" type="button">
<span class="mdx__avatar" style="background:#4338ca">佐</span>
<span class="mdx__item-body">
<b>佐藤 美咲</b>
<span class="mdx__item-sub">請求書のご確認について</span>
</span>
<span class="mdx__item-time">10:24</span>
</button>
</li>
<li>
<button class="mdx__item" data-target="d2" type="button">
<span class="mdx__avatar" style="background:#0ea5a4">田</span>
<span class="mdx__item-body">
<b>田中 健一</b>
<span class="mdx__item-sub">来週の定例MTGの件</span>
</span>
<span class="mdx__item-time">09:47</span>
</button>
</li>
<li>
<button class="mdx__item" data-target="d3" type="button">
<span class="mdx__avatar" style="background:#c026d3">鈴</span>
<span class="mdx__item-body">
<b>鈴木 遥</b>
<span class="mdx__item-sub">デザイン修正案を送ります</span>
</span>
<span class="mdx__item-time">昨日</span>
</button>
</li>
<li>
<button class="mdx__item" data-target="d4" type="button">
<span class="mdx__avatar" style="background:#d97706">高</span>
<span class="mdx__item-body">
<b>高橋 蓮</b>
<span class="mdx__item-sub">契約更新のご案内</span>
</span>
<span class="mdx__item-time">昨日</span>
</button>
</li>
<li>
<button class="mdx__item" data-target="d5" type="button">
<span class="mdx__avatar" style="background:#2563eb">伊</span>
<span class="mdx__item-body">
<b>伊藤 直樹</b>
<span class="mdx__item-sub">出荷スケジュールの共有</span>
</span>
<span class="mdx__item-time">火曜</span>
</button>
</li>
<li>
<button class="mdx__item" data-target="d6" type="button">
<span class="mdx__avatar" style="background:#059669">中</span>
<span class="mdx__item-body">
<b>中村 陽菜</b>
<span class="mdx__item-sub">アンケートのお願い</span>
</span>
<span class="mdx__item-time">月曜</span>
</button>
</li>
</ul>
</aside>
<section class="mdx__detail" aria-live="polite">
<article class="mdx__panel is-active" id="d1">
<button class="mdx__back" type="button" data-back>← 一覧へ戻る</button>
<header class="mdx__panel-head">
<span class="mdx__avatar mdx__avatar--lg" style="background:#4338ca">佐</span>
<div>
<h3>請求書のご確認について</h3>
<p>佐藤 美咲 <span><m.sato@example.com></span> ・ 10:24</p>
</div>
</header>
<div class="mdx__panel-body">
<p>お世話になっております。先月分のご請求書を添付にてお送りいたします。内容にお気づきの点がございましたら、今週中にご連絡いただけますと幸いです。</p>
<p>お忙しいところ恐縮ですが、何卒よろしくお願いいたします。</p>
</div>
</article>
<article class="mdx__panel" id="d2">
<button class="mdx__back" type="button" data-back>← 一覧へ戻る</button>
<header class="mdx__panel-head">
<span class="mdx__avatar mdx__avatar--lg" style="background:#0ea5a4">田</span>
<div>
<h3>来週の定例MTGの件</h3>
<p>田中 健一 <span><k.tanaka@example.com></span> ・ 09:47</p>
</div>
</header>
<div class="mdx__panel-body">
<p>来週火曜の定例ミーティングですが、会議室が変更になりましたのでご連絡いたします。3階の第2会議室での開催となります。</p>
<p>資料は前日までに共有フォルダへアップロードをお願いします。</p>
</div>
</article>
<article class="mdx__panel" id="d3">
<button class="mdx__back" type="button" data-back>← 一覧へ戻る</button>
<header class="mdx__panel-head">
<span class="mdx__avatar mdx__avatar--lg" style="background:#c026d3">鈴</span>
<div>
<h3>デザイン修正案を送ります</h3>
<p>鈴木 遥 <span><h.suzuki@example.com></span> ・ 昨日</p>
</div>
</header>
<div class="mdx__panel-body">
<p>ご依頼いただいたトップページの修正案がまとまりましたので共有します。配色とボタンのサイズを中心に調整しました。</p>
<p>ご確認のうえ、フィードバックをいただけますと幸いです。</p>
</div>
</article>
<article class="mdx__panel" id="d4">
<button class="mdx__back" type="button" data-back>← 一覧へ戻る</button>
<header class="mdx__panel-head">
<span class="mdx__avatar mdx__avatar--lg" style="background:#d97706">高</span>
<div>
<h3>契約更新のご案内</h3>
<p>高橋 蓮 <span><r.takahashi@example.com></span> ・ 昨日</p>
</div>
</header>
<div class="mdx__panel-body">
<p>現在ご利用中のプランの契約更新時期が近づいております。更新内容と新プランのご案内を添付いたしましたのでご確認ください。</p>
</div>
</article>
<article class="mdx__panel" id="d5">
<button class="mdx__back" type="button" data-back>← 一覧へ戻る</button>
<header class="mdx__panel-head">
<span class="mdx__avatar mdx__avatar--lg" style="background:#2563eb">伊</span>
<div>
<h3>出荷スケジュールの共有</h3>
<p>伊藤 直樹 <span><n.ito@example.com></span> ・ 火曜</p>
</div>
</header>
<div class="mdx__panel-body">
<p>今月分の出荷スケジュールを更新しました。天候の影響で一部地域の到着が1〜2日遅れる見込みです。</p>
</div>
</article>
<article class="mdx__panel" id="d6">
<button class="mdx__back" type="button" data-back>← 一覧へ戻る</button>
<header class="mdx__panel-head">
<span class="mdx__avatar mdx__avatar--lg" style="background:#059669">中</span>
<div>
<h3>アンケートのお願い</h3>
<p>中村 陽菜 <span><h.nakamura@example.com></span> ・ 月曜</p>
</div>
</header>
<div class="mdx__panel-body">
<p>サービス向上のため、簡単なアンケートにご協力いただけますと幸いです。所要時間は3分程度です。</p>
</div>
</article>
</section>
</div>
CSS
/* 全体:左にリスト、右に詳細を並べる2ペイン構成。狭幅では1ペイン表示へ切り替え */
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: "Hiragino Sans", system-ui, sans-serif;
background: #f4f5f9;
color: #1c2130;
min-height: 100vh;
display: block; /* ビルダーの flex 中央寄せを解除し、フルブリードの2ペインを表示 */
}
/* ルート:width:100% が無いと親の flex 中央寄せで潰れるため必須 */
.mdx { width: 100%; min-height: 100vh; display: flex; position: relative; }
/* 左:リストペイン */
.mdx__list {
width: 300px; flex-shrink: 0;
background: #fff; border-right: 1px solid #e5e8f0;
display: flex; flex-direction: column;
}
.mdx__list-head {
display: flex; align-items: baseline; justify-content: space-between;
padding: 18px 18px 12px; position: sticky; top: 0; background: #fff; z-index: 1;
}
.mdx__list-head h2 { font-size: 16px; font-weight: 800; }
.mdx__count { font-size: 12px; color: #7c869c; font-weight: 700; }
.mdx__items { list-style: none; }
.mdx__item {
width: 100%; display: flex; align-items: center; gap: 10px;
font: inherit; text-align: left; cursor: pointer;
background: none; border: none; border-bottom: 1px solid #f0f1f6;
padding: 12px 18px; transition: background .15s ease;
}
.mdx__item:hover { background: #f7f8fc; }
.mdx__item.is-active { background: #eef0ff; box-shadow: inset 3px 0 0 #4338ca; }
.mdx__avatar {
width: 34px; height: 34px; border-radius: 50%; flex-shrink: 0;
display: grid; place-items: center; color: #fff; font-size: 13px; font-weight: 800;
}
.mdx__avatar--lg { width: 44px; height: 44px; font-size: 16px; }
.mdx__item-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.mdx__item-body b { font-size: 13px; }
.mdx__item-sub {
display: block; font-size: 12px; color: #6b7390;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.mdx__item-time { font-size: 11px; color: #99a1b8; flex-shrink: 0; }
/* 右:詳細ペイン */
.mdx__detail { flex: 1; min-width: 0; }
.mdx__panel {
display: none;
padding: 26px clamp(18px, 4vw, 40px);
max-width: 720px;
}
.mdx__panel.is-active { display: block; }
.mdx__back { display: none; }
.mdx__panel-head {
display: flex; gap: 14px; align-items: center;
padding-bottom: 16px; margin-bottom: 16px; border-bottom: 1px solid #e5e8f0;
}
.mdx__panel-head h3 { font-size: 18px; font-weight: 800; margin-bottom: 4px; }
.mdx__panel-head p { font-size: 12.5px; color: #7c869c; }
.mdx__panel-head p span { color: #a2abc2; }
.mdx__panel-body p { font-size: 14px; line-height: 1.9; margin-bottom: 14px; color: #333c50; }
/* 狭幅:1ペイン表示+戻るボタン(is-open は JS が root に付け外し) */
@media (max-width: 720px) {
.mdx__list { width: 100%; }
.mdx__detail { position: absolute; inset: 0; background: #fff; display: none; overflow-y: auto; }
.mdx.is-open .mdx__list { display: none; }
.mdx.is-open .mdx__detail { display: block; }
.mdx__back {
display: inline-flex; align-items: center; gap: 6px;
font: inherit; font-size: 13px; font-weight: 700; color: #4338ca;
background: none; border: none; cursor: pointer; margin-bottom: 14px; padding: 0;
}
}
@media (prefers-reduced-motion: reduce) {
.mdx__item { transition: none; }
}
JavaScript
// リスト項目クリックで右の詳細パネルを切替。狭幅では is-open で1ペイン表示にし、
// 戻るボタンで一覧へ戻す(null安全)
(() => {
const root = document.getElementById('mdxRoot');
if (!root) return;
const items = Array.from(root.querySelectorAll('.mdx__item'));
const panels = Array.from(root.querySelectorAll('.mdx__panel'));
const backBtns = Array.from(root.querySelectorAll('[data-back]'));
if (!items.length || !panels.length) return;
const show = (targetId) => {
if (!targetId) return;
items.forEach((it) => it.classList.toggle('is-active', it.dataset.target === targetId));
panels.forEach((p) => p.classList.toggle('is-active', p.id === targetId));
root.classList.add('is-open');
};
items.forEach((item) => {
item.addEventListener('click', () => show(item.dataset.target));
});
backBtns.forEach((btn) => {
btn.addEventListener('click', () => root.classList.remove('is-open'));
});
})();
🤖 AIエージェント用プロンプト
このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「マスター/詳細2ペイン」の効果を追加してください。
# 追加してほしい効果
マスター/詳細2ペイン(レイアウト & グリッド)
左に一覧、右に詳細を並べるマスター/詳細レイアウト。項目クリックで右ペインが切替わり、狭い画面では1ペイン表示に自動で切替わり戻るボタンで一覧へ戻れる。
# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】
# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- マスター/詳細2ペイン:左のリストを選ぶと右の詳細が切り替わる。狭幅では1ペイン+戻るボタン -->
<div class="mdx" id="mdxRoot">
<aside class="mdx__list" aria-label="メッセージ一覧">
<div class="mdx__list-head">
<h2>受信トレイ</h2>
<span class="mdx__count">6件</span>
</div>
<ul class="mdx__items">
<li>
<button class="mdx__item is-active" data-target="d1" type="button">
<span class="mdx__avatar" style="background:#4338ca">佐</span>
<span class="mdx__item-body">
<b>佐藤 美咲</b>
<span class="mdx__item-sub">請求書のご確認について</span>
</span>
<span class="mdx__item-time">10:24</span>
</button>
</li>
<li>
<button class="mdx__item" data-target="d2" type="button">
<span class="mdx__avatar" style="background:#0ea5a4">田</span>
<span class="mdx__item-body">
<b>田中 健一</b>
<span class="mdx__item-sub">来週の定例MTGの件</span>
</span>
<span class="mdx__item-time">09:47</span>
</button>
</li>
<li>
<button class="mdx__item" data-target="d3" type="button">
<span class="mdx__avatar" style="background:#c026d3">鈴</span>
<span class="mdx__item-body">
<b>鈴木 遥</b>
<span class="mdx__item-sub">デザイン修正案を送ります</span>
</span>
<span class="mdx__item-time">昨日</span>
</button>
</li>
<li>
<button class="mdx__item" data-target="d4" type="button">
<span class="mdx__avatar" style="background:#d97706">高</span>
<span class="mdx__item-body">
<b>高橋 蓮</b>
<span class="mdx__item-sub">契約更新のご案内</span>
</span>
<span class="mdx__item-time">昨日</span>
</button>
</li>
<li>
<button class="mdx__item" data-target="d5" type="button">
<span class="mdx__avatar" style="background:#2563eb">伊</span>
<span class="mdx__item-body">
<b>伊藤 直樹</b>
<span class="mdx__item-sub">出荷スケジュールの共有</span>
</span>
<span class="mdx__item-time">火曜</span>
</button>
</li>
<li>
<button class="mdx__item" data-target="d6" type="button">
<span class="mdx__avatar" style="background:#059669">中</span>
<span class="mdx__item-body">
<b>中村 陽菜</b>
<span class="mdx__item-sub">アンケートのお願い</span>
</span>
<span class="mdx__item-time">月曜</span>
</button>
</li>
</ul>
</aside>
<section class="mdx__detail" aria-live="polite">
<article class="mdx__panel is-active" id="d1">
<button class="mdx__back" type="button" data-back>← 一覧へ戻る</button>
<header class="mdx__panel-head">
<span class="mdx__avatar mdx__avatar--lg" style="background:#4338ca">佐</span>
<div>
<h3>請求書のご確認について</h3>
<p>佐藤 美咲 <span><m.sato@example.com></span> ・ 10:24</p>
</div>
</header>
<div class="mdx__panel-body">
<p>お世話になっております。先月分のご請求書を添付にてお送りいたします。内容にお気づきの点がございましたら、今週中にご連絡いただけますと幸いです。</p>
<p>お忙しいところ恐縮ですが、何卒よろしくお願いいたします。</p>
</div>
</article>
<article class="mdx__panel" id="d2">
<button class="mdx__back" type="button" data-back>← 一覧へ戻る</button>
<header class="mdx__panel-head">
<span class="mdx__avatar mdx__avatar--lg" style="background:#0ea5a4">田</span>
<div>
<h3>来週の定例MTGの件</h3>
<p>田中 健一 <span><k.tanaka@example.com></span> ・ 09:47</p>
</div>
</header>
<div class="mdx__panel-body">
<p>来週火曜の定例ミーティングですが、会議室が変更になりましたのでご連絡いたします。3階の第2会議室での開催となります。</p>
<p>資料は前日までに共有フォルダへアップロードをお願いします。</p>
</div>
</article>
<article class="mdx__panel" id="d3">
<button class="mdx__back" type="button" data-back>← 一覧へ戻る</button>
<header class="mdx__panel-head">
<span class="mdx__avatar mdx__avatar--lg" style="background:#c026d3">鈴</span>
<div>
<h3>デザイン修正案を送ります</h3>
<p>鈴木 遥 <span><h.suzuki@example.com></span> ・ 昨日</p>
</div>
</header>
<div class="mdx__panel-body">
<p>ご依頼いただいたトップページの修正案がまとまりましたので共有します。配色とボタンのサイズを中心に調整しました。</p>
<p>ご確認のうえ、フィードバックをいただけますと幸いです。</p>
</div>
</article>
<article class="mdx__panel" id="d4">
<button class="mdx__back" type="button" data-back>← 一覧へ戻る</button>
<header class="mdx__panel-head">
<span class="mdx__avatar mdx__avatar--lg" style="background:#d97706">高</span>
<div>
<h3>契約更新のご案内</h3>
<p>高橋 蓮 <span><r.takahashi@example.com></span> ・ 昨日</p>
</div>
</header>
<div class="mdx__panel-body">
<p>現在ご利用中のプランの契約更新時期が近づいております。更新内容と新プランのご案内を添付いたしましたのでご確認ください。</p>
</div>
</article>
<article class="mdx__panel" id="d5">
<button class="mdx__back" type="button" data-back>← 一覧へ戻る</button>
<header class="mdx__panel-head">
<span class="mdx__avatar mdx__avatar--lg" style="background:#2563eb">伊</span>
<div>
<h3>出荷スケジュールの共有</h3>
<p>伊藤 直樹 <span><n.ito@example.com></span> ・ 火曜</p>
</div>
</header>
<div class="mdx__panel-body">
<p>今月分の出荷スケジュールを更新しました。天候の影響で一部地域の到着が1〜2日遅れる見込みです。</p>
</div>
</article>
<article class="mdx__panel" id="d6">
<button class="mdx__back" type="button" data-back>← 一覧へ戻る</button>
<header class="mdx__panel-head">
<span class="mdx__avatar mdx__avatar--lg" style="background:#059669">中</span>
<div>
<h3>アンケートのお願い</h3>
<p>中村 陽菜 <span><h.nakamura@example.com></span> ・ 月曜</p>
</div>
</header>
<div class="mdx__panel-body">
<p>サービス向上のため、簡単なアンケートにご協力いただけますと幸いです。所要時間は3分程度です。</p>
</div>
</article>
</section>
</div>
【CSS】
/* 全体:左にリスト、右に詳細を並べる2ペイン構成。狭幅では1ペイン表示へ切り替え */
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: "Hiragino Sans", system-ui, sans-serif;
background: #f4f5f9;
color: #1c2130;
min-height: 100vh;
display: block; /* ビルダーの flex 中央寄せを解除し、フルブリードの2ペインを表示 */
}
/* ルート:width:100% が無いと親の flex 中央寄せで潰れるため必須 */
.mdx { width: 100%; min-height: 100vh; display: flex; position: relative; }
/* 左:リストペイン */
.mdx__list {
width: 300px; flex-shrink: 0;
background: #fff; border-right: 1px solid #e5e8f0;
display: flex; flex-direction: column;
}
.mdx__list-head {
display: flex; align-items: baseline; justify-content: space-between;
padding: 18px 18px 12px; position: sticky; top: 0; background: #fff; z-index: 1;
}
.mdx__list-head h2 { font-size: 16px; font-weight: 800; }
.mdx__count { font-size: 12px; color: #7c869c; font-weight: 700; }
.mdx__items { list-style: none; }
.mdx__item {
width: 100%; display: flex; align-items: center; gap: 10px;
font: inherit; text-align: left; cursor: pointer;
background: none; border: none; border-bottom: 1px solid #f0f1f6;
padding: 12px 18px; transition: background .15s ease;
}
.mdx__item:hover { background: #f7f8fc; }
.mdx__item.is-active { background: #eef0ff; box-shadow: inset 3px 0 0 #4338ca; }
.mdx__avatar {
width: 34px; height: 34px; border-radius: 50%; flex-shrink: 0;
display: grid; place-items: center; color: #fff; font-size: 13px; font-weight: 800;
}
.mdx__avatar--lg { width: 44px; height: 44px; font-size: 16px; }
.mdx__item-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.mdx__item-body b { font-size: 13px; }
.mdx__item-sub {
display: block; font-size: 12px; color: #6b7390;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.mdx__item-time { font-size: 11px; color: #99a1b8; flex-shrink: 0; }
/* 右:詳細ペイン */
.mdx__detail { flex: 1; min-width: 0; }
.mdx__panel {
display: none;
padding: 26px clamp(18px, 4vw, 40px);
max-width: 720px;
}
.mdx__panel.is-active { display: block; }
.mdx__back { display: none; }
.mdx__panel-head {
display: flex; gap: 14px; align-items: center;
padding-bottom: 16px; margin-bottom: 16px; border-bottom: 1px solid #e5e8f0;
}
.mdx__panel-head h3 { font-size: 18px; font-weight: 800; margin-bottom: 4px; }
.mdx__panel-head p { font-size: 12.5px; color: #7c869c; }
.mdx__panel-head p span { color: #a2abc2; }
.mdx__panel-body p { font-size: 14px; line-height: 1.9; margin-bottom: 14px; color: #333c50; }
/* 狭幅:1ペイン表示+戻るボタン(is-open は JS が root に付け外し) */
@media (max-width: 720px) {
.mdx__list { width: 100%; }
.mdx__detail { position: absolute; inset: 0; background: #fff; display: none; overflow-y: auto; }
.mdx.is-open .mdx__list { display: none; }
.mdx.is-open .mdx__detail { display: block; }
.mdx__back {
display: inline-flex; align-items: center; gap: 6px;
font: inherit; font-size: 13px; font-weight: 700; color: #4338ca;
background: none; border: none; cursor: pointer; margin-bottom: 14px; padding: 0;
}
}
@media (prefers-reduced-motion: reduce) {
.mdx__item { transition: none; }
}
【JavaScript】
// リスト項目クリックで右の詳細パネルを切替。狭幅では is-open で1ペイン表示にし、
// 戻るボタンで一覧へ戻す(null安全)
(() => {
const root = document.getElementById('mdxRoot');
if (!root) return;
const items = Array.from(root.querySelectorAll('.mdx__item'));
const panels = Array.from(root.querySelectorAll('.mdx__panel'));
const backBtns = Array.from(root.querySelectorAll('[data-back]'));
if (!items.length || !panels.length) return;
const show = (targetId) => {
if (!targetId) return;
items.forEach((it) => it.classList.toggle('is-active', it.dataset.target === targetId));
panels.forEach((p) => p.classList.toggle('is-active', p.id === targetId));
root.classList.add('is-open');
};
items.forEach((item) => {
item.addEventListener('click', () => show(item.dataset.target));
});
backBtns.forEach((btn) => {
btn.addEventListener('click', () => root.classList.remove('is-open'));
});
})();
# 外部ライブラリ
なし(追加ライブラリ不要)
# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。