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
#innerdivs zu aktualisieren. - Zeit für Update-Funktion: Dies ist eine weitere Funktion, die wir noch nicht programmiert haben, aber sie gibt
truezurück, wenn ein Update erforderlich ist. Dies ist eine Möglichkeit, die Anzahl der Aufrufe derupdate()-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)unseresmouse-Objekts auf die Mitte des Elements (e).updatePosition(): Aktualisiert die aktuelle Position unseresmouse-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#innerdivs.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!
Die CSS-Version :)
Ich fand das sehr clever, aber... Sie verwenden 100 leere Anker, um den Effekt zu erzeugen.
Gut gemacht, aber nicht produktionsreif.
Wäre es performanter, die Berechnung der Mausereignisse von den Stilaktualisierungen hier zu entkoppeln?
Theoretisch ja, aber als ich die refreshRate auf 1 reduziert und getestet und verglichen habe, gab es wirklich keinen Unterschied.....
Original mit refreshRate auf 1 reduziert: https://codepen.io/asiankingofwhales/pen/GxWOBL?editors=1010
Entkopplung der Mausberechnung von Stilaktualisierungen: https://codepen.io/asiankingofwhales/pen/VXprjX?editors=0010
Hallo WeiLi Fan!
Ich denke, Sie werden ein besseres Verständnis dafür bekommen, wie die Methode
isTimeToUpdatefunktioniert, wenn Sie diese CSS-Zeilen auskommentierenMit einer
updateRatevon 1 oder 0 wird Ihr inner div bei jeder Mausbewegung aktualisiert (bei jedem Pixel)!Die Idee hinter der Methode
isTimeToUpdateist es, die Anzahl der Aufrufe der Methodeupdatezu verringern. Dadurch verringern wir auch die Anzahl der Berechnungen, die vom Computer des Kunden durchgeführt werden.Dies führt jedoch zu einem ruckartigen Übergang zwischen den Updates, wenn es allein gelassen wird. Deshalb wenden wir CSS-Übergänge an! Wir haben jetzt einen schönen und sanften Übergang zwischen jedem Update.
Versuchen Sie, Ihre
updateRatehoch genug einzustellen und diese CSS-Zeilen auszukommentieren. Sie werden deutlicher sehen, wie oft Sie die neue 3D-Rotation für Ihr inner div berechnen.Ich hoffe, das hilft! :)
Schöne Darstellung. Haben Sie https://micku7zu.github.io/vanilla-tilt.js/ gemacht?
Hallo Nico!
Der Hauptpunkt dieses Beitrags ist es, ein Beispiel für einen coolen CSS-Trick zu geben und zu erklären, wie er gemacht werden kann. :)
Schöne Entdeckung übrigens!