ASP.NET Web Formsで同じ位置に重なる複数のPanelを扱うと、編集したいパネル以外が邪魔になりがちです。本記事では「選択した1枚だけ作業しやすくし、他のパネルは右端へ退避させる」ためのUI設計と、CSS+JavaScriptで実現する具体例をまとめます。
複数のPanelを「選択した1枚だけ残す」時に整理しておくべきこと
最初に押さえたいのは、目的が「パネルを物理的に右へ飛ばすこと」そのものではなく、ユーザーが今触っている1つに集中できる状態を作ることだという点です。見た目を派手に動かすよりも、次の条件を満たす方が結果的に使いやすく、保守もしやすくなります。
- 操作対象(選択パネル)が常に分かる(見出し、強調、フォーカスなど)
- 他パネルに「戻れる」導線がある(縮小状態でもクリックできる、折りたたみでも見出しが残る)
- レスポンシブで破綻しにくい(画面幅が変わっても横スクロールやはみ出しが起きない)
- Web Forms特有のID変換やポストバックと相性が良い(ClientIDやUpdatePanelでも壊れない)
この観点で見ると、実装方針は大きく「UIを変えてシンプルに解決する」か「見た目の退避をCSS+JavaScriptで実現する」の2択に整理できます。
解決策の全体像:おすすめは「アコーディオン」か「Flexboxで縮小退避」
先に結論を整理すると、次の2案が現実的です。要件が「1つだけ開いて、他は閉じたい」ならアコーディオン(またはタブ)が第一候補です。要件が「他パネルも“存在”は残しつつ右端へ寄せたい」ならFlexbox+クラス切替が向きます。
| 方針 | 何を実現するか | メリット | 注意点 | 向いているケース |
|---|---|---|---|---|
| アコーディオンUI(UI設計を変える) | 見出しを残して、選択セクションだけ展開。他は折りたたむ。 | 実装が比較的簡単/UIとして馴染みがある/レイアウトが安定しやすい | 「右端へ退避」という見た目は再現しない(ただし目的は満たせることが多い) | フォーム入力、設定画面、FAQのように「1つずつ見たい」 |
| CSS+JavaScript(Flexbox+クラス切替) | 選択パネルを拡大し、他は縮小して右端へ寄せる。必要なら並び替えも。 | 「退避している感」が出る/縮小状態のままヘッダだけ残せる/UIの自由度が高い | CSS/JSの設計が必要/UpdatePanelや動的生成で再バインドが必要なことがある | 常に“複数ある”ことを示したい、ワークスペース風のUIにしたい |
避けたい“力技”:leftを極端に大きくして画面外へ飛ばす方法
質問者が試していたような Panel.Style("left") = "9541px" など、leftを大きくして画面外に逃がす手法は、短期的には動いて見えることがあります。しかし、長期運用や端末差・レスポンシブ対応を考えるとトラブルになりやすいので、採用する前にデメリットを理解しておくことが重要です。
| 観点 | leftで飛ばす(position依存) | クラス切替(display/flex/transform) |
|---|---|---|
| 前提条件 | position(absolute/relative等)や親要素の基準が必要 | 基本はCSS設計だけで成立 |
| レスポンシブ | 画面幅によっては横スクロールが出たり、戻ってこないことがある | flexやdisplay制御なら画面幅変化に強い |
| 保守性 | 「9541px」など意味のない魔法値が増えがち | 状態をクラス名で表現でき、意図が読み取りやすい |
| アクセシビリティ | 見えないのにフォーカスが当たる、読み上げが残るなどが起こりやすい | display:noneやaria属性で整合性を取りやすい |
「見えなくする」なら display:none、「縮小して残す」ならFlexbox、「アニメーション込みで外へ逃がす」なら transform: translateX() といった形で、目的に合うCSSを選ぶ方が安全です。
推奨案:アコーディオンUIで“1つだけ集中”を素直に実現する
「選択したものだけ作業しやすい状態にしたい」という要件は、実はアコーディオン(折りたたみ)が最もまっすぐ刺さることが多いです。クリックできる見出しが常に残るため、ユーザーは迷子になりにくく、実装側も「開く・閉じる」だけに集中できます。
Web Forms(VB.NET)でも、Panelの中身はそのまま使えます。ポイントはサーバー側で頑張るのではなく、表示後の振る舞いはブラウザ側で完結させることです。
アコーディオンが向いている場面
- パネルの役割が「セクション」や「手順」になっている(入力フォーム、設定、手続き)
- 常に1つだけ開いていればよい(同時に2つを見比べない)
- スマホや小さい画面でも破綻させたくない
jQuery UI Accordionの最小例(Panelをそのまま入れる)
例えば、見出しと内容の組を5つ用意して、アコーディオン化します。Panelの中には既存のサーバーコントロールを入れて構いません。
<!-- CSS/JSはプロジェクト方針に合わせて読み込み(CDNでもローカルでもOK) -->
<link rel="stylesheet" href="https://code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.min.js"></script>
<div id="workAccordion">
<h3>パネルA</h3>
<div>
<asp:Panel ID="PanelA" runat="server">
<!-- ここに入力欄やボタンなど -->
</asp:Panel>
</div>
<h3>パネルB</h3>
<div>
<asp:Panel ID="PanelB" runat="server">
...
</asp:Panel>
</div>
<!-- C〜Eも同様に -->
</div>
<script>
$(function () {
$("#workAccordion").accordion({
collapsible: true,
heightStyle: "content"
});
});
</script>
この方式なら「右へ退避」という表現はしなくても、ユーザー体験としては“他が邪魔にならず、必要なら見出しからすぐ戻れる”を実現できます。UIとしての学習コストも低く、まず最初に検討する価値があります。
退避の見た目を作りたい:CSS+JavaScriptで「選択パネル拡大、他は縮小して右端へ」
ここからは、質問のニュアンスにより近い「選択した1枚だけ大きくし、他のパネルを右端へ押しやる」実装例です。ポイントは次の3つです。
- パネルは同じサイズ・同じ場所に重ねるのではなく、横並びに配置できる土台(Flexbox)を作る
- クリックされたパネルにactive、それ以外にshrinkを付けて幅を制御する
- 必要ならinsertBefore()で選択パネルを先頭へ移動し、操作対象が左側に寄るようにする
HTML(ASPX)例:Panelにクラスを付けておく
Web FormsではClientIDが自動変換されることが多いので、JavaScript側はIDに依存せずクラスで拾うのがおすすめです。クリック対象はボタンにするとキーボード操作にも強くなります。
<div class="panelDock" id="panelDock">
<asp:Panel ID="Panel1" runat="server" CssClass="dockPanel">
<button type="button" class="dockPanel__header" data-dock-toggle>パネル1</button>
<div class="dockPanel__body">
<p>ここにPanel1の入力欄やボタンを配置します。</p>
</div>
</asp:Panel>
<asp:Panel ID="Panel2" runat="server" CssClass="dockPanel">
<button type="button" class="dockPanel__header" data-dock-toggle>パネル2</button>
<div class="dockPanel__body">
<p>Panel2のコンテンツ。</p>
</div>
</asp:Panel>
<asp:Panel ID="Panel3" runat="server" CssClass="dockPanel">
<button type="button" class="dockPanel__header" data-dock-toggle>パネル3</button>
<div class="dockPanel__body">...</div>
</asp:Panel>
<asp:Panel ID="Panel4" runat="server" CssClass="dockPanel">
<button type="button" class="dockPanel__header" data-dock-toggle>パネル4</button>
<div class="dockPanel__body">...</div>
</asp:Panel>
<asp:Panel ID="Panel5" runat="server" CssClass="dockPanel">
<button type="button" class="dockPanel__header" data-dock-toggle>パネル5</button>
<div class="dockPanel__body">...</div>
</asp:Panel>
</div>
CSS例:Flexboxで「1枚だけ広い、他は細い」状態を作る
縮小したパネルは幅を固定し、コンテンツを隠してヘッダだけ残すと「右端へ退避している」印象が出せます。アニメーションはtransitionで十分滑らかになります。
/* 全体の器:横並びにする */
.panelDock {
display: flex;
align-items: stretch;
width: 100%;
min-height: 320px; /* 必要に応じて */
overflow: hidden; /* 横スクロールを出したくない場合 */
gap: 8px; /* 余白はお好みで */
}
/* 各Panel(ASP.NET Panelは最終的にdivとして出力される想定) */
.dockPanel {
flex: 1 1 0;
min-width: 220px; /* 全員が通常状態のときの最低幅 */
border: 1px solid #ddd;
border-radius: 8px;
background: #fff;
overflow: hidden;
transition: flex-basis 0.25s ease, max-width 0.25s ease;
}
/* ヘッダ(クリックできるタブ的な役割) */
.dockPanel__header {
display: block;
width: 100%;
padding: 12px 14px;
border: 0;
background: #f6f6f6;
font-weight: 600;
text-align: left;
cursor: pointer;
}
/* コンテンツ部 */
.dockPanel__body {
padding: 14px;
}
/* 選択中:とにかく広く使う */
.dockPanel.is-active {
flex: 1 1 auto;
max-width: 100%;
}
/* 非選択:細くして右側へ“退避”させる */
.dockPanel.is-shrink {
flex: 0 0 56px; /* ここを小さくすると「退避」感が増える */
max-width: 56px;
}
/* 退避中は中身を隠し、ヘッダだけ残す */
.dockPanel.is-shrink .dockPanel__body {
display: none;
}
/* 退避中でもタイトルが読めるように縦書きにする例(好みで) */
.dockPanel.is-shrink .dockPanel__header {
writing-mode: vertical-rl;
text-orientation: mixed;
height: 100%;
padding: 10px 6px;
}
ここまでで、クリック時にクラスが切り替われば「選択パネルが広く、他が細く」なります。Flexboxなので、広いパネルが空間を取るほど残りが右側へ寄り、結果として“右端へ退避”して見える作りです。
状態クラスの設計例
状態を表すクラス名を決めておくと、後から仕様変更が入っても影響範囲を抑えられます。
| クラス | 意味 | 主なスタイル | ユーザー体験 |
|---|---|---|---|
| .is-active | 選択中のパネル | flexを大きく、max-width制限なし | 編集領域が広くなり、集中できる |
| .is-shrink | 非選択のパネル | 幅固定(小さく)、本文非表示 | 右端へ寄り、邪魔にならないが存在は分かる |
| (クラスなし) | 初期/リセット状態 | 全員が同じflex | 全パネルを俯瞰して選べる |
JavaScript例:クリックでactive/shrinkを切り替え、必要なら先頭へ移動
クリックされたパネル以外を縮小し、選択したパネルは拡大します。さらに insertBefore() で先頭へ移動すると、操作対象が左端に寄るため「作業領域を確保した」感が出ます。もう一度クリックしたらリセットする動きも入れておくと便利です。
<script>
(function () {
const dock = document.getElementById("panelDock");
if (!dock) return;
const getPanels = () => Array.from(dock.querySelectorAll(".dockPanel"));
function resetPanels() {
getPanels().forEach(p => {
p.classList.remove("is-active", "is-shrink");
const btn = p.querySelector("[data-dock-toggle]");
if (btn) btn.setAttribute("aria-expanded", "false");
});
}
function activatePanel(panel) {
const panels = getPanels();
panels.forEach(p => {
p.classList.toggle("is-active", p === panel);
p.classList.toggle("is-shrink", p !== panel);
const btn = p.querySelector("[data-dock-toggle]");
if (btn) btn.setAttribute("aria-expanded", p === panel ? "true" : "false");
});
// 選択パネルを先頭へ(“左に寄せる”)
if (dock.firstElementChild !== panel) {
dock.insertBefore(panel, dock.firstElementChild);
}
// 必要なら見える位置へスクロール
panel.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "start" });
}
dock.addEventListener("click", function (e) {
const toggle = e.target.closest("[data-dock-toggle]");
if (!toggle) return;
const panel = toggle.closest(".dockPanel");
if (!panel) return;
const isActive = panel.classList.contains("is-active");
if (isActive) {
resetPanels();
return;
}
activatePanel(panel);
});
// 初期状態:全員を同じ幅にしておく
resetPanels();
})();
</script>
この実装はサーバー側(VB.NET)に依存しません。Web Formsで行うことは「Panelを出力してクラスを付ける」程度で、動作はブラウザ側で完結します。
Web Forms(VB.NET)でハマりやすいポイントと対策
CSS+JavaScript方式は強力ですが、Web Formsならではの事情でつまずくことがあります。よくあるポイントを先に潰しておくと、実装が安定します。
ClientIDが変わる問題:ID参照をやめてクラス・data属性で拾う
Web Formsのサーバーコントロールは、親コンテナの影響で出力IDが変わることがあります。今回のように複数パネルへ同じ振る舞いを付けたい場合、ID固定に頼らず「クラスとdata属性」でイベント委譲するのが堅実です。
- クリック対象は
[data-dock-toggle]のようにdata属性を付ける - パネルは
.dockPanelのようにクラスでまとめる - どうしてもID固定が必要なら
ClientIDMode="Static"を検討する
UpdatePanelで部分更新する場合:再バインドのタイミングを意識する
UpdatePanelでパネルの中身を更新すると、クリックイベントが効かなくなることがあります。今回の実装はコンテナにイベントを付けているので比較的壊れにくいですが、コンテナ自体を置き換えるような更新をすると再設定が必要です。
Microsoft AJAX(ScriptManager)を使っている場合は、次のように Sys.Application.add_load で初期化する方法もあります(既存の構成に合わせて選んでください)。
<script>
function initDock() {
// ここに上で示した初期化処理を入れる(重複バインドに注意)
}
if (window.Sys && Sys.Application) {
Sys.Application.add_load(initDock);
} else {
document.addEventListener("DOMContentLoaded", initDock);
}
</script>
ポストバックで状態が戻る問題:選択状態をHiddenFieldに保存する
「選択中のパネルをサーバー処理で更新したい」「ポストバック後も同じパネルを開いた状態にしたい」場合は、選択状態をHiddenFieldに入れておくと扱いやすいです。
<asp:HiddenField ID="SelectedPanelKey" runat="server" />
<script>
function setSelectedKey(panelKey) {
const hf = document.getElementById("<%= SelectedPanelKey.ClientID %>");
if (hf) hf.value = panelKey;
}
</script>
Panelごとに data-panel-key を持たせ、クリック時にHiddenFieldへ書き込み、ページ読み込み時にそのキーのPanelへ is-active を付与する、といった流れにすると「見た目」と「サーバー処理」を両立しやすくなります。
見た目と操作性を一段上げる改善アイデア
基本形ができたら、次の小さな改善で「使えるUI」から「迷わないUI」へ一気に近づきます。
縮小状態でも“戻れる”ようにする
- 縮小時は本文を隠すが、ヘッダは常に押せるようにする
- ヘッダを縦書きにする/アイコン+短いラベルにするなど、幅が小さくても判別できる工夫を入れる
- 選択中はヘッダ背景を変える、枠線を太くするなど視覚的な強調を入れる
キーボード操作とフォーカスを整える
クリック前提のUIでも、ボタン要素を使うだけでキーボード操作が一気に改善します。さらに、選択後にパネル内の最初の入力欄へフォーカスを移すと作業が速くなります。
// 例:activatePanel(panel) 内で最初の入力へフォーカス
const firstInput = panel.querySelector("input, select, textarea, button");
if (firstInput) firstInput.focus({ preventScroll: true });
DOMを動かさずに並び替えたい場合:flexのorderを使う
insertBefore() は分かりやすい反面、DOMの順序が変わります。ログやテストの都合でDOM順を固定したい場合は、CSSの order で見た目の順だけ変える方法もあります。
/* activeだけ左に寄せたい */
.dockPanel { order: 10; }
.dockPanel.is-active { order: 0; }
これならDOMはそのままで、表示だけ「選択が左へ」になります。どちらが良いかは、要件(アクセシビリティ、読み上げ順、テスト方針)で選びましょう。
“退避”の演出を強めたい場合:transformで軽くスライドさせる
Flexboxの幅変更だけでも十分ですが、縮小時にわずかにスライドする演出を入れると「押し出された」印象が出ます。重いアニメーションは避け、transform中心にするとパフォーマンスが安定します。
.dockPanel {
transition: flex-basis 0.25s ease, max-width 0.25s ease, transform 0.25s ease;
}
.dockPanel.is-shrink {
transform: translateX(8px);
}
トラブルシューティング:よくある症状とチェックポイント
最後に、実装時によく出る症状をまとめます。原因を切り分けると、だいたいはCSSかイベントの問題に集約されます。
| 症状 | よくある原因 | 対策 |
|---|---|---|
| クリックしても何も変わらない | イベントがバインドされていない/セレクタが合っていない | コンテナIDが正しいか、[data-dock-toggle] が出力されているか確認する |
| 縮小したパネルが見えない・押せない | 幅が小さすぎる/overflowやz-indexで隠れている | flex: 0 0 56px を増やす、overflow の指定を見直す |
| 横スクロールが出てしまう | 合計幅が画面を超えている/min-widthが大きすぎる | コンテナにoverflow:hidden、各Panelのmin-widthを調整する |
| UpdatePanel更新後に動かなくなる | DOMが差し替わり、初期化が外れている | Sys.Application.add_load やDOMContentLoadedで再初期化する |
| ポストバック後に状態が戻る | クラスはクライアント側だけで保持している | HiddenFieldやlocalStorageで選択状態を保存し、復元する |
まとめ:目的に合わせて「UI変更」か「Flex退避」を選ぶ
複数のASP.NET Panelを扱うとき、操作性を上げる近道は「1つだけに集中できる状態を作る」ことです。目的が“折りたたんで見出しだけ残せれば十分”なら、アコーディオンUIが最も素直で堅牢です。
一方で、「退避している見た目」や「ワークスペースのような操作感」を出したいなら、Flexbox+クラス切替が強力です。VB.NET(Web Forms)でも問題なく使え、サーバー側はPanel出力に専念できます。
まずは小さく作って、縮小幅や見出しの見せ方を調整し、チームやユーザーの使い方にフィットする落とし所を探すのが、実務で失敗しにくい進め方です。

コメント