display:none の要素をフェードインさせようとして、失敗したことはありませんか?.
理由は、display:none の要素はブラウザ上で描画されていないためです。opacity はアニメーションできますが、display は通常の transition のように「0から1へなめらかに変化する」プロパティではありません。
この記事では、display:none の要素をフェードイン・フェードアウトさせる方法を、実用的なサンプル付きで紹介します。
display:noneの要素がtransitionでフェードインしない理由
opacity は、次のように数値が変化するプロパティです。
opacity: 0;
opacity: 0.5;
opacity: 1;そのため、transition を使えばなめらかに変化させることができます。
一方で、display は次のように状態を切り替えるプロパティです。
display: none;
display: block;none と block の間には、中間の状態がありません。
そのため、単純に display:none から display:block に変えただけでは、opacity の変化をブラウザがうまくアニメーションとして扱えないことがあります。
つまり、display は表示・非表示の切り替え担当、opacity はフェードの見た目担当として分けて考えるのがポイントです。
方法1:CSSアニメーションでdisplay:noneの要素をフェードインする
まずは、CSSの @keyframes を使ってフェードインさせる方法です。
See the Pen Untitled by kokusyo (@kokusyo) on CodePen.
この方法では、表示するときに .is-show を付け、非表示にするときに .is-hide を付けています。
.fade-box.is-show {
display: block;
animation: fadeIn 0.5s ease forwards;
}
.fade-box.is-hide {
display: block;
animation: fadeOut 0.5s ease forwards;
}フェードアウト中にすぐ display:none にすると、アニメーションが見えずに一瞬で消えてしまいます。
そのため、フェードアウト中は display:block のままにしておき、アニメーションが終わってから .is-hide を外します。
box.addEventListener('animationend', () => {
box.classList.remove('is-hide');
}, { once: true });.is-hide が外れると、元の .fade-box の状態に戻るため、結果的に display:none になります。
方法2:displayとopacityをJavaScriptで制御する方法
次に、フェードインだけでなくフェードアウトにも対応したサンプルです。
See the Pen Untitled by kokusyo (@kokusyo) on CodePen.
流れとしては、表示するときにまず display:block にして、その後に opacity:1 へ変更します。
box.style.display = 'block';
setTimeout(() => {
box.style.opacity = '1';
}, 10);非表示にするときは、先に opacity:0 へ変更し、フェードアウトが終わってから display:none にします。
box.style.opacity = '0';
setTimeout(() => {
box.style.display = 'none';
}, 500);CSSアニメーションよりJavaScriptの記述は少し増えますが、display と opacity の役割が分かりやすい方法です。
方法3:jQueryのfadeIn・fadeOutを使う
jQueryを使っているサイトであれば、もっと簡単に書けます。
See the Pen Untitled by kokusyo (@kokusyo) on CodePen.
表示の切り替えは、今回のように fadeToggle() を使うと簡単です。
$('#btn').on('click', function () {
$('#box').fadeToggle(500);
});jQueryの fadeIn() や fadeOut() は、内部で display と opacity を調整してくれるため、display:none の要素でも簡単にフェード表示できます。
方法4:opacityとvisibilityでフェードさせる
もっと簡単にすませたい方は、opacity と visibility を使う方法もあります。
See the Pen Untitled by kokusyo (@kokusyo) on CodePen.
CSSの transition だけで自然にフェードイン・フェードアウトできます。
ただし、注意点があります。visibility:hidden は要素を見えなくするだけなので、レイアウト上のスペースは残ります。
つまり、下の要素を詰めたい場合には向いていません。

スペースを残したまま、モーダル・ツールチップ・固定表示のメニューなどをフェードさせたい場合には使いやすい方法です。
方法5:@starting-styleとtransition-behaviorを使う新しいCSSの方法
最近のCSSでは、@starting-style と transition-behavior: allow-discrete を使うことで、display:none を含む表示切り替えも扱いやすくなっています。
See the Pen Untitled by kokusyo (@kokusyo) on CodePen.
@starting-style は、要素が表示される最初の状態を指定するためのCSSです。
通常、display:none から display:block に切り替わると、ブラウザは開始状態をうまく取れません。
そこで @starting-style を使い、表示開始時のスタイルを明示します。
@starting-style {
.fade-box.is-show {
opacity: 0;
transform: translateY(12px);
}
}また、display のように通常はなめらかに変化しないプロパティをトランジション対象にするために、allow-discrete を指定します。
transition:
opacity 0.5s ease,
transform 0.5s ease,
display 0.5s ease allow-discrete;この方法を使うと、JavaScript側ではクラスを付け外しするだけで済みます。
ただし、比較的新しいCSSの書き方なので、対応ブラウザを考慮する必要があります。
