display の切り替えとは何か
要素の「表示・非表示」を制御する最基本の方法が display の切り替えです。display: none にすると要素は完全に消え、ページのレイアウト計算からも外れます。再表示するときは本来の display(block・inline・flex・grid など)を戻します。ここが重要です:消す方式と戻し方を正しく選ばないと、レイアウト崩れやアクセシビリティの問題が起きます。
最小構成の切り替え方法(クラス方式とインライン方式)
クラス方式(推奨:保守性が高い)
<style>
.is-hidden { display: none !important; }
</style>
<button id="toggle">切り替え</button>
<div id="panel" class="panel">内容</div>
<script>
const btn = document.getElementById("toggle");
const panel = document.getElementById("panel");
btn.addEventListener("click", () => {
const hidden = panel.classList.toggle("is-hidden");
btn.textContent = hidden ? "開く" : "閉じる";
});
</script>
HTMLここが重要です:見た目のルールは CSS に置き、JS は“状態クラス”だけ触る。ルールが一箇所に集約され、チーム開発で壊れにくくなります。
インライン方式(最短だが設計が分散しやすい)
<button id="toggle">切り替え</button>
<div id="panel" style="display: block;">内容</div>
<script>
const btn = document.getElementById("toggle");
const panel = document.getElementById("panel");
btn.addEventListener("click", () => {
const isHidden = panel.style.display === "none";
panel.style.display = isHidden ? "block" : "none";
btn.textContent = isHidden ? "閉じる" : "開く";
});
</script>
HTMLここが重要です:その場の小さな UI には便利ですが、画面全体では「どこが display を決めているのか」が分散します。基本はクラス方式、インラインは例外的に。
深掘り:元の display を覚えて正しく戻す
block か inline か flex か——戻し先を間違えない
要素の本来の表示モードはさまざまです。毎回 “block” に戻すと、inline 要素や flex コンテナが壊れます。安全に扱うには「初期表示値」を覚えておきます。
<div id="toolbar" class="toolbar">…</div>
<script>
const el = document.getElementById("toolbar");
// 初回に本来の display を記録(空文字なら CSS が決める)
const original = getComputedStyle(el).display;
el.dataset.originalDisplay = original === "none" ? "" : original; // “none”なら空にし CSS に委ねる
function show(el) {
el.style.display = el.dataset.originalDisplay || "";
}
function hide(el) {
el.style.display = "none";
}
</script>
HTMLここが重要です:display の“正解”は要素次第。getComputedStyle で一度だけ取り、data-* に記録して使い回すと安全です。
表示の種類とアクセシビリティ(見え方だけでなく意味も)
display: none と visibility: hidden の違い
- display: none
- 完全に消える。レイアウトから除外。スクリーンリーダーにも読まれないことが多い。
- visibility: hidden
- その場所は確保されるが見えない。スクリーンリーダーには読まれることがある。
ここが重要です:操作不能にしたい非表示は display: none。見えないが領域を保持したいなら visibility: hidden。意味が違います。
スクリーンリーダーとフォーカス管理
「見えない=操作不可」に揃えるため、非表示時はフォーカスも外します。
function hideAccessibly(el) {
el.classList.add("is-hidden"); // 視覚的に隠す
el.setAttribute("aria-hidden", "true"); // 読み上げ対象から外す
el.inert = true; // クリック・フォーカスを無効(対応ブラウザ)
}
function showAccessibly(el) {
el.classList.remove("is-hidden");
el.setAttribute("aria-hidden", "false");
el.inert = false;
}
JavaScriptここが重要です:視覚・読み上げ・フォーカスの整合性を取る。特にモーダルやメニューは“見えないのに tab で入れる”事故を防ぐ必要があります。
アニメーションする場合の考え方(display は直接は動かない)
display はトランジション不可。ラッパーで“擬似的に”見せる
<style>
.drawer { overflow: hidden; max-height: 0; transition: max-height 200ms ease; }
.drawer.is-open { max-height: 300px; } /* 実際の高さに合わせて十分な値に */
</style>
<button id="toggle">開く</button>
<div id="drawer" class="drawer">…内容…</div>
<script>
const drawer = document.getElementById("drawer");
document.getElementById("toggle").addEventListener("click", () => {
const open = drawer.classList.toggle("is-open");
// 開閉の文言同期
});
</script>
HTMLここが重要です:display はアニメーションできません。高さ・不透明度・transform を使うのが定石。開閉はクラス切り替え、動きは CSS に任せます。
フェードの場合の設計
<style>
.fade { opacity: 0; pointer-events: none; transition: opacity 180ms; }
.fade.is-show { opacity: 1; pointer-events: auto; }
</style>
HTMLここが重要です:opacity と pointer-events を組み合わせると“見えないが操作も不可”が実現できます。読み上げの制御が必要なら aria-hidden も併用します。
代表パターンの実装例(ドロップダウン・モーダル)
ドロップダウンメニュー
<button id="open" aria-expanded="false">メニュー</button>
<ul id="menu" class="menu is-hidden" role="menu">
<li role="menuitem">A</li>
<li role="menuitem">B</li>
</ul>
<style>
.is-hidden { display: none !important; }
</style>
<script>
const btn = document.getElementById("open");
const menu = document.getElementById("menu");
btn.addEventListener("click", () => {
const hidden = menu.classList.toggle("is-hidden");
btn.setAttribute("aria-expanded", String(!hidden));
});
// メニュー外クリックで閉じる
document.addEventListener("click", (e) => {
if (!(e.target instanceof Element)) return;
if (!menu.contains(e.target) && e.target !== btn) {
menu.classList.add("is-hidden");
btn.setAttribute("aria-expanded", "false");
}
});
</script>
HTMLここが重要です:表示状態(is-hidden)を“単一情報源”にし、aria-expanded を同期させる。外側クリックで閉じるのは UX の基本。
モーダル(背景ロックとフォーカス制御)
<button id="show">開く</button>
<div id="backdrop" class="backdrop is-hidden"></div>
<div id="modal" class="modal is-hidden" role="dialog" aria-modal="true">
<button id="close">閉じる</button>
</div>
<style>
.is-hidden { display: none !important; }
.backdrop { position: fixed; inset: 0; background: rgba(0,0,0,.4); }
.modal { position: fixed; inset: 20% auto auto 20%; background: #fff; padding: 16px; }
.lock { overflow: hidden; } /* body に付ける */
</style>
<script>
const body = document.body;
const modal = document.getElementById("modal");
const backdrop = document.getElementById("backdrop");
const showBtn = document.getElementById("show");
const closeBtn = document.getElementById("close");
function openModal() {
modal.classList.remove("is-hidden");
backdrop.classList.remove("is-hidden");
body.classList.add("lock");
modal.setAttribute("aria-hidden", "false");
modal.querySelector("button")?.focus();
}
function closeModal() {
modal.classList.add("is-hidden");
backdrop.classList.add("is-hidden");
body.classList.remove("lock");
modal.setAttribute("aria-hidden", "true");
showBtn.focus();
}
showBtn.addEventListener("click", openModal);
closeBtn.addEventListener("click", closeModal);
backdrop.addEventListener("click", closeModal);
</script>
HTMLここが重要です:背景スクロールのロック、初期フォーカス、閉じた後のフォーカス返却まで面倒を見る。アクセシビリティが揃うと“自然な”体験になります。
落とし穴と回避策(タイミング・競合・テスト)
DOM がないタイミングで触らない
DOMContentLoaded 後、または defer スクリプトで実行。常に null ガードを入れます。ここが重要です:初期化が安定します。
CSS と JS の契約を揃える
- 非表示は is-hidden に統一(!important で強くしておく)
- 状態クラスは is-、テーマは theme-、種類は type-* に分ける
ここが重要です:クラス命名の契約が整っていると、表示制御のコードが短く、読みやすくなります。
テスト観点
- 画面上は隠れているか(視覚)
- Tab でフォーカスできないか(操作)
- スクリーンリーダーに読まれないか(aria/inert)
- レイアウトに影響が出ていないか(display と visibility の違い)
ここが重要です:表示・操作・読み上げ・レイアウトの4視点で確認するのが“安全な切り替え”の基準です。
まとめ
display の切り替えは「表示・非表示」の最短手。基本はクラス方式で一元管理し、インラインは例外的に。元の display を記録して正しく戻し、アクセシビリティ(aria-hidden・inert・フォーカス管理)を揃える。アニメーションは display を直接動かさず、height・opacity・transform とクラス切り替えで実現。命名と契約を整え、4視点(視覚・操作・読み上げ・レイアウト)でテストすれば、初心者でも壊れにくい表示制御が書けます。
