ドラッグ並べ替え
ハンドルをつまんで縦リストの順序を入れ替える。掴んだ項目に合わせて他の項目がスッと動いて場所を空ける(並べ替えの定番)。PC・スマホ両対応。
プレビュー
ドラッグ
操作ドラッグ/スワイプで操作できます(PC・スマホ対応)。
仕様書
- 向く場面
- ToDo・プレイリストなど順序が意味を持つ縦リスト
- 5〜20件程度を指で並べ替えたい
- 行の高さが均一な一覧
- 避ける場面
- 行の高さが不揃いな一覧(スロット計算が崩れる)
- 順序に意味がない一覧
- キーボード代替なしで並べ替えを必須にする
- 構成要素
- リスト
- 項目
- ドラッグハンドル
- 順位番号
- 持っている状態
- 通常
- 押下中
- キーボード
Tab で各行のハンドル button へ・↑↓ で1つ上/下へ移動(ハンドルにフォーカスが残る)。ドラッグはマウス・タッチ
- 支援技術
ハンドルは「ドラッグまたは↑↓キーで移動」の aria-label 付き button、順位は番号で示す。順序変更は sr-only の role=status で「N番目へ移動」を告知
- 動き
掴んだ項目は transition なしで追従、他の項目は translateY 0.18s で隙間を空ける。影 0.18s で持ち上がりを示す。reduced-motion では即時
デザインの要点
- 掴んでいる間は DOM を動かさず transform だけで見せ、離した瞬間に一度だけ並べ替える。ドラッグ中に DOM を組み替えるとフォーカスと座標が飛ぶ
- 間の項目は行の高さ+gap ぶん translateY でずらして隙間を空ける。ずらさないと「どこに落ちるか」が離すまで分からない
- 掴めるのはハンドルだけにし、行本体は普通にタップできる状態を残す。行全体をドラッグ可能にすると縦スクロールと取り合う
- ハンドルは button にして ↑↓ でも動かす。ドラッグしか無い並べ替えは、キーボードと読み上げでは順序を変えられない
実装メモ
ハンドルの Pointer Events でドラッグを検知し、掴んだ項目は指に追従(transform で移動・transition なし)、間の項目は行の高さ分だけ translateY でずらして「隙間を空ける」ことで並べ替えを表現します。他項目には transition を効かせるのでスッと動きます。離すと実際のDOM順を組み替えて番号を振り直します。ハンドルに touch-action:none を付け、縦ドラッグがスクロールと衝突しないようにしています(均等な行高さが前提)。ハンドルは button なので Tab で届き、↑↓ キーでも1つずつ入れ替えられます。
コード(コピーして使えます)
<ul class="dr-list" id="dr-list">
<li class="dr-item"><button class="dr-handle" aria-label="ドラッグまたは↑↓キーで移動">⠿</button><span class="dr-rank"></span>牛乳を買う</li>
<li class="dr-item"><button class="dr-handle" aria-label="ドラッグまたは↑↓キーで移動">⠿</button><span class="dr-rank"></span>資料をまとめる</li>
<li class="dr-item"><button class="dr-handle" aria-label="ドラッグまたは↑↓キーで移動">⠿</button><span class="dr-rank"></span>ジムに行く</li>
<li class="dr-item"><button class="dr-handle" aria-label="ドラッグまたは↑↓キーで移動">⠿</button><span class="dr-rank"></span>本を返却する</li>
<li class="dr-item"><button class="dr-handle" aria-label="ドラッグまたは↑↓キーで移動">⠿</button><span class="dr-rank"></span>友人に返信</li>
</ul>
<p class="dr-status" role="status" aria-live="polite"></p>