【jQuery】ちょっと見えた状態からslideToggle的なことをする

jQueryでアコーディオンやプルダウンなどを作れるslideToggleメソッドがありますが、要素を少し見せた状態からこれと同じようなことをするサンプルをご紹介します。
目次
やりたいこと
「画像を開く」をクリックしてください。少し見えた状態からスライドダウンされます。
jQueryのslideToggleは要素の表示・非表示を切り替えるので
この「ちょっと見せた状態から」というのはslideToggleではおそらく不可能。
という訳で、オリジナルでJSを書いてみました。
HTML
HTMLはこんな感じ。
<div class="contents">
<img src="img/img.jpg">
</div>
<button class="btn">開く</button>
プルダウンの内容を<div class="contents">の中に入れていください。
画像以外にも、文章やiframeなどを入れても動きます。
ボタンは<button>タグじゃなくてもOK。
CSS
最小限だけ書くと、こんな感じ。
.contents {
height: 100px; /* ちょっと見せたい高さ */
overflow: hidden;
}
この.contentsにtransitionは設定しないでください。
JSで取ったり付けたりしたいので。
JS
そして、jQueryコードはこちら
//contents
let contents = $(".contents");
//アニメーションの長さ (ms)
let duration = 1000;
//ボタンをクリックしたとき
$(".btn").on("click", function(){
//開くとき
if(!contents.hasClass("active")){
//contentsの制限されてる高さを取得
let cont_h = contents.height();
//一度、heightを解除
contents.css("height", "auto");
//オリジナルの高さを取得
let cont_h_origin = contents.height();
//再度高さを制限
contents.css("height", cont_h + "px");
//少し遅延を入れてtransitionとオリジナルの高さに設定 (アニメーションしながら開いていく)
setTimeout(function(){
contents.css({
"transition": "height "+duration+"ms",
"height": cont_h_origin + "px"
});
}, 1);
//アニメーション後にCSS値をリセット
setTimeout(function(){
contents.css({
"height": "auto",
"transition": ""
});
}, duration);
//クラス付与
contents.addClass("active");
//閉じるとき
}else{
//contentsの高さを取得
let cont_h = contents.height();
//一度、heightを削除
contents.css("height", "");
//制限された状態の高さを取得
let cont_h_limited = contents.height();
//再度高さを設定
contents.css("height", cont_h + "px");
//少し遅延を入れてtransitionと制限された高さに設定 (アニメーションしながら閉じていく)
setTimeout(function(){
contents.css({
"transition": "height "+duration+"ms",
"height": cont_h_limited + "px"
});
}, 1);
//アニメーション後にCSS値をリセット
setTimeout(function(){
contents.css("transition", "");
}, duration);
//クラス削除
contents.removeClass("active");
}
});
一応、下手な説明を書いておきます
CSSのtransitionを使ってアニメーションさせています。
transitionでheightの変化にアニメーションを付けるには、heightが特定の値から特定の値への変化でなければなりません。 (auto → 100px などの変化ではアニメーションできない。 354px → 100px などなら可。)
そこで、ボタンをクリックした瞬間、一瞬だけ高さの制限を解除し、要素の本来の高さを計測。
制限された高さから、本来の高さに変更させてtransitionを発火させています。
その際、タイミングをずらさないといけないので1msだけ遅延を入れたりしています。
バニラなJavaScriptなら (開く)
バニラなJavaScriptならこんな感じ。
//contents
let contents = document.querySelector(".contents");
//アニメーションの長さ (ms)
let duration = 1000;
//ボタンをクリックしたとき
document.querySelector(".btn").onclick = function(){
//開くとき
if(!contents.classList.contains("active")){
//contentsの制限されてる高さを取得
let cont_h = contents.offsetHeight;
//一度、heightを解除
contents.style.height = "auto";
//オリジナルの高さを取得
let cont_h_origin = contents.offsetHeight;
//再度高さを制限
contents.style.height = cont_h + "px";
//少し遅延を入れてtransitionとオリジナルの高さに設定 (アニメーションしながら開いていく)
setTimeout(function(){
contents.style.transition = "height "+duration+"ms";
contents.style.height = cont_h_origin + "px";
}, 1);
//アニメーション後にCSS値をリセット
setTimeout(function(){
contents.style.height = "auto";
contents.style.transition = "";
}, duration);
//クラス付与
contents.classList.add("active");
//閉じるとき
}else{
//contentsの高さを取得
let cont_h = contents.offsetHeight;
//一度、heightを削除
contents.style.height = "";
//制限された状態の高さを取得
let cont_h_limited = contents.offsetHeight;
//再度高さを設定
contents.style.height = cont_h + "px";
//少し遅延を入れてtransitionと制限された高さに設定 (アニメーションしながら閉じていく)
setTimeout(function(){
contents.style.transition = "height "+duration+"ms";
contents.style.height = cont_h_limited + "px";
}, 1);
//アニメーション後にCSS値をリセット
setTimeout(function(){
contents.style.transition = "";
}, duration);
//クラス削除
contents.classList.remove("active");
}
};
関数化してみる
HTMLはこんな感じ。
<div class="contents">
<p><img src="img/img.jpg"></p>
</div>
<button onclick="slideToggle('.contents', 300)">開く</button>
JSはこんな感じ。
function slideToggle(elm, duration){
let contents = $(elm);
//開くとき
if(!contents.hasClass("active")){
//contentsの制限されてる高さを取得
let cont_h = contents.height();
//一度、heightを解除
contents.css("height", "auto");
//オリジナルの高さを取得
let cont_h_origin = contents.height();
//再度高さを制限
contents.css("height", cont_h + "px");
//少し遅延を入れてtransitionとオリジナルの高さに設定 (アニメーションしながら開いていく)
setTimeout(function(){
contents.css({
"transition": "height "+duration+"ms",
"height": cont_h_origin + "px"
});
}, 1);
//アニメーション後にCSS値をリセット
setTimeout(function(){
contents.css({
"height": "auto",
"transition": ""
});
}, duration);
//クラス付与
contents.addClass("active");
//閉じるとき
}else{
//contentsの高さを取得
let cont_h = contents.height();
//一度、heightを削除
contents.css("height", "");
//制限された状態の高さを取得
let cont_h_limited = contents.height();
//再度高さを設定
contents.css("height", cont_h + "px");
//少し遅延を入れてtransitionと制限された高さに設定 (アニメーションしながら閉じていく)
setTimeout(function(){
contents.css({
"transition": "height "+duration+"ms",
"height": cont_h_limited + "px"
});
}, 1);
//アニメーション後にCSS値をリセット
setTimeout(function(){
contents.css("transition", "");
}, duration);
//クラス削除
contents.removeClass("active");
}
}
バニラなJavaScriptなら (開く)
バニラなJavaScriptならこんな感じ。
function slideToggle(elm, duration){
let contents = document.querySelector(elm);
//開くとき
if(!contents.classList.contains("active")){
//contentsの制限されてる高さを取得
let cont_h = contents.offsetHeight;
//一度、heightを解除
contents.style.height = "auto";
//オリジナルの高さを取得
let cont_h_origin = contents.offsetHeight;
//再度高さを制限
contents.style.height = cont_h + "px";
//少し遅延を入れてtransitionとオリジナルの高さに設定 (アニメーションしながら開いていく)
setTimeout(function(){
contents.style.transition = "height "+duration+"ms";
contents.style.height = cont_h_origin + "px";
}, 1);
//アニメーション後にCSS値をリセット
setTimeout(function(){
contents.style.height = "auto";
contents.style.transition = "";
}, duration);
//クラス付与
contents.classList.add("active");
//閉じるとき
}else{
//contentsの高さを取得
let cont_h = contents.offsetHeight;
//一度、heightを削除
contents.style.height = "";
//制限された状態の高さを取得
let cont_h_limited = contents.offsetHeight;
//再度高さを設定
contents.style.height = cont_h + "px";
//少し遅延を入れてtransitionと制限された高さに設定 (アニメーションしながら閉じていく)
setTimeout(function(){
contents.style.transition = "height "+duration+"ms";
contents.style.height = cont_h_limited + "px";
}, 1);
//アニメーション後にCSS値をリセット
setTimeout(function(){
contents.style.transition = "";
}, duration);
//クラス削除
contents.classList.remove("active");
}
}
使い方
ボタンのonclick属性に2つの引数を入れます。
<button onclick="slideToggle('.contents', 300)">開く</button>
1つ目にプルダウン要素のセレクタを。
2つ目にアニメーションの長さ (ms) を入れます。
このように入れ子で指定したり
<button onclick="slideToggle('#main .contents', 300)">開く</button>
属性値で指定したりもできます。
<button onclick="slideToggle('[data-contents=01]', 300)">開く</button>
コメント
「できました!」などの報告もお待ちしております。
お役に立てましたら応援をお待ちしております!
頂いた応援は子育てに活用させていただきます。
または以下のボタンからなにか買って応援 (PR)