Top > Blog > CrossBrowser > Programming

テーブルの行(TR要素)をスライドで表示切替させる方法(2)

前回はサンプルだけ提示しましたが、今回はそのソースコードを解説します。

念のため、対応ブラウザ

このページのサンプルは、下記ブラウザで確認しました。

  • 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でもいくつか注意すべきところがあります。概要は以下の通りです。

  1. [HTML] 各セル内部をdivで囲み、divをスライドさせるようにする。
  2. [CSS] セルのパディング(cellpaddingまたはCSSのpaddingプロパティ)は0pxにする。
  3. [CSS] セルのパディングを0にした分、セル内部のdivにパディングを指定する。
  4. [CSS] 非表示前後の行の高さをそろえるため、heightプロパティを指定する。
  5. [CSS] 表示状態のdisplayプロパティを、table-rowにする。
  6. [JavaScript] スライド終了とほぼ同時に、行を非表示に切り替える。
  7. [CSS] IE6対策として、標準準拠モードでレンダリングされるようにしておく
完成例↓
2行目の表示非表示を切り替え 表示 非表示
この行が対象
sample
この行はダミー

まずは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)をスライドさせてもある程度上手くいきますが、微妙に動きがカクカクしてしまいます。

動きがカクカクする例↓
2行目の表示非表示を切り替え 表示 非表示
この行が対象
sample
この行はダミー

これは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>

コメントの投稿