Kollisionserkennung

Avatar of Chris Coyier
Chris Coyier am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Ich habe vor Jahren über die Positionsfunktion von jQuery UI geschrieben, aber ich dachte gerade daran, wie nützlich der Teil der Kollisionserkennung dieser Funktion ist. Kurz gesagt: Sie können ein Element dort positionieren, wo Sie es haben möchten, aber wenn berechnet wird, dass die Position, an die Sie es verschieben, außerhalb des Bildschirms oder anderweitig nicht sichtbar wäre, passt es die Positionierung an, um dies zu beheben.

Hier ist ein Beispiel von Disqus, wo das Standardverhalten für dieses Benutzer-Popup darin besteht, sich nach oben zu öffnen, aber wenn es vom oberen Bildschirmrand verdeckt würde, öffnet es sich stattdessen nach unten.

Ich habe keine Ahnung, ob sie jQuery UI verwenden oder nicht (wahrscheinlich nicht).

Ich habe kürzlich dasselbe bei CodePen gemacht, um sicherzustellen, dass der Einstellungen-Dropdown-Bereich nicht unterhalb des Seitenrands geöffnet wurde, sondern stattdessen nach oben geöffnet wurde.

Wir verwenden jQuery UI, da wir es sowieso für ein paar andere Dinge verwenden (Ziehen, Ändern der Größe, möglicherweise zukünftiges Neuanordnen).

Immer wenn ein Element auf einer Seite gerichtet geöffnet wird und Sie nicht zu 100 % sicher sind, dass diese Richtung nicht verdeckt wird, ist eine Kollisionserkennung eine gute Idee.

Tooltips sind ein klassisches Beispiel. Sie könnten einen Tooltip so gestalten, dass er oberhalb und rechts von einem Link geöffnet wird.

$("a[data-tooltip]")
  .on("mouseenter", function() {
     var whichTip = $(this).data("tooltip");
     $(".tooltip[data-tooltip=" + whichTip + "]")
       .position({
         my: "left bottom",
         at: "left top",
         of: $(this)
       })
       .show();
  });

(PS: Wäre es nicht schön, wenn wir Tooltips mit HTML darin irgendwie ohne JS machen könnten?)

Aber wenn sich dieser Link nahe am oberen Rand der Seite befand, könnte sich das leicht über den Rand hinaus öffnen und ziemlich nutzlos sein.

Es könnte auch gefährlich an einem Rand sein, je nachdem, wie es gestaltet ist.

jQuery UI hat standardmäßig die Kollisionserkennung aktiviert und wird "flips", was bedeutet,

Dreht das Element auf die gegenüberliegende Seite des Ziels und die Kollisionserkennung wird erneut ausgeführt, um zu sehen, ob es passt. Die Seite, die mehr vom Element sichtbar lässt, wird verwendet.

Sie müssen das explizit ausschalten, wenn Sie möchten. Kollision hat auch ein paar andere Werte, darunter fit, das die Position verschiebt, bis das Element auf die Seite/den Bereich passt, oder fitflip, das zuerst dreht und dann nach Bedarf passt.

Das würde so aussehen, mit jQuery UI position

$("a[data-tooltip]")
  .on("mouseenter", function() {
     var whichTip = $(this).data("tooltip");
     $(".tooltip[data-tooltip=" + whichTip + "]")
       .position({
         my: "left bottom",
         at: "left top",
         of: $(this),
         collision: "flipfit"
       })
       .show();
  });

Wenn sich der Tooltip nun öffnen und vom oberen Rand oder Rand verdeckt würde, wird er gedreht oder verschoben, um zu passen.

Wie funktioniert das? Mathematik!

Ich bin sicher, Sie können sich vorstellen, wie. JavaScript kennt die Abmessungen und die Position aller Elemente und des Viewports selbst. Es kann also eine kleine Überprüfung durchführen wie: Passt ein Element dieser Größe an dieser Position in diesen Bereich?

Wenn Sie jQuery UI nicht verwenden möchten, könnten Sie sicherlich Ihre eigene Lösung entwickeln. Eine Sache, die ich empfehlen würde, wenn Sie dies tun: Fügen Sie dem Element Klassennamen hinzu, wenn es ein Flip oder Fit durchführt. Das fehlt derzeit in jQuery UI, und Sie benötigen möglicherweise diese Klassennamen, um andere Elemente im Tooltip zu beeinflussen. Sagen wir, um sicherzustellen, dass ein Zeigerpfeil an der richtigen Stelle zeigt.

Einfache Demo

Der Container, gegen den die Kollisionserkennung funktioniert, muss nicht der Viewport sein, es kann ein bestimmter Container sein. Das ist es, was hier geschieht, nur um es zu demonstrieren.

Sehen Sie den Pen collision detection von Chris Coyier (@chriscoyier) auf CodePen.

Und das JS, das die Tooltips auch versteckt

$("a[data-tooltip]")
  .on("mouseenter", function() {
     var whichTip = $(this).data("tooltip");
     $(".tooltip[data-tooltip=" + whichTip + "]")
       .position({
         my: "left bottom",
         at: "left top",
         of: $(this),
         collision: "flip",
         within: ".page-wrap"
       })
       .show();
  })
  .on("mouseleave", function() {
    var whichTip = $(this).data("tooltip");
    $(".tooltip[data-tooltip=" + whichTip + "]")
      .stop()
      .fadeOut(function() {
        $(this).removeAttr("style");
      });
  });