Start · Sprachen · JavaScript · Referenz · StaticRange

StaticRange

Schnittstelle

Stellt einen unveränderlichen DOM-Bereich dar, dessen Grenzpunkte sich bei Änderungen am DOM-Baum <em>nicht</em> automatisch anpassen.

seit JavaScript Baseline: alle modernen Browser (Konstruktor seit Kategorie: webapi

Signatur

interface StaticRange extends AbstractRange

Beschreibung

StaticRange erweitert AbstractRange und beschreibt einen Inhaltsbereich im DOM über einen Start- und einen Endpunkt (startContainer/startOffset bzw. endContainer/endOffset). Im Unterschied zu Range ist ein StaticRange eine reine Momentaufnahme: Wird der DOM-Baum danach verändert, passt der Browser die Grenzpunkte nicht an.

Da der Browser einen statischen Bereich nicht bei jeder Mutation nachführen muss, ist er deutlich günstiger als ein lebendiger Range. Deshalb verwenden Browser StaticRange etwa in InputEvent.getTargetRanges() (bei beforeinput) und in der CSS Custom Highlight API (Highlight). Dort beschreiben sie, welcher Text von einer Eingabe betroffen wäre bzw. welcher Text markiert werden soll.

Ein StaticRange hat nur die schreibgeschützten Eigenschaften startContainer, startOffset, endContainer, endOffset und collapsed. Methoden wie cloneContents(), deleteContents() oder getBoundingClientRect() gibt es nicht. Brauchst du sie, erzeugst du aus den Grenzpunkten einen normalen Range (siehe Beispiel).

Beim Erstellen prüft der Konstruktor nur, dass kein DocumentType- oder Attr-Knoten als Container übergeben wird. Ob die Offsets gültig sind oder der Start vor dem Ende liegt, prüft er nicht. Ein StaticRange kann also ungültig sein oder durch spätere DOM-Änderungen ungültig werden.

Parameter

Name Typ Default Beschreibung
$rangeSpec Pflicht { startContainer: Node, startOffset: number, endContainer: Node, endOffset: number } Objekt mit den Grenzpunkten, das an den Konstruktor new StaticRange(rangeSpec) übergeben wird. Alle vier Felder sind Pflicht.
$rangeSpec.startContainer Pflicht Node Knoten, in dem der Bereich beginnt. Darf kein DocumentType- oder Attr-Knoten sein, sonst wird ein InvalidNodeTypeError ausgelöst.
$rangeSpec.startOffset Pflicht number Position im Startknoten: bei Textknoten der Zeichenindex, bei Elementen der Index des Kindknotens.
$rangeSpec.endContainer Pflicht Node Knoten, in dem der Bereich endet. Es gelten dieselben Einschränkungen wie bei startContainer.
$rangeSpec.endOffset Pflicht number Position im Endknoten, wird genauso ausgewertet wie startOffset.

Rückgabewert

Typ
StaticRange
Beschreibung
Der Konstruktor gibt ein neues, unveränderliches StaticRange-Objekt mit den angegebenen Grenzpunkten zurück.

Beispiele

StaticRange erzeugen und auslesen

const p = document.createElement('p');
p.textContent = 'Hallo Welt';
const text = p.firstChild;

const range = new StaticRange({
  startContainer: text,
  startOffset: 6,
  endContainer: text,
  endOffset: 10
});

console.log(range.startOffset, range.endOffset); // 6 10
console.log(range.collapsed);                    // false
console.log(text.data.slice(range.startOffset, range.endOffset));
6 10 false Welt

Statisch vs. lebendig: Verhalten bei DOM-Änderungen

const div = document.createElement('div');
div.innerHTML = '<b>A</b><i>B</i><u>C</u>';

const live = document.createRange();
live.setStart(div, 2);
live.setEnd(div, 3);

const fixed = new StaticRange({
  startContainer: div, startOffset: 2,
  endContainer: div, endOffset: 3
});

// Erstes Kind entfernen
div.firstChild.remove();

console.log('Range:', live.startOffset, live.endOffset);
console.log('StaticRange:', fixed.startOffset, fixed.endOffset);
Range: 1 2 StaticRange: 2 3

Betroffenen Text bei beforeinput ermitteln

const editor = document.querySelector('[contenteditable]');

editor.addEventListener('beforeinput', (event) => {
  const [target] = event.getTargetRanges(); // Array<StaticRange>
  if (!target) return;

  // In einen lebendigen Range umwandeln, um den Inhalt zu lesen
  const range = document.createRange();
  range.setStart(target.startContainer, target.startOffset);
  range.setEnd(target.endContainer, target.endOffset);

  console.log(`${event.inputType}: "${range.toString()}"`);
});
deleteContentBackward: "x"

Text mit der CSS Custom Highlight API markieren

// CSS: ::highlight(treffer) { background: yellow; }
const textNode = document.querySelector('p').firstChild;
const index = textNode.data.indexOf('JavaScript');

if (index !== -1 && 'highlights' in CSS) {
  const range = new StaticRange({
    startContainer: textNode, startOffset: index,
    endContainer: textNode, endOffset: index + 'JavaScript'.length
  });
  CSS.highlights.set('treffer', new Highlight(range));
}

// Wichtig · Fallstricke

  • Keine Prüfung der Offsets: Der Konstruktor akzeptiert auch Offsets, die über die Länge des Knotens hinausgehen, oder einen Start, der hinter dem Ende liegt. Liest du damit später Text oder Kindknoten aus, kann das fehlschlagen. Beim Umwandeln in einen Range löst setStart()/setEnd() dann einen IndexSizeError aus.
  • Veraltete Grenzpunkte: Da sich ein StaticRange nicht anpasst, kann er nach DOM-Änderungen auf falsche Stellen oder auf entfernte Knoten zeigen. Werte ihn daher möglichst direkt aus, z. B. noch im selben beforeinput-Handler.
  • Ungültige Knotentypen: Übergibst du einen DocumentType- oder Attr-Knoten als Container, löst der Konstruktor einen InvalidNodeTypeError aus (eine DOMException).
  • Nur wenige Funktionen: Methoden wie toString(), getBoundingClientRect() oder extractContents() gibt es nur bei Range.
  • Leistung: Für viele Markierungen, etwa bei Suchtreffern mit der Highlight API, ist StaticRange günstiger als Range, weil der Browser ihn nicht bei jeder DOM-Änderung nachführen muss.
  • Kompatibilität: Die Schnittstelle selbst gibt es schon länger. Den öffentlichen Konstruktor gibt es erst seit Chrome/Edge 90, Firefox 71 und Safari 13.1. In Node.js steht die Schnittstelle nur über DOM-Implementierungen wie jsdom zur Verfügung.