ちょっとリッチなjQuery UI Sortaleのつくりかた

jQuery UI Sortableを使ってドラッグ&ドロップで順序変更できるリストを簡単に作ることができるんですが、見た目がどうも好きじゃないです。なんというか、元いた位置がわからなくなっちゃうとことか。
そんなわけで、自分好みの見た目になるCSS(とJavaScript)を書いてみました。

とりあえずデモを見てみて下さいまし。IE6, IE8, Firefox3.5, Google Chrome 3, Safari 4 で動作確認しました。(IE7だけしてないです。)

LIVE DEMO

ではコードを段階的に解説してゆきます。あ、コードは全てデモのHTMLファイル内に書いています。構造は上からCSS、HTML本文、JavaScriptになってます。

デフォルトの

まずこれ。

/* 順序変更可能な一覧 */
.sortable-list {
    background-color: #EEEEEE;
    border: solid 1px #CCCCCC;
    list-style-type: none;
    padding: 5px;
    width: 300px;
}
/* 一覧項目 */
.sortable-item {
    display: list-item !important;
    padding: 3px;
    /zoom: 1;
}
/* マウスホバー時の一覧項目 */
.sortable-item:hover,
.sortable-item-hover {
    background-color: #FFFFEE;
    color: #003399;
}

デフォルト版とリッチ版と共通のスタイルです。それぞれ枠を付けたり色を付けたり。
/zoom: 1は、IE6/7でちょっとおかしくなるのを防ぐためです。要素をブロックレベルにしても文字のある箇所しかhoverが反応しないので、これで調整します。頭のスラッシュはIE6/7にだけ適応させるためのCSSハックです。
!importantを使う理由はちょっと待ってて下さいね。

IE6で:hoverが動かないので、これはJavaScriptを使ってsortable-item-hoverクラスを与える事で解決します。

    // IE6でマウスホバーを有効に
    if ($.browser.msie && $.browser.version <= 6) {
        $('.sortable-item').
            mouseover(function() { $(this).addClass('sortable-item-hover'); }).
            mouseout(function() { $(this).removeClass('sortable-item-hover'); });
    }

では順序変更できるようにしましょう。

    // 普通なsortable
    var elListDefault = $('#sortable-default');
    elListDefault.sortable();

これで普通のSortableは動くようになりました。めでたしめでたし。

ちょっとリッチなの

続いてちょっとリッチな感じのものについて考えます。やりたいことは、

  • ドラッグを開始しても元の位置に元の項目が表示されている
  • でもドラッグ中のマウスカーソルにダミーが追随する
  • 移動先には線が表示される
  • 移動先の線の高さは、0 (ぱたぱたしない)

という感じ。

ドラック開始時に項目が増えるっていうのは、jQuery UI Sortableのオプションhelper'clone'を指定してやればできそうです。できそうなんですが、できませんw なんかですね、たしかに要素はクローニングされてるんですが、何故かdisplay: none;が指定されてしまうんです。バグでしょうか? そのあたりを書いておられる方がおられました。→jQueryUIのsortableにハマる - Cheese Pie

で、今回はライブラリには手を入れず、CSSでなんとかしちゃいます。display: none;は要素に直接指定されてしまっているので、displayの指定にさっき書いた!importantを付けて優先させます。このあたりは他のCSSとの兼ね合いがあって難しい場合もあるかもしれません。そういう場合はJavaScriptを使ってドラッグ開始時のコールバック関数でヘルパー要素を表示させても良いのでしょう。一瞬だけ消えてしまいますが……。

/* ドラッグ中の一覧項目 */
#sortable-rich .ui-sortable-sorting,
#sortable-rich .ui-sortable-helper {
    background-color: #FFFFEE;
    color: #003399;
}
/* 移動先 */
#sortable-rich .ui-sortable-placeholder {
    background-color: #000099;
    font-size: 0;
    height: 2px;
    margin-bottom: -2px;
    _margin-bottom: -19px;
    padding: 0px;
    position: relative;
    top: -1px;
    _top: -14px;
    visibility: visible !important;
}
/* ヘルパー(ドラッグで掴んでるもの) */
#sortable-rich .ui-sortable-helper {
    filter: alpha(opacity=70);
    opacity: .7;
}

ドラッグしているものはhover時と同じスタイルを指定しておく*1と見た目がスムーズです。
さて移動先のスタイルです。ここがキモ。

  1. 通常、移動先にはvisibility: hiddenで透明にしたplaceholderが配置されます。これをvisivility: visible;を設定して可視化します。例によって!importantを使います。
  2. 要素が画面に出るようになったので、heightbackground-colorを指定してplaceholderが線のように見えるようにします。
  3. またそれだけだと配置された際に後方の項目が下がってしまうので、margin-bottomに負数を指定*2して戻します。
  4. すると線が後方の項目と重なってしまうので、さらにpositiontopで線を上へ移動させます。

はい、これで移動先に線が表示されるようになりました!

できあがり

ね、簡単でしょ?

というわけでできました。デモみたいに左右に三角?みたいなのを作る場合は、コードを見てみて下さいね。

このスタイルがデフォルトにならないかなーあんまりぱたぱた動くの好きじゃないんだよー。

*1:もちろん、実際に使う際は指定は一箇所にまとるべきです。

*2:google:CSS ネガティブマージン