前回はサンプルだけ提示しましたが、今回はそのソースコードを解説します。
念のため、対応ブラウザ
このページのサンプルは、下記ブラウザで確認しました。
- 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>