Einen Container per Mausüberlauf mit Perspektive und Transformation animieren

Avatar of Mihai Ionescu
Mihai Ionescu am

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

Ich habe an einer Website gearbeitet, auf der dem Benutzer große Bilder angezeigt werden. Anstatt für diese großen Bilder einen typischen Lightbox-Effekt (eine Zoom-Animation mit schwarzer Überlagerung) zu erstellen, habe ich beschlossen, etwas Interaktiveres und Spaßigeres zu versuchen. Am Ende habe ich einen Bildcontainer programmiert, der sich neigt, wenn der Benutzer den Mauszeiger darüber bewegt.

Hier ist die endgültige Version

Siehe den Pen MrLopq von Mihai (@MihaiIonescu) auf CodePen.

Dieser Effekt wird durch CSS und JavaScript erzielt. Ich dachte, ich mache ein kleines Tutorial, das erklärt, wie jeder Teil funktioniert, damit Sie ihn leicht reproduzieren oder erweitern können.

Ich empfehle, die Almanac-Einträge für perspective und transform zu lesen, bevor wir beginnen. Wir werden uns während des Beitrags auf diese Eigenschaften beziehen, und es ist eine gute Idee, sich mit ihnen vertraut zu machen.

Legen wir los.

Setup

Zuerst benötigen wir einen Container mit einem weiteren inneren Element. Der Container hilft bei der Perspektive.

<div id="container">
  <div id="inner"></div>
</div>

Zu Demonstrationszwecken zentrieren wir die Karte genau in der Mitte des Bildschirms

body {
  /* Full screen width and height */
  width: 100%;
  min-height: 100vh;
    
  /* Centers the container in the middle of the screen */
  display: flex;
  justify-content: center;
  align-items: center;
    
  margin: 0;
  background-color: rgb(220, 220, 220);
}

#container {
  /* This will come into play later */
  perspective: 40px;
}

#inner {
  width: 20em;
  height: 18em;
  background-color: white;
}

Das ergibt eine weiße Karte, die direkt in der Mitte eines hellgrauen Hintergrunds positioniert ist. Beachten Sie, dass wir die Perspektive des #container auf 40px gesetzt haben, was zu diesem Zeitpunkt nichts bewirkt, da wir noch keine Transformationen erstellt haben. Das wird später in JavaScript behandelt.

Siehe den Pen 3D Image Container – Teil 0 von Mihai (@MihaiIonescu) auf CodePen.

Lass uns mit dem Skripten beginnen

Hier ist der Umriss dessen, was wir tun werden

var container = document.getElementById('container');
var inner = document.getElementById('inner');
        
var onMouseEnterHandler = function(event) {
  update(event);
};
var onMouseLeaveHandler = function() {
  inner.style = "";
};
var onMouseMoveHandler = function(event) {
  if (isTimeToUpdate()) {
    update(event);
  }
};

container.onmouseenter = onMouseEnterHandler;
container.onmouseleave = onMouseLeaveHandler;
container.onmousemove = onMouseMoveHandler;

Und hier ist, was all diese Dinge tun (oder tun werden)

  • Handler-Funktionen: Diese Funktionen verarbeiten die Ereignisse, wenn sie eintreten. Wir wollen entscheiden, was passiert, wenn der Cursor in den Container eintritt, sich darüber bewegt und ihn verlässt, daher hat jede dieser Aktionen einen Handler.
  • Update-Funktion: Wir haben diese noch nicht programmiert, aber ihr Ziel wird es sein, die 3D-Rotation unseres #inner divs zu aktualisieren.
  • Zeit für Update-Funktion: Dies ist eine weitere Funktion, die wir noch nicht programmiert haben, aber sie gibt true zurück, wenn ein Update erforderlich ist. Dies ist eine Möglichkeit, die Anzahl der Aufrufe der update()-Funktion zu reduzieren und die Leistung unseres Skripts zu verbessern.
  • Ereignis: Dies ist ein JavaScript-Objekt, das das aufgetretene Ereignis beschreibt.

Der obige Code wird

  • Die 3D-Rotation des inneren divs aktualisieren, sobald die Maus in den Container eintritt.
  • Die 3D-Rotation des inneren divs aktualisieren, wenn die entsprechende Zeit kommt, während sich die Maus über dem Container bewegt.
  • Den Stil des inneren divs zurücksetzen, wenn die Maus den Container verlässt.

Ist es Zeit für ein Update?

Fügen wir die Funktion hinzu, die entscheidet, wann die 3D-Rotation des #inner divs aktualisiert werden soll.

var counter = 0;
var updateRate = 10;
var isTimeToUpdate = function() {
  return counter++ % updateRate === 0;
};

Wenn der counter die updateRate erreicht, erfolgt eine Aktualisierung.

An diesem Punkt können Sie versuchen, die update-Funktion durch ein console.log() zu ersetzen und mit der updateRate zu spielen, um zu sehen, wie alles zusammen funktioniert.

Die Maus

Als nächstes kommt das Mausobjekt. Dieses ist etwas komplexer als die anderen Abschnitte. Dennoch ist es nicht allzu schwer zu verstehen, aber der Code kann einschüchternd wirken, besonders wenn Sie neu in JavaScript sind.

// Init
var container = document.getElementById('container');
var inner = document.getElementById('inner');
// Mouse 
var mouse = {
  _x: 0,
  _y: 0,
  x: 0,
  y: 0,
  updatePosition: function(event) {
    var e = event || window.event;
    this.x = e.clientX - this._x;
    this.y = (e.clientY - this._y) * -1;
  },
  setOrigin: function(e) {
    this._x = e.offsetLeft + Math.floor(e.offsetWidth/2);
    this._y = e.offsetTop + Math.floor(e.offsetHeight/2);
  },
  show: function() { return '(' + this.x + ', ' + this.y + ')'; }
}
// Track the mouse position relative to the center of the container.
mouse.setOrigin(container);

Auch hier gehen wir das gemeinsam durch.

  • show(): Zeigt die aktuelle Position der Maus an (wenn Sie etwas Debugging in der Browserkonsole durchführen möchten).
  • setOrigin(e): Setzt die Koordinaten (0,0) unseres mouse-Objekts auf die Mitte des Elements (e).
  • updatePosition(): Aktualisiert die aktuelle Position unseres mouse-Objekts relativ zu (0,0).

Die letzte Codezeile mouse.setOrigin(container) legt die Koordinaten (0,0) unseres mouse-Objekts auf die Mitte unseres Containers. Hier ist ein Beispiel, das dies veranschaulicht.

Siehe den Pen 3D Image Container – Teil 1 von Mihai (@MihaiIonescu) auf CodePen.

Die Idee hinter all dem ist, unserem #inner div mehr Rotation zu verleihen, wenn Sie die Maus weiter von der Mitte des Containers wegbewegen.

Stile basierend auf Mausposition aktualisieren

Hier ist unsere Update-Funktion

var update = function(event) {
  mouse.updatePosition(event);
  updateTransformStyle(
    (mouse.y / inner.offsetHeight/2).toFixed(2),
    (mouse.x / inner.offsetWidth/2).toFixed(2)
  );
};

var updateTransformStyle = function(x, y) {
  var style = "rotateX(" + x + "deg) rotateY(" + y + "deg)";
  inner.style.transform = style;
  inner.style.webkitTransform = style;
  inner.style.mozTransform = style;
  inner.style.msTransform = style;
  inner.style.oTransform = style;
};
  • update(): Aktualisiert die Mausposition und aktualisiert den Stil des #inner divs.
  • updateTransformStyle(): Aktualisiert den Stil für jeden Vendor-Präfix.

Sind wir fertig?

Wir sollten ein paar Tests machen! Es sieht so aus, als ob sich die Perspektive ändert, wenn der Mauszeiger in die Karte eintritt und sie verlässt, aber es ist nicht so reibungslos, wie es sein könnte

Siehe den Pen 3D Image Container – Teil 2 von Mihai (@MihaiIonescu) auf CodePen.

Ach ja! Wir haben ihm gesagt, er soll die Rotation unseres #inner divs jedes Mal aktualisieren, wenn der counter die updateRate erreicht. Das führt zu einem ruckartigen Übergang zwischen den Updates.

Wie lösen wir das? CSS-Übergänge.

Übergänge hinzufügen

#inner {
  transition: transform 0.5s;
}

Dies sind willkürliche Zahlen. Sie können mit den Perspektiven- und Transformationswerten spielen, um den Effekt nach Belieben dramatischer oder weniger dramatisch zu gestalten.

Siehe den Pen 3D Image Container – Teil 3 von Mihai (@MihaiIonescu) auf CodePen.

Beachten Sie, dass das Ändern der Seitengröße einige Probleme verursachen wird, da sich die Position des Containers auf der Seite ändert. Die Lösung besteht darin, Ihr mouse-Objekt nach dem Größenwechsel der Seite erneut in Ihrem container zu zentrieren.

Zusammenfassend

Wir sind fertig! Jetzt haben wir einen Container, um ein Element etwas interaktiver zu gestalten. Die Demo am Anfang dieses Beitrags verwendet ein Bild im Container, aber dies kann auch für andere Dinge als Bilder verwendet werden, einschließlich Formulare, Modals oder praktisch für jeden anderen Inhalt, den Sie in den Container einfügen. Gehen Sie experimentieren!