前回はサンプルだけ提示しましたが、今回はそのソースコードを解説します。
念のため、対応ブラウザ
このページのサンプルは、下記ブラウザで確認しました。
- Firefox 2.0.0.10, Firefox 3.0.10 (Windows XP sp3, Mac OS X v10.5.6)
- IE6, IE7, IE8 (Windows XP sp3)
- Safari 3.2.1 (Mac OS X v10.5.6)
jQueryのバージョンは、1.3.2です。
組み方のポイント
行の表示/非表示をスムーズに見せるには、jQueryの組み方だけでなく、HTML, CSSでもいくつか注意すべきところがあります。概要は以下の通りです。
- [HTML] 各セル内部をdivで囲み、divをスライドさせるようにする。
- [CSS] セルのパディング(cellpaddingまたはCSSのpaddingプロパティ)は0pxにする。
- [CSS] セルのパディングを0にした分、セル内部のdivにパディングを指定する。
- [CSS] 非表示前後の行の高さをそろえるため、heightプロパティを指定する。
- [CSS] 表示状態のdisplayプロパティを、table-rowにする。
- [JavaScript] スライド終了とほぼ同時に、行を非表示に切り替える。
- [CSS] IE6対策として、標準準拠モードでレンダリングされるようにしておく
まずはHTMLの組み直し
サンプルで使用するテーブルは、修正前は下記のようなコードになっています。 (※スライド対象となっている2行目のみ抜粋)
<tr style="background-color: #FFCCCC;" id="row"> <td> この行が対象 </td> <td> sample </td> </tr>
tr要素をスライドしても、td要素をスライドしても上手くいかないので、内部にdivをはめ込みます(ポイント1)。
<tr style="background-color: #FFCCCC;" id="row"> <td> <div id="cell01"> この行が対象 </div> </td> <td> <div id="cell02"> sample </div> </td> </tr>
この状態でdiv(idはcell01, cell02)をスライドさせてもある程度上手くいきますが、微妙に動きがカクカクしてしまいます。
これはtd要素側のパディングが原因で、分かり易く図示すると、次のような感じになります。
上図の黄色い部分がスライドアニメーションされて徐々に高さが減るのですが、最後にtd要素のパディング部分(図では背景が薄い赤の部分)が残って、その後で行全体が非表示になるので、残った部分が一気に消えて、全体としてカクカクした動きになるようです。
これを回避するために、td要素側のパディングを0にし(ポイント2)、減らした分のパディングを(修正前と見た目が変わらないように)div側に割り当てます(ポイント3)。パディングの数値は、元の画面デザインに合わせます。
また、下のコード例では height プロパティを指定していますが、これを指定する事で、一旦非表示にして表示に戻した際の、行の高さを同じにします(ポイント4)。これもデザインに合わせて適宜数値は変えます。
<tr style="background-color: #FFCCCC;" id="row"> <td style="padding: 0px;"> <div id="cell01" style="padding: 1px; height: 22px;"> この行が対象 </div> </td> <td style="padding: 0px;"> <div id="cell02" style="padding: 1px; height: 22px;"> sample </div> </td> </tr>
displayプロパティにtable-rowを指定する
概ねIE以外のブラウザでは、行(tr要素)の表示/非表示を実現するdisplay
プロパティの値は、block/none
でなはく、table-row/none
です。しかしjQueryのslideUp()
メソッドでは、最終的にdivが非表示になった際にこのdisplay
プロパティがnone
に、slideDown()
メソッドではdisplay
プロパティがblock
になってまして、table-row
は適用されません。
前回のサンプルで、tr要素をそのままスライドした場合に、Firefoxでは一旦行全体が左端のセルに収まってからスライドし、表示時には左端のセルに収まったままの状態になっていましたが、それはこのdisplay
プロパティの値が原因と思われます。
そこで、tr要素に適宜display: table-row
を適用するようにしておきます。
ただ、table-row
はIE6, IE7ではサポートされていないようで、エラーが発生します。IEの場合はtr要素のdisplay
プロパティがblock
であっても問題なくスライドするので、次のような関数を作成し、エラー発生時は何もしない(catchして何も行わない)ようにしました。
function _cb() { try { $("#row").css("display", "table-row"); } // IE6, IE7では例外が発生する catch(e) { // 何もしない } }
これを、slideDown()
メソッドの第2引数に、コールバック関数として指定します。こうすると、表示時のdisplay
プロパティが、(table-row
をサポートしているブラウザだけ)table-row
になります(ポイント5)。
var speed = 300; $("#radio01").click(function() { $("#cell01").slideDown(speed); $("#cell02").slideDown(speed); $("#row").slideDown(speed, _cb()); });
divが消えた後で、行そのものを非表示に切り替える
だいたい以上でうまくスライドしますが、実際に消えているのはセル内部のdiv要素なので、table要素でborder
に幅がある場合は、行が残っているのが視覚的にも分かります。
その対策として、div要素のスライド終了と(ほぼ)同時に、行(tr要素)を非表示にします。これにはhide()
メソッドを使用しますが、JavaScriptのsetTimeout()
でタイミングを遅らせます。
$("#radio02").click(function() { $("#cell01").slideUp(speed); $("#cell02").slideUp(speed); setTimeout(function() { $("#row").hide(); }, speed); });
setTimeout()
関数の第2引数に指定する値はslideUp()
の引数と同じ値にします。こうするとslideUp()
の終了とほぼ同時に $("#row").hide()
が実行されるようになって、行そのもののスライド非表示がスムーズに完了したように見えます(ポイント6)。
IE6で、非表示時に一旦フラッシュしたように見える場合
IE6では、まれにslideUp()
が完了する直前(display
プロパティがnone
になる時)に、一旦スライド前の状態に一瞬だけ戻る事があります。見ているとフラッシュしたような動作です。
これはIEのレンダリングモードが後方互換モードになっているせいで、ボックスモデルがW3C標準に準拠していないのが原因です。HTMLの1行目をDOCTYPE宣言にすると、IEは標準準拠モードでレンダリングをするので、このフラッシュは無くなります。XML宣言などが1行目に書いてある場合は、削除してDOCTYPE宣言を1行目に持ってくる必要があります。
完成したコード
以上で、行の表示/非表示をスライドアニメーションさせるサンプルは完成です。全コードを記載します。
<table border="2"> <tr> <td>2行目の表示非表示を切り替え</td> <td> <input type="radio" id="radio01" name="sample_radios01" checked="checked" />表示 <input type="radio" id="radio02" name="sample_radios01" />非表示 </td> </tr> <tr style="background-color: #FFCCCC;" id="row"> <td style="padding: 0px;"> <div id="cell01" style="height: 22px; padding: 1px;"> この行が対象 </div> </td> <td style="padding: 0px;"> <div id="cell02" style="height: 22px; padding: 1px;"> sample </div> </td> </tr> <tr> <td colspan="2">この行はダミー</td> </tr> </table> <script type="text/javascript"> <!-- function _cb() { try { $("#row").css("display", "table-row"); } catch(e) {} } $(document).ready(function() { var speed = 300; // 完成版 $("#radio01").click(function() { $("#cell01").slideDown(speed); $("#cell02").slideDown(speed); $("#row").slideDown(speed, _cb()); }); $("#radio02").click(function() { $("#cell01").slideUp(speed); $("#cell02").slideUp(speed); setTimeout(function() { $("#row").hide(); }, speed); }); }); //--> </script>