Signatur
Beschreibung
document.createRange() gibt ein neues Range-Objekt zurück. Ein Range beschreibt einen zusammenhängenden Ausschnitt des DOM-Baums. Er wird durch zwei Grenzpunkte festgelegt, einen Start und ein Ende, die jeweils aus einem Knoten und einem Versatz bestehen. Direkt nach dem Erzeugen ist der Range zusammengefallen (collapsed === true): Start und Ende liegen beide auf (document, 0).
Danach legt man mit Methoden wie setStart(), setEnd(), selectNode() oder selectNodeContents() fest, welchen Bereich der Range umfassen soll. Mit einem so eingestellten Range kann man:
- Textbereiche per
window.getSelection()programmatisch markieren, - DOM-Inhalte mit
extractContents(),cloneContents()oderdeleteContents()ausschneiden, kopieren oder löschen, - Knoten mit
insertNode()odersurroundContents()einfügen bzw. umhüllen, - Position und Größe eines Textstücks mit
getBoundingClientRect()bzw.getClientRects()messen, - HTML-Strings mit
createContextualFragment()in einDocumentFragmentumwandeln.
Alternativ gibt es den Konstruktor new Range(), der gleichwertig ist und immer an das globale document gebunden wird. createRange() braucht man vor allem, wenn der Range zu einem anderen Dokument gehören soll, zum Beispiel zum Dokument eines iframes oder eines mit DOMParser erzeugten Dokuments.
Rückgabewert
Range-Objekt. startContainer und endContainer sind das Dokument, startOffset und endOffset sind 0.Beispiele
Leeren Range erzeugen und Grundzustand prüfen
const range = document.createRange();
console.log(range.collapsed); // true
console.log(range.startContainer === document); // true
console.log(range.startOffset, range.endOffset); // 0 0
Inhalt eines Elements programmatisch markieren
// HTML: <p id="code">npm install my-package</p>
const selectText = (element) => {
const range = document.createRange();
range.selectNodeContents(element);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
};
selectText(document.getElementById('code'));
console.log(window.getSelection().toString());
Suchbegriff mit <mark> hervorheben
// HTML: <p id="text">JavaScript macht Spaß.</p>
const highlight = (element, term) => {
const textNode = element.firstChild;
const start = textNode.textContent.indexOf(term);
if (start === -1) return;
const range = document.createRange();
range.setStart(textNode, start);
range.setEnd(textNode, start + term.length);
const mark = document.createElement('mark');
range.surroundContents(mark);
};
const p = document.getElementById('text');
highlight(p, 'Spaß');
console.log(p.innerHTML);
Position eines Textstücks messen (z. B. für Tooltips)
// HTML: <p id="info">Hier steht ein wichtiges Wort.</p>
const textNode = document.getElementById('info').firstChild;
const word = 'wichtiges';
const index = textNode.textContent.indexOf(word);
const range = document.createRange();
range.setStart(textNode, index);
range.setEnd(textNode, index + word.length);
const { top, left, width } = range.getBoundingClientRect();
console.log(`Wort bei x=${Math.round(left)}, y=${Math.round(top)}, Breite ${Math.round(width)}px`);
// Wichtig · Fallstricke
- Versätze hängen vom Knotentyp ab: Bei Text- und Kommentarknoten zählt der Versatz Zeichen (UTF-16-Codeeinheiten). Bei Elementknoten zählt er Kindknoten. Ein falscher Versatz löst einen
IndexSizeErroraus. surroundContents()wirft einenInvalidStateError, wenn der Range ein Element nur teilweise umfasst. Robuster ist dannextractContents()+appendChild()+insertNode().- Ranges sind „lebendig“: Wenn sich das DOM ändert, passt der Browser die Grenzpunkte automatisch an. Das kann bei vielen Ranges auf großen Dokumenten Leistung kosten. Für reine Markierungen ohne DOM-Änderung sind
StaticRangeoder die CSS Custom Highlight API oft besser geeignet. - Sicherheit:
range.createContextualFragment(html)führt enthaltene<script>-Elemente beim Einfügen aus, anders alsinnerHTML. Nicht vertrauenswürdiges HTML nie ungefiltert übergeben (XSS-Gefahr), sondern vorher bereinigen, z. B. mit DOMPurify. - Kompatibilität:
createRange()wird von allen modernen Browsern unterstützt. Der Konstruktornew Range()funktioniert nicht im Internet Explorer. In sehr alten IE-Versionen (≤ 8) gab es nur das proprietäreTextRange. - Nach
selection.addRange()sollte man den Range nicht weiter verändern, wenn die Auswahl gleich bleiben soll: In einigen Browsern ist die Auswahl direkt an das Range-Objekt gekoppelt.