display:noneとvisibility:hiddenって何が違うの?
要素を非表示にしたいとき、なんとなくdisplay: noneを書いていませんか。
もしくは逆に、なんとなくvisibility: hiddenを選んでいませんか。
実はこの2つ、見た目が「消える」という結果は同じでも、裏側で起きていることはまったく違います。
この違いを知らないまま実装すると、レイアウトが崩れたり、スクリーンリーダーの挙動が意図しないものになったりと、思わぬバグの原因になることがあるんです。
結論から言うと
- display: none → 要素が「存在しない」扱いになる。レイアウトのスペースも消える
- visibility: hidden → 要素は「見えない」だけ。レイアウトのスペースはそのまま残る
たったこれだけの違いですが、影響範囲は見た目・レイアウト・アクセシビリティ・パフォーマンスと多岐にわたります。順番に見ていきましょう。
レイアウトへの影響がまったく違う
一番わかりやすい違いはここです。
display: noneを指定すると、要素はDOMのレンダリングツリーから取り除かれたのと同じ扱いになります。そのため、その要素があった場所は周囲の要素が詰めて埋めてしまいます。
.hidden-display {
display: none;
}
一方visibility: hiddenは、要素を透明にして見えなくするだけで、レイアウト上のスペースはそのまま確保され続けます。
.hidden-visibility {
visibility: hidden;
}
タブ切り替えのように「非表示にした分だけ他の要素を詰めたい」場面ではdisplay: none、ローディング中のプレースホルダーのように「場所だけキープしておきたい」場面ではvisibility: hiddenが向いています。
opacity: 0という選択肢もありますが、こちらは要素を透明にするだけでクリックやフォーカスは有効なままです。見た目は同じでも動作がまったく違うので混同注意です。
クリックやフォーカスの扱いも違う
display: noneの要素は文字通り存在しないので、当然クリックもタブ移動でのフォーカスもできません。
visibility: hiddenの要素も、通常はクリックやフォーカスができない点は同じです。ただし後述するように、子要素の指定次第でこの挙動を上書きできてしまうという、少しクセのある性質を持っています。
微妙に差が出る「子要素の扱い」
ここが意外と知られていないポイントです。
display: noneを親要素に指定すると、子要素も含めてすべて非表示になります。子要素側で個別に上書きすることはできません。
ところがvisibility: hiddenは違います。親要素にhiddenを指定していても、子要素にvisibility: visibleを指定すれば、その子要素だけ表示を復活させることができるのです。
.parent {
visibility: hidden;
}
.child {
visibility: visible; /* 親が非表示でもこの子だけ見える */
}
ドロップダウンメニューのように「親のリストは隠したいが、ホバー中の一部だけ見せたい」という凝った実装ではこの性質が活躍しますが、意図せずこの挙動にハマって「なぜか消えないパーツがある」と悩むケースもあります。仕組みを知っていれば怖くありません。
アクセシビリティへの影響は基本同じ
読み上げ機能への影響について、両者に大きな差はありません。
display: noneもvisibility: hiddenも、要素をアクセシビリティツリーから除外します。つまりスクリーンリーダーはその要素を読み上げませんし、キーボード操作でもフォーカスが当たりません。
どちらのプロパティも「見た目上消えているだけで、実際にはダウンロードされている」という点には注意が必要です。画像や埋め込みコンテンツをdisplay: noneにしても、ネットワークリクエスト自体は発生します。機密情報や重い処理を単に隠すだけの目的で使うのは避けましょう。
比較表でまとめ
| 観点 | display: none | visibility: hidden |
|---|---|---|
| レイアウトのスペース | 消える | 残る |
| クリック・フォーカス | 不可 | 不可(子要素での上書き可) |
| スクリーンリーダー | 読み上げない | 読み上げない |
| 子要素での復活 | できない | できる |
| 主な用途 | タブ切り替え・レスポンシブ表示切替 | ツールチップ・レイアウト維持したい要素 |
display: noneとvisibility: hiddenは、どちらも「要素を消す」という結果だけを見ると同じに見えます。
ですが、レイアウトへの影響と子要素の扱いという2点を押さえておくだけで、実装時の事故をかなり減らせます。
次に非表示処理を書くときは、「本当にこのプロパティで合っているか」を一度確認してみてください。