Start · Sprachen · JavaScript · Referenz · Document.elementsFromPoint()

Document.elementsFromPoint()

Methode

Gibt ein Array aller Elemente zurück, die an den angegebenen Viewport-Koordinaten liegen – geordnet vom obersten (vordersten) bis zum untersten Element.

seit JavaScript Baseline: alle modernen Browser (seit 2020) Kategorie: webapi

Signatur

Document.prototype.elementsFromPoint(x, y)

Beschreibung

document.elementsFromPoint(x, y) ermittelt alle Elemente, die sich an einem bestimmten Punkt im Viewport überlagern. Anders als elementFromPoint(), das nur das oberste Element liefert, erhältst du hier den gesamten „Stapel“, also die komplette Treffer-Hierarchie in Stapelreihenfolge (z-Order): Index 0 ist das vorderste Element, am Ende stehen typischerweise <body> und <html>.

Das ist besonders nützlich für Drag-and-drop (Welche Drop-Zone liegt unter dem gezogenen Element?), für Overlay- und Tooltip-Logik, für Debugging-Werkzeuge (Welche Elemente verdecken einen Button?) sowie für eigene Hit-Tests in Canvas-ähnlichen Oberflächen, die aus DOM-Elementen bestehen.

Die Koordinaten beziehen sich auf den Viewport (wie clientX/clientY eines Mausereignisses), nicht auf das Dokument. Elemente mit pointer-events: none werden ignoriert, ebenso Elemente mit visibility: hidden. Liegt der Punkt außerhalb des Viewports, ist das Ergebnis ein leeres Array.

Parameter

Name Typ Default Beschreibung
$x Pflicht number Horizontale Koordinate in CSS-Pixeln, relativ zur linken Kante des Viewports.
$y Pflicht number Vertikale Koordinate in CSS-Pixeln, relativ zur oberen Kante des Viewports.

Rückgabewert

Typ
Element[]
Beschreibung
Ein echtes Array (keine NodeList) mit allen getroffenen Elementen, sortiert vom obersten zum untersten. Leeres Array, wenn der Punkt außerhalb des Viewports liegt.

Beispiele

Alle Elemente unter dem Mauszeiger protokollieren

document.addEventListener('click', (event) => {
  const stack = document.elementsFromPoint(event.clientX, event.clientY);
  // Kompakte Darstellung: tag#id.klasse
  const labels = stack.map((el) => {
    const id = el.id ? `#${el.id}` : '';
    const cls = el.classList.length ? `.${[...el.classList].join('.')}` : '';
    return `${el.tagName.toLowerCase()}${id}${cls}`;
  });
  console.log(labels.join(' > '));
});
button.btn > div#card.card > main > body > html

Drop-Zone beim Ziehen ermitteln (gezogenes Element verdeckt das Ziel)

const dragged = document.querySelector('#draggable');

document.addEventListener('pointermove', (event) => {
  if (!dragged.hasPointerCapture?.(event.pointerId) && event.buttons !== 1) return;

  // Das gezogene Element liegt oben – daher den ganzen Stapel durchsuchen
  const dropZone = document
    .elementsFromPoint(event.clientX, event.clientY)
    .find((el) => el !== dragged && el.matches('.drop-zone'));

  document.querySelectorAll('.drop-zone').forEach((zone) => {
    zone.classList.toggle('is-over', zone === dropZone);
  });
});

Prüfen, ob ein Button von einem Overlay verdeckt wird

const isCovered = (element) => {
  const rect = element.getBoundingClientRect();
  const x = rect.left + rect.width / 2;
  const y = rect.top + rect.height / 2;
  const [topMost] = document.elementsFromPoint(x, y);
  // Verdeckt, wenn das oberste Element weder das Element selbst noch ein Kind davon ist
  return topMost !== undefined && !element.contains(topMost);
};

const submit = document.querySelector('#submit');
console.log('Verdeckt:', isCovered(submit));
Verdeckt: false

// Wichtig · Fallstricke

  • Viewport-Koordinaten: Verwende clientX/clientY, nicht pageX/pageY. Bei gescrollter Seite liefern Seitenkoordinaten sonst falsche Treffer.
  • pointer-events: none und visibility: hidden schließen Elemente aus – praktisch, um ein gezogenes Element „durchlässig“ zu machen, aber auch eine häufige Ursache für scheinbar fehlende Treffer.
  • Shadow DOM: Auf document aufgerufen, werden Elemente in Shadow Roots auf ihren Host „retargetet“. Für Treffer innerhalb eines Shadow Trees shadowRoot.elementsFromPoint() verwenden.
  • iframes: Inhalte eines <iframe> werden nicht durchsucht; nur das <iframe>-Element selbst erscheint im Ergebnis.
  • Performance: Der Aufruf erzwingt ggf. ein synchrones Layout (Reflow). In pointermove-Handlern sparsam einsetzen oder per requestAnimationFrame drosseln.
  • Kompatibilität: In allen aktuellen Browsern verfügbar; ältere Edge/IE-Versionen kannten nur msElementsFromPoint() (liefert eine NodeList).