カンバン D&D
カードを「ToDo/進行中/完了」の列間でドラッグして移動できる。Pointer Events で実装しタッチ操作にも対応。矢印キーでも移動できる。
プレビュー
ドラッグ
操作ドラッグ/スワイプで操作できます(PC・スマホ対応)。
仕様書
- 向く場面
- タスク・案件を段階で管理する業務ボード
- 列間の移動が主操作の少量カード
- タッチでも並べ替えたい進捗管理
- 避ける場面
- 1 列に数十枚並ぶカード(一覧+状態変更が向く)
- 列が 5 つを超えて横スクロールが常態化する構成
- 構成要素
- 列(ToDo/進行中/完了)
- 列見出しと件数
- カード
- ドラッグ中の複製
- 挿入位置のゴースト
- 持っている状態
- 通常
- 押下中
- キーボード
Tab で各カードへ(tabindex=0)。←→ で隣の列へ移動、↑↓ で同じ列内の順番を入れ替え。ドラッグは Pointer Events でマウス・タッチ両対応
- 支援技術
列は role=list+見出しの aria-labelledby、カードは role=listitem+tabindex=0。移動結果は視覚外の aria-live=polite で読み上げ。複製とゴーストは aria-hidden の装飾。reduced-motion で影・透明度の遷移停止
- 動き
掴んだカードは 0.35 の透明度、複製が 2° 傾いて指に追従、受け入れ列の背景 150ms で青く。落とす場所を示す
デザインの要点
- 掴んだ元のカードは 0.35 の透明度で残し、指に付いていく複製を別に作る。元の位置が見えないと戻せない
- 挿入位置は破線のゴーストで先に見せる。落としてから並びが変わると「どこに入るか」を賭けることになる
- 受け入れ列の背景を 150ms で青くする。列全体が「ここに落とせる」と言う方が、カード単位の反応より迷わない
- ドラッグに矢印キーの代替を必ず付ける。←→ で列、↑↓ で順番。読み上げで移動先を告げないと結果が分からない
コード(コピーして使えます)
<div class="kb-board">
<span class="kb-sr" id="kb-status" aria-live="polite"></span>
<div class="kb-col" data-col="todo">
<div class="kb-col-header" id="kb-head-todo">
<span class="kb-col-dot dot-todo" aria-hidden="true"></span>ToDo
<span class="kb-count" id="cnt-todo"></span>
</div>
<div class="kb-cards" id="cards-todo" role="list" aria-labelledby="kb-head-todo">
<div class="kb-card" data-id="1" role="listitem" tabindex="0">要件定義</div>
<div class="kb-card" data-id="2" role="listitem" tabindex="0">競合調査</div>
</div>
</div>
<div class="kb-col" data-col="wip">
<div class="kb-col-header" id="kb-head-wip">
<span class="kb-col-dot dot-wip" aria-hidden="true"></span>進行中
<span class="kb-count" id="cnt-wip"></span>
</div>
<div class="kb-cards" id="cards-wip" role="list" aria-labelledby="kb-head-wip">
<div class="kb-card" data-id="3" role="listitem" tabindex="0">UI設計</div>
</div>
</div>
<div class="kb-col" data-col="done">
<div class="kb-col-header" id="kb-head-done">
<span class="kb-col-dot dot-done" aria-hidden="true"></span>完了
<span class="kb-count" id="cnt-done"></span>
</div>
<div class="kb-cards" id="cards-done" role="list" aria-labelledby="kb-head-done">
<div class="kb-card" data-id="4" role="listitem" tabindex="0">キックオフ</div>
</div>
</div>
</div>