We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
今天,群友问了这样一个问题,如下所示的鼠标跟随交互效果,如何实现:
简单分析一下,这个交互效果主要有两个核心:
本文,就将讲述如何使用纯 CSS 实现类似的交互效果,以及,借助 JavaScript 绑定鼠标事件,快速还原上述效果。
如果不借助 JavaScript,仅仅只是 CSS,如何实现类似的 3D 旋转效果呢?
这里会运用到一种名为正反旋转相消或者是正负旋转相消的小技巧。嗯,名字起的很奇怪,好像数学概念一样。
在动画中,旋转是非常常用的属性,
{ transform: rotate(90deg); }
如果我们给不同的层级的元素,添加不同方向的旋转,会发生什么呢?
首先假设一下场景,我们有这样的一层 HTML 结构:
<div class="reverseRotate"> <div class="rotate"> <div class="content">正负旋转相消3D动画</div> </div> </div>
样式如下:
.content 内是我们的主要内容,好了,现在想象一下,如果父元素 .rotate 进行正向 linear 360° 旋转,最外层的父级元素 .reverseRotate 进行反向 linear 360° 旋转,效果会是啥样?
.content
.rotate
.reverseRotate
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) 这个动画,产生了上述的效果。
rotateX(40deg)
这样,在没有 JavaScript 介入的情况下,我们就模拟了题图所示的 3D 效果。当然,仅仅是这样,与用户的联动是不够的,如果一定要结合鼠标移动,我们就需要 JavaScript 的一些辅助了。
我们的目标是实现这样一个动画效果:
这里,我们其实有两个核心元素:
鼠标在鼠标活动区域内的移动,会影响旋转物体本身的 3D 旋转,而旋转的方向其实可以被分解为 X 轴方向与 Y 轴方向。
我们来看一下,假设我们的 HTML 结构如下:
<body> <div id="element"></div> </body>
得到这样一个图形:
这里,body 的范围就是整个鼠标可活动区域,也是我们添加鼠标的 mousemove 事件的宿主 target,而 #element 就是需要跟随鼠标一起转动的旋转物体本身。
body
mousemove
#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() 试一下(注意,这里默认的旋转圆心即是元素中心):
rotate()
div { transform: rotateX(15deg) rotateY(30deg); }
效果如下,是有那么点意思了:
好,接下来,我们的目标就是通过结合 mouseover 事件,让元素动起来。
当然,为了更加容易理解,我们把动画拆分为 X、Y 两个方向上的移动。首先看 X 方向上的移动:
这里,我们需要以元素的中心为界:
这样,我们可以得到这样一个公式:
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 即可:
calcX
-1
let calcX = (e.clientY - box.y - (box.height / 2)) / multiple * -1;
OK,到这里,我们只需要把上述的结果合并一下即可,同时,上面我们使用的是 onmousemove 触发每一次动画移动。现代 Web 动画中,我们更倾向于使用 requestAnimationFrame 去优化我们的动画,确保每一帧渲染一次动画即可。
onmousemove
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 即可。
mouseleave
transition
div { // 与上述保持一致... transition: all .2s; }
mouseOverContainer.addEventListener('mouseleave', (e) => { window.requestAnimationFrame(function(){ element.style.transform = "rotateX(0) rotateY(0)"; }); });
至此,我们就可以完美的实现平滑出入,整体效果最终如下:
完整的代码,你可以戳这里:CodePen Demo -- CSS 3D Rotate With Mouse Move
怎样,其实也不是很难吧?好了,本文到此结束,希望本文对你有所帮助 :)
想 Get 到最有意思的 CSS 资讯,千万不要错过我的公众号 -- iCSS前端趣闻 😄
更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。
如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。
The text was updated successfully, but these errors were encountered:
(检测到是移动设备时改用陀螺仪运动
Sorry, something went wrong.
这个实际使用的时候 确实应该这样处理
真的跟你学了好多css动画的知识哦,赞👍
今天又来学习了 理解更加透彻了
No branches or pull requests
今天,群友问了这样一个问题,如下所示的鼠标跟随交互效果,如何实现:
简单分析一下,这个交互效果主要有两个核心:
本文,就将讲述如何使用纯 CSS 实现类似的交互效果,以及,借助 JavaScript 绑定鼠标事件,快速还原上述效果。
纯 CSS 实现元素的 3D 旋转
如果不借助 JavaScript,仅仅只是 CSS,如何实现类似的 3D 旋转效果呢?
这里会运用到一种名为正反旋转相消或者是正负旋转相消的小技巧。嗯,名字起的很奇怪,好像数学概念一样。
在动画中,旋转是非常常用的属性,
如果我们给不同的层级的元素,添加不同方向的旋转,会发生什么呢?
首先假设一下场景,我们有这样的一层 HTML 结构:
样式如下:
.content
内是我们的主要内容,好了,现在想象一下,如果父元素.rotate
进行正向 linear 360° 旋转,最外层的父级元素.reverseRotate
进行反向 linear 360° 旋转,效果会是啥样?CSS 代码如下:
我们可以得到这样一种动画(注意,下图是 GIF 不是 PNG):
神奇!因为一正一反的旋转,且缓动函数一样,所以整个
.content
看上去依然是静止的!注意,这里整个.content
静止的非常重要。有读者看到这里就要骂人了,作者你个智障,静止了不就没动画了吗?哪来的动画技巧?
别急!虽然看上去是静止的,但是其实祖先两个元素都是在旋转的!这会看上去风平浪静的效果底下其实是暗流涌动。用开发者工具选取最外层祖先元素是这样的:
既然如此,我们继续思考,如果我在其中旋转的一个父元素上,添加一些别的动画会是什么效果?想想就很刺激。
首先,我们先给这几个元素添加 CSS 3D 转换:
接着,尝试修改上面的旋转动画,在内层旋转上额外添加一个 rotateX:
效果如下:
Wow,这里需要好好理解一下。由于内容
.content
层是静止的但其实外层两个图层都在旋转,通过设置额外的rotateX(40deg)
,相当于叠加多了一个动画,由于正反旋转抵消了,所有整个动画只能看到旋转的rotateX(40deg)
这个动画,产生了上述的效果。这样,在没有 JavaScript 介入的情况下,我们就模拟了题图所示的 3D 效果。当然,仅仅是这样,与用户的联动是不够的,如果一定要结合鼠标移动,我们就需要 JavaScript 的一些辅助了。
借助 Javascript 实现鼠标跟随 3D 旋转动效
我们的目标是实现这样一个动画效果:
这里,我们其实有两个核心元素:
鼠标在鼠标活动区域内的移动,会影响旋转物体本身的 3D 旋转,而旋转的方向其实可以被分解为 X 轴方向与 Y 轴方向。
我们来看一下,假设我们的 HTML 结构如下:
得到这样一个图形:
这里,
body
的范围就是整个鼠标可活动区域,也是我们添加鼠标的mousemove
事件的宿主 target,而#element
就是需要跟随鼠标一起转动的旋转物体本身。因为整个效果是需要基于 CSS 3D 的,我们首先加上简单的 CSS 3D 效果:
效果如下:
没有什么不一样。这是因为还没有添加任何的 3D 变换,我们给元素添加 X、Y 两个方向的
rotate()
试一下(注意,这里默认的旋转圆心即是元素中心):效果如下,是有那么点意思了:
好,接下来,我们的目标就是通过结合 mouseover 事件,让元素动起来。
控制 X 方向的移动
当然,为了更加容易理解,我们把动画拆分为 X、Y 两个方向上的移动。首先看 X 方向上的移动:
这里,我们需要以元素的中心为界:
这样,我们可以得到这样一个公式:
rotateY = (鼠标 x 坐标 - 元素左上角 x 坐标 - 元素宽度的一半)deg
通过绑定 onmousemove 事件,我们尝试一下:
效果如下:
好吧,旋转的太夸张了,因此,我们需要加一个倍数进行控制:
通过一个倍数约束后,效果好了不少:
控制 Y 方向的移动
同理,我们利用上述的方式,同样可以控制 Y 方向上的移动:
效果如下:
当然,在这里,我们会发现方向是元素运动的方向是反的,所以需要做一下取反处理,修改下
calcX
的值,乘以一个-1
即可:结合 X、Y 方向的移动
OK,到这里,我们只需要把上述的结果合并一下即可,同时,上面我们使用的是
onmousemove
触发每一次动画移动。现代 Web 动画中,我们更倾向于使用requestAnimationFrame
去优化我们的动画,确保每一帧渲染一次动画即可。完整的改造后的代码如下:
至此,我们就能简单的实现题图所示的鼠标跟随 3D 旋转动效:
设置平滑出入
现在,还有最后一个问题,就是当我们的鼠标离开活动区域时,元素的 transform 将停留在最后一帧,正确的表现应该是复原到原状。因此,我们还需要添加一些事件监听做到元素的平滑复位。
通过一个
mouseleave
事件配合元素的transition
即可。至此,我们就可以完美的实现平滑出入,整体效果最终如下:
完整的代码,你可以戳这里:CodePen Demo -- CSS 3D Rotate With Mouse Move
最后
怎样,其实也不是很难吧?好了,本文到此结束,希望本文对你有所帮助 :)
想 Get 到最有意思的 CSS 资讯,千万不要错过我的公众号 -- iCSS前端趣闻 😄
更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。
如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。
The text was updated successfully, but these errors were encountered: