jQueryのslideUp() / slideDown()をCSS3で実現する

公開
更新

2020年11月23日更新

改めて検討したのですが、現状ではheightを使用した場合でも上手くslideUp()やslideDown()相当の動作が実現できました。以前参照していた仕様書の内容も今は見当たりません。そこでこの後で紹介するサンプルコードも大幅に書き換えています。WAI-ARIAも誤りがありましたので修正いたしました。

2015年当時の記事

jQueryを使わずZepto.jsを使う時、もしくはライブラリを使わない時に、jQueryのslideUp()やslideDown()相当のことができないかと考えました。利用シーンは、例えばスマートフォン向けの画面で、ボタンを押すとメニューが下に開くウィジェットです。実現方法は、昨今のブラウザ環境も考えるとCSS3 Transitions(もしくはCSS3 Animation)を使えば良いかと考えました。

いざCSS3 Transitionsでやろうとしたのですが、CSS Transitionsの仕様書の7.1. Properties from CSS を見ると、heightはアニメーション可能なプロパティに入っていません。どうしようかと考えていたのですが、Stack Overflowを見るとCSS transition height: 0; to height: auto;という同じ悩みを抱えた人がいて、回答にmax-heightを使えば良いとありました。

サンプルを参考にしつつ自分なりに書いたところ、最終的には下記のようになりました。

See the Pen Toggle Menu by Hideki Abe (@hideki-a) on CodePen.

ポイント

  • max-heightを設定する(※2020年11月23日にheightに書き換えました)
  • transitionで、開いた状態と閉じた状態のトランジションを設定する
  • JavaScriptでclass属性値を変化させる

max-heightの値が大きい場合の問題点

メニューの高さは様々な要因で変わる可能性があるので、それに備えてmax-heightを1,000pxといった大きな値に設定してみました。値が大きくてもIEやChrome、Androidのブラウザではまぁ良い感じにアニメーションしてくれるのですが(よく見るとおかしいです。開く時と閉じる時で速さが違います。)、Firefoxではパッと一瞬でスライドダウンしてしまうような感じでした。スライドアップの際もタイムラグが生じます。やはりきれいにアニメーションさせるには、適切な高さを設定しなければならないようです。

そこで今回は、1つdiv要素を追加し、スクリプト内で高さを取得してmax-height値として設定するようにしてみました。要素を追加せず高さを取得することもおそらく可能ではありますが、少し手間が増えます。

参考:WAI-ARIAの実装

参考までに、WAI-ARIAの実装もしてみました。WAI-ARIAを用いることで、ウィジェットがよりアクセシブルになります。

今回はボタンにaria-controls="menu"を設定し、nav#menuを制御していることを示しました。また、aria-expanded属性により、メニューが開いているか否かを表現することができます。これらの属性は、JavaScriptで設定・値の変更を行っています。