ドラッグでリサイズするUIを実装するときに設定したいCSS
例えばサイドバーの幅をドラッグで調整できるUIを実装した時、以下のような症状に遭遇したことはありませんか?
- ドラッグ中になんか引っかかる・スムースに反応しない
- マウスのボタンを離してもドラッグ中判定のままになってしまう
- ドラッグ中にテキストが選択されてしまう
僕はあります。
挙動が微妙な実装例
以下は上記のような挙動を再現した実装例になっています。試しに、サイドバーの右端をドラッグして色々と操作をしてみてください。おそらく、リサイズがカクついたり、マウスのボタンを離した状態でもリサイズされてしまったり、テキストが選択されてしまう症状が出ると思います。
(↓の埋込状態の操作だとうまく再現されないので別ウインドウで開いて操作してください)
修正した実装例
こちらは修正した実装例です。先程のような症状はでていないです。
ドラッグ操作が正常に動かない対策
この原因は外部コンテンツの埋め込みがドラッグ上に存在していると発生することがあります。画像のようにiframe上をドラッグ操作で通過すると、mousemove
イベントが途切れサイドバーのリサイズがされなかったり、iframe上でマウスのボタンを離すと mouseup
イベントが発火せず、ドラッグ中の判定のままになります。
これは外部コンテンツは異なるコンテキストで動くためです。
対策は pointer-events: none
を指定することです。ドラッグ開始のタイミングでbodyに対して指定すると、あらゆるポインター操作が無効になります。
dragbar.addEventListener("mousedown", function (e) {
isDragging = true;
document.body.style.pointerEvents = "none"; // 追加
});
テキストが選択されてしまう対策
これはドラッグ操作はテキスト選択するのがデフォルトなので、ある意味期待通りではあるのですがリサイズ時には嬉しくありません。
対策は user-select: none;
を指定することです。このプロパティで、テキストの範囲選択を強制的に無効にできます。もしくはドラッグ中はマウスの操作を無効にすることでも防げます。
dragbar.addEventListener("mousedown", function (e) {
e.preventDefault(); // preventDefaultでマウス操作を無効にすることでも対応可能
isDragging = true;
document.body.style.userSelect = "none"; // 追加
});
また、リサイズ操作が終わったあとにはもとに戻したいので mouseup
などのイベント時にプロパティを修正します。
document.addEventListener("mouseup", function (e) {
if (isDragging) {
isDragging = false;
document.body.style.userSelect = "auto";
document.body.style.pointerEvents = "auto";
}
});
以上のように非常にシンプルなCSS指定で安定したドラッグのリサイズUIを実装することができます。
Discussion