Signatur
Beschreibung
Die schreibgeschützte Eigenschaft commonAncestorContainer eines Range-Objekts gibt den tiefsten gemeinsamen Vorfahren von startContainer und endContainer zurück. Das ist der am weitesten unten im Dokumentbaum liegende Knoten, der beide Grenzpunkte des Bereichs umschließt.
Liegen Start und Ende im selben Knoten, zum Beispiel beide im selben Textknoten, dann ist commonAncestorContainer genau dieser Knoten. Das Ergebnis kann also auch ein Text-Knoten sein und muss kein Element sein. Umfasst der Bereich dagegen mehrere Absätze, bekommt man meist ein Container-Element wie <div> oder <article>.
In der Praxis braucht man die Eigenschaft oft bei Texteditoren, Markierungs- und Annotationswerkzeugen sowie bei Kontextmenüs. Damit lässt sich prüfen, ob eine Benutzerauswahl innerhalb eines bestimmten Bereichs liegt (z. B. in einem contenteditable-Editor). Außerdem kann man den umgebenden Block ermitteln, um Formatierungen anzuwenden.
Der Wert wird jedes Mal neu berechnet, wenn sich die Grenzpunkte ändern, etwa durch setStart(), setEnd(), selectNode() oder durch Änderungen am DOM.
Rückgabewert
Node, der beide Grenzpunkte enthält. Das kann ein Element, ein Text-Knoten, ein DocumentFragment oder das Document selbst sein.Beispiele
Gemeinsamen Vorfahren zweier Absätze ermitteln
// HTML: <article id="post"><p id="a">Erster Absatz</p><p id="b">Zweiter Absatz</p></article>
const range = document.createRange();
range.setStart(document.getElementById('a').firstChild, 3);
range.setEnd(document.getElementById('b').firstChild, 5);
console.log(range.commonAncestorContainer.id);
Start und Ende im selben Textknoten
const p = document.createElement('p');
p.textContent = 'Hallo Welt';
document.body.append(p);
const range = document.createRange();
range.setStart(p.firstChild, 0);
range.setEnd(p.firstChild, 5);
const ancestor = range.commonAncestorContainer;
console.log(ancestor.nodeType === Node.TEXT_NODE, ancestor.nodeName);
Prüfen, ob die Auswahl im Editor liegt
const editor = document.querySelector('[contenteditable]');
document.addEventListener('selectionchange', () => {
const selection = document.getSelection();
if (!selection || selection.rangeCount === 0) return;
const ancestor = selection.getRangeAt(0).commonAncestorContainer;
const insideEditor = editor.contains(ancestor);
console.log(insideEditor ? 'Auswahl im Editor' : 'Auswahl außerhalb');
});
Nächstes umgebendes Element finden (Textknoten berücksichtigen)
const getAncestorElement = (range) => {
const node = range.commonAncestorContainer;
return node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
};
const range = document.getSelection()?.rangeCount
? document.getSelection().getRangeAt(0)
: null;
if (range) {
const block = getAncestorElement(range).closest('p, li, h1, h2, h3');
console.log('Umgebender Block:', block?.tagName);
}
// Wichtig · Fallstricke
- Häufiger Fehler: Textknoten. Das Ergebnis ist oft ein
Text-Knoten. Der hat keine Methoden wieclosest(),classListoderquerySelector(). Prüfe deshalb vorhernodeTypeoder weiche aufparentElementaus. - Zugeklappter Bereich: Bei einem leeren Bereich (
collapsed === true) ist der Wert einfach derstartContainer. - Schreibgeschützt: Eine Zuweisung hat keine Wirkung, im Strict Mode wirft sie einen
TypeError. Um den Bereich zu ändern, nutzesetStart()/setEnd()oderselectNode(). - Shadow DOM: Innerhalb von Shadow Roots liefert
document.getSelection()je nach Browser Bereiche, die an der Shadow-Grenze angepasst sind. Der gemeinsame Vorfahre kann dann der Host statt des eigentlichen inneren Knotens sein. Für solche Fälle gibt esSelection.getComposedRanges(), das aber noch nicht überall unterstützt wird. StaticRange(z. B. ausInputEvent.getTargetRanges()) hat keine EigenschaftcommonAncestorContainer.- Kompatibilität: Wird von allen modernen Browsern und seit dem Internet Explorer 9 unterstützt.