Start · Sprachen · JavaScript · Referenz · Document.createRange()

Document.createRange()

Methode

Erzeugt ein neues, leeres <code>Range</code>-Objekt, dessen Start- und Endpunkt auf Versatz 0 des aufrufenden <code>Document</code> liegen.

seit JavaScript Baseline: alle Browser (DOM Level 2) Kategorie: webapi

Signatur

Document.prototype.createRange()

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() oder deleteContents() ausschneiden, kopieren oder löschen,
  • Knoten mit insertNode() oder surroundContents() einfügen bzw. umhüllen,
  • Position und Größe eines Textstücks mit getBoundingClientRect() bzw. getClientRects() messen,
  • HTML-Strings mit createContextualFragment() in ein DocumentFragment umwandeln.

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

Typ
Range
Beschreibung
Ein neues 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
true true 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());
npm install my-package

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);
JavaScript macht <mark>Spaß</mark>.

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`);
Wort bei x=…, y=…, Breite …px (abhängig vom Layout)

// 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 IndexSizeError aus.
  • surroundContents() wirft einen InvalidStateError, wenn der Range ein Element nur teilweise umfasst. Robuster ist dann extractContents() + 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 StaticRange oder die CSS Custom Highlight API oft besser geeignet.
  • Sicherheit: range.createContextualFragment(html) führt enthaltene <script>-Elemente beim Einfügen aus, anders als innerHTML. 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 Konstruktor new Range() funktioniert nicht im Internet Explorer. In sehr alten IE-Versionen (≤ 8) gab es nur das proprietäre TextRange.
  • 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.