Cet article vous expliquera comment utiliser CSS pour obtenir un effet de rotation 3D intéressant avec le suivi de la souris, rendant l'interaction plus vivante. J'espère que cela sera utile à tout le monde !
Aujourd'hui, un groupe d'amis a posé une telle question, comment implémenter l'effet interactif suivant la souris comme indiqué ci-dessous :
Une brève analyse montre que cet effet interactif a principalement deux noyaux :
Avec l'aide de Sans la capacité de CSS 3D
La rotation des éléments doit être combinée avec le mouvement de la souris
Cet article décrira comment utiliser du CSS pur pour obtenir des effets interactifs similaires et utiliser JavaScript pour lier les événements de la souris afin de restaurer rapidement l'effet ci-dessus. [Apprentissage recommandé : Tutoriel vidéo CSS]
Comment obtenir un effet de rotation 3D similaire sans JavaScript, juste CSS ?
Une petite astuce appelée annulation de rotation positive et négative ou annulation de rotation positive et négative sera utilisée ici. Eh bien, le nom est très étrange, cela ressemble à un concept mathématique.
En animation, la rotation est un attribut très couramment utilisé
{ transform: rotate(90deg); }
Que se passera-t-il si nous ajoutons une rotation dans différentes directions à des éléments à différents niveaux ?
Prenons d'abord le scénario. Nous avons une telle couche de structure HTML :
<div> <div> <div>正负旋转相消3D动画</div> </div> </div>
Le style est le suivant :
.content
est notre contenu principal. Si l'élément parent .rotate
effectue une rotation linéaire avant de 360° et que l'élément parent le plus à l'extérieur .reverseRotate
effectue une rotation linéaire inverse de 360°, quel sera l'effet ? .content
内是我们的主要内容,好了,现在想象一下,如果父元素 .rotate
进行正向 linear 360° 旋转,最外层的父级元素 .reverseRotate
进行反向 linear 360° 旋转,效果会是啥样?
CSS 代码如下:
.rotate { animation: rotate 5s linear infinite; } .reverseRotate { animation: reverseRotate 5s linear infinite; } @keyframes rotate { 100% { transform: rotate(360deg); } } @keyframes reverseRotate { 100% { transform: rotate(-360deg); } }
我们可以得到这样一种动画(注意,下图是 GIF 不是 PNG):
神奇!因为一正一反的旋转,且缓动函数一样,所以整个 .content
看上去依然是静止的!注意,这里整个 .content
静止的非常重要。
有读者看到这里就要骂人了,作者你个智障,静止了不就没动画了吗?哪来的动画技巧?
别急!虽然看上去是静止的,但是其实祖先两个元素都是在旋转的!这会看上去风平浪静的效果底下其实是暗流涌动。用开发者工具选取最外层祖先元素是这样的:
既然如此,我们继续思考,如果我在其中旋转的一个父元素上,添加一些别的动画会是什么效果?想想就很刺激。
首先,我们先给这几个元素添加 CSS 3D 转换:
div { transform-style: preserve-3d; perspective: 100px; }
接着,尝试修改上面的旋转动画,在内层旋转上额外添加一个 rotateX:
@keyframes rotate { 0% { transform: rotateX(0deg) rotateZ(0deg); } 50% { transform: rotateX(40deg) rotateZ(180deg); } 100% { transform: rotateX(0deg) rotateZ(360deg); } }
效果如下:
Wow,这里需要好好理解一下。由于内容 .content
层是静止的但其实外层两个图层都在旋转,通过设置额外的 rotateX(40deg)
,相当于叠加多了一个动画,由于正反旋转抵消了,所有整个动画只能看到旋转的 rotateX(40deg)
<div></div>
.content
semble toujours stationnaire ! Notez qu'il est très important que l'intégralité du .content
soit statique ici. Certains lecteurs sont sur le point de jurer en voyant ça. Auteur, vous êtes une personne attardée, n'y aura-t-il pas d'animation ? Où avez-vous acquis vos compétences en animation ? Ne vous inquiétez pas ! Bien qu'ils semblent stationnaires, les deux éléments ancêtres tournent en réalité ! Cela peut sembler être un effet de calme, mais il s’agit en réalité d’un courant sous-jacent. L'utilisation des outils de développement pour sélectionner l'élément ancêtre le plus externe ressemble à ceci :
Tout d'abord, ajoutons une transformation CSS 3D à ces éléments :
body { width: 100vw; height: 100vh; transform-style: preserve-3d; perspective: 500px; } div { width: 200px; height: 200px; background: #000; transform-style: preserve-3d; }
div { transform: rotateX(15deg) rotateY(30deg); }
L'effet est le suivant :
Wow, cela doit être compris attentivement. Étant donné que la couche de contenu .content
est statique mais que les deux couches externes tournent réellement, en définissant un rotateX(40deg)
supplémentaire, cela équivaut à superposer une animation supplémentaire, puisque. les rotations avant et arrière sont décalées, toute l'animation entière ne peut voir que l'animation rotateX(40deg)
pivotée, qui produit l'effet ci-dessus. De cette façon, sans intervention de JavaScript, nous simulons l'effet 3D présenté dans l'image du titre. Bien entendu, cela ne suffit pas à lui seul pour établir un lien avec l'utilisateur. Si cela doit être combiné avec le mouvement de la souris, nous aurons besoin de l'aide de JavaScript.
Notre objectif est d'obtenir un tel effet d'animation :
🎜Ici, nous avons en fait deux éléments principaux :🎜🎜🎜🎜Zone d'activité de la souris🎜🎜🎜 🎜L'objet rotatif lui-même🎜🎜🎜🎜Le mouvement de la souris dans la 🎜zone d'activité de la souris🎜 affectera la rotation 3D de 🎜l'objet rotatif lui-même🎜, et la direction de rotation peut en fait être décomposée dans la direction de l'axe X et la direction de l’axe Y. 🎜🎜Jetons un coup d'oeil, en supposant que notre structure HTML est la suivante : 🎜const mouseOverContainer = document.getElementsByTagName("body")[0]; const element = document.getElementById("element"); mouseOverContainer.onmousemove = function(e) { let box = element.getBoundingClientRect(); let calcY = e.clientX - box.x - (box.width / 2); element.style.transform = "rotateY(" + calcY + "deg) "; }
这里,body
的范围就是整个鼠标可活动区域,也是我们添加鼠标的 mousemove
事件的宿主 target,而 #element
就是需要跟随鼠标一起转动的旋转物体本身。
因为整个效果是需要基于 CSS 3D 的,我们首先加上简单的 CSS 3D 效果:
body { width: 100vw; height: 100vh; transform-style: preserve-3d; perspective: 500px; } div { width: 200px; height: 200px; background: #000; transform-style: preserve-3d; }
效果如下:
没有什么不一样。这是因为还没有添加任何的 3D 变换,我们给元素添加 X、Y 两个方向的 rotate()
试一下(注意,这里默认的旋转圆心即是元素中心):
div { transform: rotateX(15deg) rotateY(30deg); }
效果如下,是有那么点意思了:
好,接下来,我们的目标就是通过结合 mouseover 事件,让元素动起来。
当然,为了更加容易理解,我们把动画拆分为 X、Y 两个方向上的移动。首先看 X 方向上的移动:
这里,我们需要以元素的中心为界:
当鼠标在中心右侧连续移动,元素绕 Y 轴移动,并且值从 0 开始,越来越大,范围为(0, +∞)deg
反之,当鼠标在中心左侧连续移动,元素绕 Y 轴移动,并且值从 0 开始,越来越小,范围为(-∞, 0)deg
这样,我们可以得到这样一个公式:
rotateY = (鼠标 x 坐标 - 元素左上角 x 坐标 - 元素宽度的一半)deg
通过绑定 onmousemove 事件,我们尝试一下:
const mouseOverContainer = document.getElementsByTagName("body")[0]; const element = document.getElementById("element"); mouseOverContainer.onmousemove = function(e) { let box = element.getBoundingClientRect(); let calcY = e.clientX - box.x - (box.width / 2); element.style.transform = "rotateY(" + calcY + "deg) "; }
效果如下:
好吧,旋转的太夸张了,因此,我们需要加一个倍数进行控制:
const multiple = 20; const mouseOverContainer = document.getElementsByTagName("body")[0]; const element = document.getElementById("element"); mouseOverContainer.onmousemove = function(e) { let box = element.getBoundingClientRect(); let calcY = (e.clientX - box.x - (box.width / 2)) / multiple; element.style.transform = "rotateY(" + calcY + "deg) "; }
通过一个倍数约束后,效果好了不少:
同理,我们利用上述的方式,同样可以控制 Y 方向上的移动:
const multiple = 20; const mouseOverContainer = document.getElementsByTagName("body")[0]; const element = document.getElementById("element"); mouseOverContainer.onmousemove = function(e) { let box = element.getBoundingClientRect(); let calcX = (e.clientY - box.y - (box.height / 2)) / multiple; element.style.transform = "rotateX(" + calcX + "deg) "; };
效果如下:
当然,在这里,我们会发现方向是元素运动的方向是反的,所以需要做一下取反处理,修改下 calcX
的值,乘以一个 -1
即可:
let calcX = (e.clientY - box.y - (box.height / 2)) / multiple * -1;
OK,到这里,我们只需要把上述的结果合并一下即可,同时,上面我们使用的是 onmousemove
触发每一次动画移动。现代 Web 动画中,我们更倾向于使用 requestAnimationFrame
去优化我们的动画,确保每一帧渲染一次动画即可。
完整的改造后的代码如下:
const multiple = 20; const mouseOverContainer = document.getElementsByTagName("body")[0]; const element = document.getElementById("element"); function transformElement(x, y) { let box = element.getBoundingClientRect(); let calcX = -(y - box.y - (box.height / 2)) / multiple; let calcY = (x - box.x - (box.width / 2)) / multiple; element.style.transform = "rotateX("+ calcX +"deg) " + "rotateY("+ calcY +"deg)"; } mouseOverContainer.addEventListener('mousemove', (e) => { window.requestAnimationFrame(function(){ transformElement(e.clientX, e.clientY); }); });
至此,我们就能简单的实现题图所示的鼠标跟随 3D 旋转动效:
现在,还有最后一个问题,就是当我们的鼠标离开活动区域时,元素的 transform 将停留在最后一帧,正确的表现应该是复原到原状。因此,我们还需要添加一些事件监听做到元素的平滑复位。
通过一个 mouseleave
事件配合元素的 transition
即可。
div { // 与上述保持一致... transition: all .1s; }
mouseOverContainer.addEventListener('mouseleave', (e) => { window.requestAnimationFrame(function(){ element.style.transform = "rotateX(0) rotateY(0)"; }); });
至此,我们就可以完美的实现平滑出入,整体效果最终如下:
完整的代码,你可以戳这里:CodePen Demo -- CSS 3D Rotate With Mouse Move
(学习视频分享:web前端)
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!