CSSで要素を非表示にする方法は、displayvisibilityopacityの3つが基本です。結論から書くと、非表示のときに領域を詰めたいならdisplay: none、領域を残したいならvisibility: hidden、フェードさせたいならopacity: 0を選びます。

3つは「見えなくなる」という結果が同じなので混同されがちですが、レイアウトへの影響・アニメーションの可否・キーボード操作やスクリーンリーダーからの見え方がそれぞれ違います。私はLP制作で毎回この使い分けを判断しているので、その基準を表と実際のコードで整理しました。

記事の後半には、4パターンの動作を確認できるCodePenのデモも置いています。

display・visibility・opacityの違いは?一覧で比較

3つのプロパティは、「非表示のときに領域が残るか」と「その要素を操作できてしまうか」で決定的に違います。見た目が消える点だけが共通していて、それ以外はほぼ別物です。

▼3つのプロパティの違い

項目 display: none visibility: hidden opacity: 0
非表示時の領域 詰まる 残る 残る
transition △(後述の指定が必要) △(0か1で切り替わる) ◯(滑らかに変化する)
クリックできるか できない できない できてしまう
Tabキーで移動できるか できない できない できてしまう
スクリーンリーダーが読むか 読まない 読まない 読み上げる
子要素だけ再表示 できない できる(visibility: visible できない

この表でいちばん注意したいのがopacity: 0の行です。opacity: 0は見た目を透明にするだけなので、要素そのものはページに残り続けます。閉じたはずのメニューがTabキーで選べたり、スクリーンリーダーに読み上げられたりするのはこれが原因です。

 

領域を詰めたいなら display: none

非表示のときにその要素の場所を空けたくないならdisplay: noneを使います。要素はレイアウト計算から完全に外れ、後ろの要素が上に詰まります。

▼display: none の書き方

.box {
  display: block;
}

.box.is-hidden {
  display: none;
}

 

display: none はアニメーションが効かないのか

かつてはdisplaytransitionは一切効きませんでした。ただし現在は、transition-behavior: allow-discrete@starting-styleを組み合わせることで、display: noneへの切り替えにもアニメーションを付けられます。

▼display をアニメーションさせる書き方

.box {
  display: block;
  opacity: 1;
  transition: opacity 0.3s, display 0.3s;
  transition-behavior: allow-discrete;
}

.box.is-hidden {
  display: none;
  opacity: 0;
}

/* 表示され始めるときの開始値 */
@starting-style {
  .box {
    opacity: 0;
  }
}

対応状況は、@starting-styleがChrome 117以降・Edge 117以降・Safari 17.5以降・Firefox 129以降、transition-behaviorがChrome 121以降・Safari 17.5以降・Firefox 129以降です。非対応のブラウザではアニメーションが付かないだけで、表示・非表示の切り替え自体は正しく動くため、そのまま書いて問題ありません。

 

display: none を使うと良い場面

折りたたんだ中身を完全に畳みたいときに向いています。アコーディオンやハンバーガーメニューの中身はdisplay: noneが基本です。領域が残ると、閉じているのに下に大きな空白ができてしまうためです。

実装の具体例はCSSとjQueryでアコーディオンを実装するで書いています。

 

領域を残したまま消したいなら visibility: hidden

レイアウトを崩さずに要素だけ消したいならvisibility: hiddenを使います。要素の領域はそのまま確保され、周りの要素は動きません。

▼visibility: hidden の書き方

.box {
  visibility: visible;
}

.box.is-hidden {
  visibility: hidden;
}

 

visibility: hidden は子要素だけ表示に戻せる

visibilityは継承されるプロパティなので、親をhiddenにしたまま、子要素にだけvisibility: visibleを指定して表示に戻せます。これはdisplayopacityにはできない挙動です。

.parent {
  visibility: hidden;
}

.parent .child {
  visibility: visible; /* 親が hidden でも表示される */
}

 

visibility: hidden を使うと良い場面

表の行やグリッドの升目のように、消しても場所を空けてほしくない要素に向いています。キーボード操作とスクリーンリーダーからも外れるため、閉じているメニューを隠す用途でも安全です。

 

フェードで消したいなら opacity: 0

滑らかに消したいならopacity: 0を使います。3つの中で唯一、transitionで中間の状態を持てるプロパティです。

▼opacity でフェードさせる書き方

.box {
  opacity: 1;
  transition: opacity 0.3s ease;
}

.box.is-hidden {
  opacity: 0;
}

 

opacity: 0 だけだとクリックできてしまう

opacity: 0の要素は透明になっただけで、そこに存在し続けます。透明なまま重なった要素が、下にあるボタンのクリックを奪ってしまう事故が起きます。私はモーダルの背景で実際にこれを踏みました。

対策はpointer-events: noneを足すか、visibilityと併用することです。キーボード操作とスクリーンリーダーからも外したいなら、後者を選びます。

▼フェードさせつつ、操作もできなくする書き方

.box {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.3s ease, visibility 0.3s;
}

.box.is-hidden {
  opacity: 0;
  visibility: hidden;
}

visibilityは中間の値を持たない(visiblehiddenのどちらか)プロパティですが、transitionに並べて書くと切り替わるタイミングをopacityの完了まで遅らせられます。これでフェードアウトの途中で要素が消える現象を防げます。

この書き方はjQueryでモーダルウィンドウをさくっと作るでも使っています。

 

4パターンの動作デモ

「領域が詰まるか」と「アニメーションが付くか」の組み合わせで4通りになります。実際の動きはCodePenで確認してください。

 

①領域が詰まる・アニメーションあり

See the Pen
rNadzmZ
by りん@webコーダー (@rinblog0408)
on CodePen.

非表示にすると領域が詰まり、切り替えにアニメーションが付きます。私はLP制作でよく使う組み合わせです。面積の大きい要素が予告なく消えると読み手が驚くため、大きなブロックほどアニメーションを入れています。

 

②領域が詰まる・アニメーションなし

See the Pen
MWYVvLz
by りん@webコーダー (@rinblog0408)
on CodePen.

非表示にすると領域が詰まり、切り替えは即座に行われます。小さな要素の出し分けや、フォームのエラー文の表示など、演出が不要な場面はこれで十分です。

 

③領域が残る・アニメーションあり

See the Pen
xxbWXEw
by りん@webコーダー (@rinblog0408)
on CodePen.

非表示にしても領域は残り、フェードで切り替わります。周りのレイアウトを1pxも動かしたくないときは、この組み合わせを選びます。ホバーで内容を差し替える表現とも相性が良く、似た考え方はホバーしたときにCSSだけで画像を切り替える方法でも使っています。

 

④領域が残る・アニメーションなし

See the Pen
oNgqGWY
by りん@webコーダー (@rinblog0408)
on CodePen.

非表示にしても領域は残り、切り替えは即座に行われます。表の中身の出し分けのように、位置がずれると読みにくくなる箇所で使っています。

 

結局どれを使えばいいのか

迷ったときの判断は、「非表示のときに場所を空けるか」を先に決めると一本に絞れます。

▼目的別の選び方

  • 閉じたら詰めたい(アコーディオン・メニュー)→ display: none
  • 閉じても場所は残したい(表・グリッド)→ visibility: hidden
  • ふわっと消したい(モーダル・ツールチップ)→ opacity: 0visibility: hidden
  • 見た目だけ消して、読み上げには残したい → opacity: 0 単体

最後の1つは用途が限られます。見えていないのにスクリーンリーダーが読み上げる状態は、多くの場合は不具合です。意図してそうする場面以外ではvisibilityを併用してください。

JavaScriptやjQueryでも同じことは実現できますが、状態の切り替えをクラスの付け外しだけで済ませられる分、私はCSS側に寄せるほうが保守しやすいと感じています。

ABOUT ME
りん
このブログでは、Web開発やプログラミングに関する情報を中心に、私が日々感じたことや学んだことをシェアしています。技術と生活の両方を楽しめるブログを目指して、日常で触れた出来事や本、グルメの話題も取り入れています。気軽に覗いて、少しでも役立つ情報や楽しいひとときを見つけてもらえたら嬉しいです。