やろうとしたこと
前提固定ヘッダーにボタン押下でナビゲーションメニューを開閉する仕組み
(いわゆるハンバーガーメニュー)
その開閉時の視覚効果を「スーッと消えたり現れたりする透過アニメーション」にする
失敗集
その1
<button class="menu-btn type="button" title="メニュー" aria-expanded="false">MENU</button>
<div class="menu">
# 以下グローバルメニューの中身
</div>
document.querySelector('.menu-btn').addEventListener('click', function () {
document.querySelector('.menu').classList.toggle('is-active');
if (this.getAttribute('aria-expanded') == 'false') {
this.setAttribute('aria-expanded', true);
} else {
this.setAttribute('aria-expanded', false);
}
});
.menu {
opacity: 0;
transition: all 0.5s ease-out;
&.is-active {
opacity: 1;
}
}
結果:アニメーションは期待通りになるが、ヘッダーのリンクが機能しなくなった。
原因:透過しても、要素自体が無くなる訳ではないのでそれらが重なってしまった。
対策:displayの値を切り替える
↓↓↓
その2
.menu {
display: none;
opacity: 0;
transition: all 0.5s ease-out;
&.is-active {
display: block;
opacity: 1;
}
}
結果:リンクが機能しなくなる問題は解決したが、今度は透過アニメーションが作動せず。
原因:期待する挙動が
①display:noneを解除(この時点でopacity:0)
②n秒かけてopacityを1にする
であるのに対し、CSSファイルは上から順に指示をされるため
transitionが適切なタイミングで実行されない
対策:jQueryの@keyframesを使えば、アニメーションを自由に定義できるとのこと。
display:noneの解除後に@keyframesを読み込んでアニメーションを実行させる
↓↓↓
その3
@keyframes fadeIn {
0% {
opacity:0;
}
100% {
opacity:1;
}
}
@keyframes fadeOut {
0% {
opacity:1;
}
100% {
opacity:0;
}
}
.menu {
animation-name: fadeOut;
animation-duration: 0.6s;
animation-timing-function: ease-out;
animation-fill-mode: forwards;
display: none;
&.is-active {
display: block;
animation-name: fadeIn;
animation-duration: 0.6s;
animation-timing-function: ease-out;
animation-fill-mode: forwards;
}
}
結果:動きました!但し、アニメーションが適用されたのはフェードインの方だけ。
原因:.is-active
というクラス名を付与した際は有効だが、
除去したタイミングにはcssの再読み込みはされないから??
この問題について解決策を見つけることは出来ませんでしたが、
色々調べていく中で今回自分が実現したかったことは
jQueryのfadeToggleと同一のものだと分かりました。
cssは不要です。
↓↓↓
最終的なコード
document.querySelector('.menu-btn').addEventListener('click', function () {
$('.menu').fadeToggle(1000); // この一文を追加
document.querySelector('.menu').classList.toggle('is-active');
if (this.getAttribute('aria-expanded') == 'false') {
this.setAttribute('aria-expanded', true);
} else {
this.setAttribute('aria-expanded', false);
}
});