Signatur
Beschreibung
Die Schnittstelle Selection steht für die aktuelle Markierung im Dokument. Ein Objekt dafür bekommt man über window.getSelection() oder document.getSelection(). Pro Dokument gibt es genau ein Selection-Objekt. Es ist „live“, ändert sich also, sobald der Benutzer oder ein Skript die Markierung ändert.
Eine Markierung hat einen Anker (anchorNode/anchorOffset, dort beginnt sie) und einen Fokus (focusNode/focusOffset, dort endet sie). Markiert der Benutzer von rechts nach links, liegt der Fokus vor dem Anker. Ist nichts markiert, fallen Anker und Fokus zusammen (isCollapsed === true). Dann beschreibt die Selection nur die Cursor-Position, zum Beispiel in einem contenteditable-Element. Der markierte Inhalt besteht aus einem oder mehreren Range-Objekten (rangeCount, getRangeAt()). Praktisch unterstützt aber nur Firefox mehrere Bereiche.
Typische Einsätze sind:
- markierten Text auslesen (
toString()), etwa für „Zitieren“- oder „Teilen“-Schaltflächen, - Text per Skript markieren (
selectAllChildren(),setBaseAndExtent(),addRange()), - Rich-Text-Editoren bauen: Cursor setzen (
collapse()), Markierung verschieben (modify()), markierten Inhalt löschen (deleteFromDocument()), - prüfen, ob ein Knoten markiert ist (
containsNode()).
Wichtige Eigenschaften: anchorNode, anchorOffset, focusNode, focusOffset, isCollapsed, rangeCount, type ("None", "Caret" oder "Range") und direction. Wichtige Methoden: getRangeAt(), addRange(), removeRange(), removeAllRanges() bzw. empty(), collapse(), collapseToStart(), collapseToEnd(), extend(), setBaseAndExtent(), selectAllChildren(), containsNode(), deleteFromDocument(), modify() und toString(). Änderungen an der Markierung meldet das Event selectionchange auf document.
Rückgabewert
window.getSelection() bzw. document.getSelection(). Wenn das Dokument keinen Browsing-Kontext hat (z. B. ein iframe mit display: none in Firefox), kann auch null zurückkommen.Beispiele
Markierten Text auslesen und Selection-Zustand prüfen
document.addEventListener('mouseup', () => {
const selection = window.getSelection();
if (!selection || selection.isCollapsed) return; // nichts markiert
console.log('Text:', selection.toString());
console.log('Typ:', selection.type);
console.log('Bereiche:', selection.rangeCount);
console.log('Anker:', selection.anchorNode.nodeName, selection.anchorOffset);
console.log('Fokus:', selection.focusNode.nodeName, selection.focusOffset);
});
Inhalt eines Elements per Skript markieren (z. B. Code-Block)
const selectCode = (element) => {
const selection = window.getSelection();
selection.removeAllRanges();
selection.selectAllChildren(element);
};
const pre = document.querySelector('pre');
pre.addEventListener('dblclick', () => {
selectCode(pre);
console.log('Markiert:', window.getSelection().toString().length, 'Zeichen');
});
Cursor in einem contenteditable-Element ans Ende setzen
const editor = document.querySelector('[contenteditable]');
const placeCaretAtEnd = (el) => {
el.focus();
const range = document.createRange();
range.selectNodeContents(el);
range.collapse(false); // false = ans Ende
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
console.log('Typ:', selection.type, '| collapsed:', selection.isCollapsed);
};
placeCaretAtEnd(editor);
Auf Änderungen der Markierung reagieren (Zitieren-Button)
const quoteButton = document.querySelector('#quote');
const onSelectionChange = () => {
const selection = document.getSelection();
const text = selection?.toString().trim() ?? '';
quoteButton.hidden = text.length === 0;
quoteButton.dataset.quote = text;
};
document.addEventListener('selectionchange', onSelectionChange);
quoteButton.addEventListener('click', () => {
console.log(`> ${quoteButton.dataset.quote}`);
document.getSelection().removeAllRanges();
});
// Wichtig · Fallstricke
- Das Objekt ist live:
getSelection()liefert immer dasselbe Objekt, und dessen Werte ändern sich laufend. Wenn du den Zustand festhalten willst, speicheretoString()oder eine Kopie mitgetRangeAt(0).cloneRange(). - Formularfelder: Markierungen in
<input>und<textarea>erscheinen je nach Browser nicht korrekt inSelection, undtoString()ist dort oft leer. Nutze stattdessenselectionStart,selectionEndundsetSelectionRange()am Element. - Mehrere Bereiche: Nur Firefox unterstützt mehr als einen
Range. Chrome und Safari übernehmen beiaddRange()keinen zweiten Bereich, wenn schon einer existiert. Rufe deshalb vorherremoveAllRanges()auf. - Fehler:
getRangeAt(i)wirft einenIndexSizeError, wennrangeCount0 ist. PrüferangeCountalso vorher. - Richtung: Wenn rückwärts markiert wurde, liegt
anchorNodenachfocusNode. Für Start und Ende in Dokumentreihenfolge nimmgetRangeAt(0).startContainerbzw.endContainer. - Shadow DOM: Markierungen innerhalb von Shadow Roots sind nicht überall einheitlich erreichbar. Neuere Browser bieten dafür
getComposedRanges()an, die Unterstützung ist aber noch lückenhaft. - Nicht standardisiert:
modify()ist in keiner Spezifikation festgelegt, funktioniert aber in allen großen Browsern.directionist neu und fehlt in älteren Browsern. - Performance:
selectionchangefeuert sehr oft, etwa bei jeder Cursorbewegung. Aufwendige Handler solltest du drosseln (Debounce).