Voeg slepen toe aan een bestaand zwevend element, zoals een deelvenster, palet, werkbalk, inspecteur of dialoogvenster. Slepen bepaalt niet hoe het element wordt getoond, gesloten, gestapeld of gefocust.
Een speciale gebruikersnaam gebruiken
Begin met slepen vanaf een speciale handgreep als het element selecteerbare tekst, knoppen, invoer of links bevat. Zo blijft de normale content bruikbaar. Zorg dat de handgreep focusbaar is voor toetsenbordbewegingen en geef deze een toegankelijke naam die de interactie met de pijltoetsen vermeldt.
Breng geen role="application" aan op de handgreep. De interactie met ondersteunende technologie wordt onnodig gewijzigd.
Pas cursor: grab/grabbing, touch-action: none en zowel user-select: none als -webkit-user-select: none toe op de handgreep, niet op het hele sleepbare element, zodat tekst daarbuiten selecteerbaar blijft en aanraakgebaren hun gebruikelijke gedrag behouden:
.drag-handle {
cursor: grab;
touch-action: none;
-webkit-user-select: none;
user-select: none;
}
.drag-handle.dragging {
cursor: grabbing;
}
Positie en bereikbaarheid van aanwijzer behouden
Gebruik een positioneringsmodel dat relatief is aan het kijkvenster, zoals position: fixed, als je de beweging vastzet in het kijkvenster.
- Start een sleepactie alleen voor de primaire aanwijzerknop (
event.button === 0). - Registreer de aanwijzerverschuiving op
pointerdownen gebruik deze bij elke verplaatsing, zodat het element niet verspringt als het niet bij de hoek wordt vastgepakt. - Houd de sleepactie actief nadat de aanwijzer de handgreep heeft verlaten. Standaard ingesteld op
setPointerCapture()en de sleepstatus wissen oplostpointercapture. Als de handgreep tijdens het slepen kan worden verwijderd of opnieuw kan worden gerenderd, gebruik je in plaats daarvan listeners op documentniveaupointermove,pointerupenpointercancel, omdat de vastlegging in dat geval verloren gaat. - Wacht eventueel ongeveer 4 pixels beweging voordat je de sleepstatus activeert, zodat een klik op de handgreep geen sleepstijl activeert.
Met aanwijzerregistratie kunnen de bewegingslisteners op de handgreep blijven:
handle.addEventListener('pointerdown', (event) => {
if (event.button !== 0 || event.target.closest('button, input, select, textarea, a')) return;
const rect = draggable.getBoundingClientRect();
offsetX = event.clientX - rect.left;
offsetY = event.clientY - rect.top;
handle.setPointerCapture(event.pointerId);
});
handle.addEventListener('pointermove', (event) => {
if (!handle.hasPointerCapture(event.pointerId)) return;
handle.classList.add('dragging');
moveTo(event.clientX - offsetX, event.clientY - offsetY);
});
handle.addEventListener('lostpointercapture', () => {
handle.classList.remove('dragging');
});
function moveTo(left, top) {
const maxLeft = Math.max(0, window.innerWidth - draggable.offsetWidth);
const maxTop = Math.max(0, window.innerHeight - draggable.offsetHeight);
draggable.style.left = `${Math.max(0, Math.min(left, maxLeft))}px`;
draggable.style.top = `${Math.max(0, Math.min(top, maxTop))}px`;
}
Klem elke aanwijzer- en toetsenbordpositie vast via dezelfde helper, zodat het element bereikbaar blijft. De huidige positie opnieuw vastzetten nadat de viewport of het elementformaat is gewijzigd. Voor elementen met veel opmaak kun je overwegen om tijdens het slepen te vertalen om opmaak per frame te voorkomen. Leg daarna de uiteindelijke positie vast in left en top bij het loslaten.
Toetsenbordbeweging bieden
Als de handgreep de focus heeft, verplaats je het element met de pijltoetsen en roep je preventDefault() aan voor die toetsen. Gebruik dezelfde helper voor vastgezette positionering als voor de beweging van de cursor. Een toename van 15 pixels is een redelijk startpunt. Pas dit aan de grootte en precisiebehoeften van de component aan.
Dialoogspecifieke notitie
Een <dialog> of [popover] kan dit mechanisme gebruiken met de koptekst als gebruikersnaam. Stel margin: 0 in voordat u left en top toewijst, omdat de standaardmarges van de browser de handmatige positionering verstoren. Ga naar Declarative Dialog and Popover Control en Platform Controls Dismiss Dialog voor het gedrag voor openen, sluiten, focus en sluiten van dialoogvensters en pop-overs.
Reservestrategieën
Als slepen alleen een component herpositioneert, behandel je dit als progressive enhancement: zonder JavaScript houd je het element, de content en de bedieningselementen zichtbaar, leesbaar en functioneel op een logische standaardpositie. Zorg dat er geen niet-functionele sleepgreep wordt getoond: als de greep een zelfstandige gripbediening is, verberg je deze standaard en toon je deze als JavaScript wordt geïnitialiseerd. Als een kop ook als greep fungeert, koppel je de sleepmogelijkheden als JavaScript wordt geïnitialiseerd.
Voeg -webkit-user-select: none toe vóór user-select: none, zodat tekstselectie onderdrukt blijft tijdens het slepen in Safari.