Start · Sprachen · JavaScript · Referenz · Range

Range

Schnittstelle

Die <code>Range</code>-Schnittstelle stellt einen zusammenhängenden Ausschnitt eines Dokuments dar, der ganze Knoten und Teile von Textknoten umfassen kann.

seit JavaScript DOM Level 2 · Baseline: alle Browser Kategorie: webapi

Signatur

interface Range extends AbstractRange

Beschreibung

Ein Range-Objekt beschreibt einen Bereich im DOM über zwei Randpunkte: einen Start (startContainer + startOffset) und ein Ende (endContainer + endOffset). Ist der Container ein Textknoten, zählt der Offset Zeichen (genauer: UTF-16-Codeeinheiten), sonst zählt er Kindknoten. So lassen sich Bereiche genau angeben, die mitten in einem Wort anfangen und mehrere Elemente überspannen.

Einen Range erzeugst du mit document.createRange() oder new Range(). Die Grenzen setzt du mit setStart(), setEnd(), selectNode() oder selectNodeContents(). Zu den wichtigsten Methoden gehören extractContents(), cloneContents(), deleteContents(), insertNode(), surroundContents(), getBoundingClientRect(), getClientRects(), compareBoundaryPoints() und createContextualFragment().

Typische Einsatzfälle sind Texthervorhebungen, Rich-Text-Editoren, das programmgesteuerte Setzen der Benutzerauswahl (zusammen mit Selection), das Bestimmen der Pixelposition von Text (z. B. für Tooltips am Cursor) sowie das Erzeugen von DOM-Fragmenten aus HTML-Strings.

Ein Range ist live: Änderst du das DOM, passen sich die Randpunkte automatisch an. Wenn du das nicht willst, nimm StaticRange.

Parameter

Name Typ Default Beschreibung
$(Konstruktor) new Range() — Der Konstruktor nimmt keine Argumente. Der neue Range ist zusammengefallen (collapsed ist true) und liegt am Anfang des globalen document, also bei Container document und Offset 0.
$setStart(node, offset) Node, number Setzt den Startpunkt. offset zählt Zeichen bei Text-, Kommentar- und CDATA-Knoten und Kindknoten bei allen anderen Knoten.
$setEnd(node, offset) Node, number Setzt den Endpunkt. Liegt das Ende vor dem Start, fällt der Range auf das neue Ende zusammen.
$collapse(toStart) boolean false Lässt den Range auf einen Randpunkt zusammenfallen: true für den Start, false für das Ende.

Rückgabewert

Typ
Range
Beschreibung
Der Konstruktor und document.createRange() liefern ein neues Range-Objekt. Die Methoden liefern je nach Aufgabe z. B. ein DocumentFragment (extractContents(), cloneContents()), ein DOMRect (getBoundingClientRect()) oder undefined.

Beispiele

Wortteil in einem Absatz hervorheben

// HTML: <p id="intro">Hallo Welt, schön dich zu sehen</p>
const textNode = document.getElementById('intro').firstChild;

const range = new Range();
range.setStart(textNode, 6);  // vor „Welt“
range.setEnd(textNode, 10);   // nach „Welt“

const mark = document.createElement('mark');
range.surroundContents(mark);

console.log(document.getElementById('intro').innerHTML);
Hallo <mark>Welt</mark>, schön dich zu sehen

Elementinhalt per Code auswählen (z. B. für einen Kopieren-Button)

const selectElementText = (el) => {
  const range = document.createRange();
  range.selectNodeContents(el);

  const selection = window.getSelection();
  selection.removeAllRanges();
  selection.addRange(range);
  return selection.toString();
};

const code = document.querySelector('pre code');
console.log(selectElementText(code));
(der Textinhalt des Codeblocks, der jetzt markiert ist)

Pixelposition eines Textabschnitts für einen Tooltip ermitteln

const para = document.querySelector('p');
const range = document.createRange();
range.setStart(para.firstChild, 0);
range.setEnd(para.firstChild, 5);

const rect = range.getBoundingClientRect();
const tip = document.createElement('div');
tip.textContent = 'Hinweis';
tip.style.position = 'fixed';
tip.style.left = `${rect.left}px`;
tip.style.top = `${rect.bottom + 4}px`;
document.body.append(tip);

console.log(Math.round(rect.width) > 0);
true

Knoten verschieben und HTML als Fragment einfügen

const list = document.querySelector('ul');
const range = document.createRange();

// Alle <li> aus der Liste entfernen und als Fragment zwischenspeichern
range.selectNodeContents(list);
const items = range.extractContents();
console.log(list.children.length, items.childNodes.length > 0);

// Neues Markup im Kontext der Liste parsen und einfügen
const fragment = range.createContextualFragment('<li>Neu</li>');
range.insertNode(fragment);
console.log(list.innerHTML);
0 true <li>Neu</li>

// Wichtig · Fallstricke

  • surroundContents() wirft einen InvalidStateError, wenn der Range einen Nicht-Textknoten nur teilweise einschließt, zum Beispiel wenn er mitten in einem <b> anfängt und außerhalb davon endet. Robuster ist extractContents(), dann das Fragment in das Wrapper-Element einfügen und dieses mit insertNode() einsetzen.
  • Offsets: In Textknoten zählen UTF-16-Codeeinheiten. Emojis und andere Zeichen außerhalb der BMP belegen 2 Einheiten, deshalb kann ein falscher Offset ein Ersatzpaar (Surrogate Pair) zerschneiden. Ein Offset außerhalb des gültigen Bereichs löst einen IndexSizeError aus.
  • Sicherheit: createContextualFragment() parst HTML, und anders als bei innerHTML werden darin enthaltene <script>-Elemente beim Einfügen ausgeführt. Übergib nie ungeprüfte Benutzereingaben (XSS-Gefahr). Bereinige sie z. B. mit DOMPurify oder nutze Trusted Types bzw. eine strenge CSP.
  • Live-Verhalten: Viele Ranges, die über längere Zeit bestehen bleiben, kosten bei häufigen DOM-Änderungen Leistung. Für einmalige Bereichsangaben ist StaticRange besser geeignet.
  • Kompatibilität: Range wird von allen modernen Browsern unterstützt. new Range() gibt es erst seit etwa 2017 (der alte IE hat es nicht), document.createRange() dagegen überall. In Node.js steht Range nur über DOM-Implementierungen wie jsdom zur Verfügung.
  • Mehrere Ranges pro Selection unterstützt praktisch nur Firefox. Andere Browser verwenden nur den ersten Range.