Атрибут draggable в HTML: перетаскивание элементов

Атрибут draggable включает или выключает перетаскивание элемента мышью. Это глобальный атрибут - его можно прописать любому тегу, но одного атрибута мало: чтобы перетаскивание к чему-то привело, нужны ещё и обработчики событий drag-and-drop.

HTML
<div draggable="true">Этот блок можно перетащить</div>

Атрибут draggable: что делает и что тащится по умолчанию

У draggable всего два допустимых значения, и оба нужно писать явно - это перечислимый атрибут, а не булевый.

ЗначениеЧто происходит
trueЭлемент можно перетащить мышью
falseЭлемент перетащить нельзя - и это значение по умолчанию для большинства тегов
Картинки и ссылки без атрибутаПеретаскиваются сами, браузер включает это поведение по умолчанию
Остальные теги без атрибутаНе перетаскиваются - как будто записано draggable="false"

У draggable нет короткой записи без значения - в отличие от contenteditable, где contenteditable без значения равнозначен contenteditable="true". Запись draggable без значения браузер читает как draggable="false" - перетаскивание не включится.

Пример: draggable="true", "false" и без значения рядом

Результат

По-настоящему перетаскивается только первый блок - у короткой записи без значения перетаскивания нет вовсе.

Полный цикл drag-and-drop: dragstart, dragover, drop

Сам по себе draggable только позволяет начать перетаскивание - что произойдёт дальше, решают события. dragstart срабатывает на перетаскиваемом элементе в начале и обычно записывает данные в event.dataTransfer. dragover срабатывает на элементе под курсором на всё время перетаскивания, и в нём обязательно нужно вызвать preventDefault() - иначе браузер не разрешит сброс в этом месте. drop срабатывает в момент отпускания кнопки мыши и читает те же данные обратно через event.dataTransfer.

Пример: перетащить карточку в зону сброса

HTML + JavaScript
<div draggable="true" id="item">Карточка #123</div>
<div id="zone">Отпустите здесь</div>

item.addEventListener("dragstart", e => {
  e.dataTransfer.setData("text/plain", "card-123");
});
zone.addEventListener("dragover", e => e.preventDefault());
zone.addEventListener("drop", e => {
  e.preventDefault();
  var data = e.dataTransfer.getData("text/plain");
});
Результат

dragstart записывает данные, dragover с preventDefault() разрешает сброс, drop считывает те же данные обратно.

Как отключить перетаскивание картинки, включённое по умолчанию

Картинки перетаскиваются мышью без единого атрибута - так браузер ведёт себя по умолчанию, и это часто мешает, когда картинка сама находится внутри области, которую пользователь перетаскивает по-другому (слайдер, карточка, canvas-редактор). Чтобы выключить это поведение, картинке прописывают draggable="false" явно - атрибута без значения или false по умолчанию здесь недостаточно, потому что у картинки свой браузерный draggable включён независимо от разметки.

Пример: обычная картинка и картинка с draggable="false"

HTML
<img src="cat.jpg" alt="Кот">
<img src="cat.jpg" alt="Кот" draggable="false">
Результат

Первая картинка тащится сама, у второй с draggable="false" перетаскивание заблокировано.

Ограничения: недоступно с клавиатуры и плохо работает с сенсорным экраном

У встроенного в браузер drag-and-drop два существенных ограничения. С клавиатуры такое перетаскивание недоступно вовсе - нет ни одной комбинации клавиш, которая заменяла бы зажатую кнопку мыши и движение курсора, поэтому человек, который не пользуется мышью, в принципе не может выполнить это действие. На сенсорных экранах нативный drag-and-drop тоже работает ненадёжно - жест перетаскивания легко путается с прокруткой страницы. Если перетаскивание - единственный способ выполнить действие на странице, часть посетителей просто не сможет им воспользоваться, поэтому рядом обычно оставляют кнопки или другой способ сделать то же самое.

Частые ошибки с атрибутом draggable

Сам атрибут draggable путают редко - ошибки чаще случаются в обработчиках событий, которые должны идти рядом.

ОшибкаЧто происходитКак исправить
Пишут draggable без значения, как contenteditableБраузер читает короткую запись как draggable="false" - перетаскивание не включаетсяПисать значение явно: draggable="true"
Прописывают draggable="true" и ждут, что перетаскивание куда-то приведётБез обработчиков dragstart/dragover/drop элемент просто сдвигается и возвращается на местоДобавлять обработчики событий - draggable только разрешает начать перетаскивание
Забывают preventDefault() в dragoverБраузер не считает место подходящим для сброса, и событие drop не срабатывает вовсеВызывать e.preventDefault() в обработчике dragover
Пытаются отключить перетаскивание картинки через CSSpointer-events и подобные свойства не влияют на нативный drag - картинка продолжает тащитьсяИспользовать именно draggable="false" на самой картинке
Делают drag-and-drop единственным способом переставить элементы спискаЧасть пользователей не может перетаскивать мышью - ни с клавиатуры, ни на части сенсорных экрановДобавлять кнопки «вверх»/«вниз» или другой способ изменить порядок

Шпаргалка по атрибуту draggable

ПравилоЧто запомнить
Где работаетНа любом теге (глобальный атрибут), кроме SVG
trueЭлемент можно перетащить мышью
falseЭлемент перетащить нельзя (значение по умолчанию)
Короткая запись без значенияРавнозначна false - в отличие от contenteditable, работает только явное значение
Картинки и ссылкиПеретаскиваются по умолчанию без атрибута
dragstartНачало перетаскивания, запись данных в dataTransfer
dragoverНужен preventDefault(), иначе drop не сработает
dropМомент отпускания, чтение данных из dataTransfer
КлавиатураНативный drag-and-drop недоступен без мыши - нужна альтернатива
Категория
Поделиться в социальных сетях

Отправить комментарий

0 Комментарии

Отправить комментарий (0)

#buttons=(Хорошо) #days=(20)

Мы используем файлы cookie для улучшения работы сайта. Подробнее
Хорошо
×