Start · Sprachen · JavaScript · Referenz · CaretPosition.offset

CaretPosition.offset

Eigenschaft

Nur lesbare Ganzzahl, die die Position des Cursors (Caret) innerhalb von <code>CaretPosition.offsetNode</code> angibt, z. B. den Zeichenindex in einem Textknoten.

seit JavaScript Firefox 20+, Chrome 128+, Safari 26.2+ (über docum Kategorie: webapi

Signatur

CaretPosition.offset

Beschreibung

Die Eigenschaft offset eines CaretPosition-Objekts gibt als Ganzzahl an, an welcher Stelle innerhalb des Knotens offsetNode die Einfügemarke liegt. CaretPosition-Objekte bekommt man über document.caretPositionFromPoint(x, y), das zu Bildschirmkoordinaten den nächstgelegenen Punkt im Dokument ermittelt.

Was der Wert bedeutet, hängt vom Knotentyp ab:

  • Ist offsetNode ein Textknoten (oder ein anderer CharacterData-Knoten), ist offset die Anzahl der UTF-16-Codeeinheiten vor dem Cursor.
  • Bei einem Elementknoten ist offset der Index des Kindknotens, vor dem der Cursor liegt.

So kann man z. B. herausfinden, auf welches Wort ein Nutzer geklickt hat, an einer bestimmten Stelle einen Range anlegen, Text an der Mausposition einfügen oder eigene Drag-and-Drop-Editoren bauen. offset und offsetNode entsprechen genau den Argumenten, die Range.setStart() und Selection.collapse() erwarten.

Rückgabewert

Typ
number
Beschreibung
Ganzzahl ≥ 0 (nur lesbar): Offset in UTF-16-Codeeinheiten bei Textknoten oder Index eines Kindknotens bei Elementknoten.

Beispiele

Zeichenposition beim Klick bestimmen

document.addEventListener('click', (event) => {
  const pos = document.caretPositionFromPoint?.(event.clientX, event.clientY);
  if (!pos) return;

  const { offsetNode, offset } = pos;
  if (offsetNode.nodeType === Node.TEXT_NODE) {
    const text = offsetNode.textContent;
    console.log(`Offset ${offset}: …${text.slice(Math.max(0, offset - 5), offset)}|${text.slice(offset, offset + 5)}…`);
  }
});
Offset 12: …Welt,| wie …

Angeklicktes Wort ermitteln

const wordAt = (text, offset) => {
  const left = text.slice(0, offset).search(/\S+$/);
  const right = text.slice(offset).search(/\s/);
  const start = left === -1 ? offset : left;
  const end = right === -1 ? text.length : offset + right;
  return text.slice(start, end);
};

document.querySelector('article').addEventListener('dblclick', (e) => {
  const pos = document.caretPositionFromPoint(e.clientX, e.clientY);
  if (pos?.offsetNode.nodeType === Node.TEXT_NODE) {
    console.log('Wort:', wordAt(pos.offsetNode.data, pos.offset));
  }
});
Wort: JavaScript

Marker an der Mausposition einfügen (mit Fallback)

const getCaret = (x, y) => {
  if (document.caretPositionFromPoint) {
    const p = document.caretPositionFromPoint(x, y);
    return p && { node: p.offsetNode, offset: p.offset };
  }
  // Fallback für ältere WebKit/Blink-Browser
  const r = document.caretRangeFromPoint?.(x, y);
  return r && { node: r.startContainer, offset: r.startOffset };
};

document.body.addEventListener('click', (e) => {
  const caret = getCaret(e.clientX, e.clientY);
  if (!caret) return;
  const range = document.createRange();
  range.setStart(caret.node, caret.offset);
  range.collapse(true);
  const mark = document.createElement('span');
  mark.textContent = '📍';
  range.insertNode(mark);
});

// Wichtig · Fallstricke

  • Einheit: Bei Textknoten zählt offset UTF-16-Codeeinheiten, nicht sichtbare Zeichen. Emojis oder Zeichen außerhalb der BMP belegen zwei Einheiten, daher kann text.slice(0, offset) ein Ersatzzeichenpaar (Surrogat) mitten durchtrennen.
  • Knotentyp prüfen: Bei Elementknoten ist offset ein Kindindex und kein Zeichenindex. Deshalb immer zuerst offsetNode.nodeType prüfen.
  • Formularfelder: Bei <input> und <textarea> kann offsetNode das Feld selbst sein. offset bezieht sich dann auf den Wert des Felds. Das Verhalten war in älteren Browsern nicht einheitlich.
  • Kompatibilität: caretPositionFromPoint() gibt es in Firefox schon lange. Chrome/Edge unterstützen es erst ab Version 128, Safari erst in sehr neuen Versionen. Für ältere Browser das nicht standardisierte document.caretRangeFromPoint() als Ersatz verwenden (dann startOffset statt offset).
  • Liegt der Punkt außerhalb des sichtbaren Bereichs, liefert caretPositionFromPoint() null. Vor dem Zugriff auf offset also prüfen.
  • Shadow DOM: Knoten in Shadow-Roots werden nur gefunden, wenn diese im Optionsobjekt { shadowRoots: [...] } übergeben werden.