Signatur
Beschreibung
document.caretPositionFromPoint() findet heraus, wo genau im Text die Einfügemarke (der Caret) stehen würde, wenn der Nutzer an die Bildschirmkoordinaten (x, y) klickt. Zurück kommt ein CaretPosition-Objekt mit offsetNode (meist ein Textknoten), offset (Zeichenposition innerhalb dieses Knotens) und der Methode getClientRect(), die das Rechteck des Carets liefert.
Typische Einsatzfälle sind eigene Editoren, Drag-and-drop von Text an eine bestimmte Stelle, das Ermitteln des Wortes unter dem Mauszeiger (z. B. für Wörterbuch- oder Übersetzungs-Tooltips), das Platzieren von Markierungen und Kommentaren sowie das Anlegen einer Selektion ab einem Mausklick.
Die Koordinaten beziehen sich auf den Viewport – also dieselben Werte wie MouseEvent.clientX/clientY, nicht pageX/pageY. Ist der Knoten ein Textknoten, ist offset ein Zeichenindex; bei einem Elementknoten ist es der Index des Kindknotens. Liegt der Punkt außerhalb des Viewports oder lässt sich keine Position ermitteln, wird null zurückgegeben.
Über den optionalen Parameter options.shadowRoots kann man Shadow-Roots übergeben, in die hinein die Suche erfolgen darf. Ohne diese Angabe wird eine Position in einem Shadow-DOM auf den Host-Knoten zurückgeführt.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $x Pflicht | number | Horizontale Koordinate in CSS-Pixeln, relativ zum Viewport (entspricht clientX). |
|
| $y Pflicht | number | Vertikale Koordinate in CSS-Pixeln, relativ zum Viewport (entspricht clientY). |
|
| $options | { shadowRoots?: ShadowRoot[] } | {} | Optionales Objekt. shadowRoots ist ein Array von ShadowRoot-Objekten, in deren Inhalt die Caret-Position ermittelt werden darf (auch geschlossene Shadow-Roots, sofern man eine Referenz besitzt). Neuere Ergänzung, nicht überall unterstützt. |
Rückgabewert
CaretPosition-Objekt mit offsetNode, offset und getClientRect() – oder null, wenn keine Position bestimmt werden kann (z. B. Punkt außerhalb des Viewports).Beispiele
Klickposition im Text ermitteln
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(0, offset) + '|' + text.slice(offset));
}
});
Browserübergreifender Helfer mit Fallback auf caretRangeFromPoint()
const getCaretAt = (x, y) => {
if (typeof document.caretPositionFromPoint === 'function') {
const pos = document.caretPositionFromPoint(x, y);
return pos ? { node: pos.offsetNode, offset: pos.offset } : null;
}
// Fallback für ältere WebKit-/Blink-Versionen (nicht standardisiert)
if (typeof document.caretRangeFromPoint === 'function') {
const range = document.caretRangeFromPoint(x, y);
return range ? { node: range.startContainer, offset: range.startOffset } : null;
}
return null;
};
document.addEventListener('dblclick', (e) => {
console.log(getCaretAt(e.clientX, e.clientY));
});
Wort unter dem Mauszeiger ermitteln
const wordAt = (x, y) => {
const pos = document.caretPositionFromPoint(x, y);
if (!pos || pos.offsetNode.nodeType !== Node.TEXT_NODE) return null;
const text = pos.offsetNode.textContent;
let start = pos.offset;
let end = pos.offset;
while (start > 0 && /\p{L}/u.test(text[start - 1])) start--;
while (end < text.length && /\p{L}/u.test(text[end])) end++;
return text.slice(start, end) || null;
};
const article = document.querySelector('article');
article.addEventListener('mousemove', (e) => {
const word = wordAt(e.clientX, e.clientY);
if (word) article.title = `Nachschlagen: ${word}`;
});
Marker an der Klickstelle einfügen und Caret-Rechteck auslesen
const editor = document.querySelector('#editor');
editor.addEventListener('click', (e) => {
const pos = document.caretPositionFromPoint(e.clientX, e.clientY);
if (!pos || !editor.contains(pos.offsetNode)) return;
const range = document.createRange();
range.setStart(pos.offsetNode, pos.offset);
range.collapse(true);
const marker = document.createElement('mark');
marker.textContent = '★';
range.insertNode(marker);
const rect = pos.getClientRect();
console.log('Caret bei', Math.round(rect.left), Math.round(rect.top));
});
// Wichtig · Fallstricke
- Browser-Kompatibilität: Firefox unterstützt die Methode schon lange, Chrome/Edge erst seit Version 128, Safari erst in neueren Versionen. Für ältere Browser gibt es das nicht standardisierte
document.caretRangeFromPoint(), das einenRangezurückgibt – immer per Feature-Erkennung prüfen. - Koordinatensystem: Es werden Viewport-Koordinaten erwartet (
clientX/clientY). WerpageX/pageYübergibt, erhält auf gescrollten Seiten falsche Ergebnisse. nullprüfen: Liegt der Punkt außerhalb des Viewports oder über einem Bereich ohne Inhalt, ist das Ergebnisnull.- Knotentyp beachten:
offsetNodemuss kein Textknoten sein. Bei Elementen istoffsetein Kindindex, kein Zeichenindex. - Formularfelder: Bei
<input>und<textarea>hängt das Verhalten vom Browser ab:offsetNodekann das Element selbst sein, während der Offset sich auf den Wert des Feldes bezieht. - Shadow DOM: Ohne
options.shadowRootswerden Positionen innerhalb von Shadow-Bäumen auf den Host zurückgeführt. Der Parameteroptionsist neuer als die Methode selbst. - Leistung: Der Aufruf löst eine Layout-Berechnung aus. In
mousemove-Handlern besser drosseln, z. B. mitrequestAnimationFrame().