原文:Moving along a curved path in CSS with layered animation
翻译:涂鸦码龙译者注:部分代码示例在原文中可以看效果(作者写在博文里面了…),我偷懒把它做成Gif图了。
CSS 的 animations (动画) 和 transitions(变换)擅于实现从点 A 到点 B 的直线运动,运动轨迹是直线路径。给一个元素添加了 animation
或者 transition
以后,无论你如何调整贝塞尔曲线,都无法让它沿着弧形路径运动。你可以通过自定义 timing function 属性,做出弹动的效果,但是它沿着 X 和 Y 轴相对移动的值永远是相同的。
与 其使用 JavaScript 实现外观自然的运动,不如尝试用这种简单的方式:分层动画,绕过已有的限制。通过使用两个或多个元素实现动画效果,我们可以更加细粒度地控制某个元素的路 径,沿着 X 轴运动使用一种 timing function ,沿着 Y 轴运动使用另一种 timing function 。
问题所在
当我们深入探讨解决方案之前,看看到底问题在哪。CSS animations
和 transitions
限制我们只能沿直线路径运动。元素总是沿着点 A 到点 B 的最短路径运动,如果我们另辟蹊径,告诉 CSS 沿着“更好的路径”,而不是“最短路径”运动呢?
用 CSS (开启硬件加速)实现两点之间的运动,最直截了当的方式是使用 transform
的 translate
在一定时间内移动某个元素。这就产生了直线运动。在 @keyframes
中,我们打算在 (0,0) 和 (100,-100) 间来回运动,见上图例子:
@keyframes straightLine { 50% { transform: translate3D(100px, -100px, 0); } } .dot { animation: straightLine 2.5s infinite linear; }
这些看起来并不难懂,但我们稍等片刻,思考一下我们需要的解决方案,拆分开来的动画,视觉上长什么样子呢。
0%
时,元素从 (0,0) 出发,50%
时,我们用了 translate3D(100px, -100px, 0)
把它移动到 (100,-100),然后原路返回。换句话说,我们把元素向右移动了 100px
,向上移动了 100px
,两个方向联合作用使元素沿着一个角度运动。
解决方案:每个轴执行自己的动画函数
那么,原先展示的例子中我们如何实现的弧形路径呢?为了让创建的路径不是直线,我们想让元素沿 X 轴和 Y 轴的运动速度不同步。
先前例子中都用到了 linear
线性运动函数,如果我们给运动的元素包裹一个容器,我们可以为 X 轴应用一种动画函数,Y 轴应用另一种动画函数。以下例子,我们在 X 轴使用 ease-in
,Y 轴使用 ease-out
。
每个轴元素的具体实现
不幸的是,我们不能只把 transform
动画简单叠加:因为只有最后声明的动画会执行。那么我们如何把两个动画效果联合起来呢?可以把一个元素放入另一个元素内部,给容器元素加一种动画,给里面的子元素添加另一种动画。
在以上例子中,你已经看到一个点沿着弧形路径运动,看到两个独立的元素一起做动画,只不过容器元素是完全透明的。为了清晰地看到两个元素沿着弧形路径是如何相互作用的,我们给容器元素加个边框看看呗:
那个点藏在带边框的盒子内部,跟随盒子一起沿 X 轴远动,同时它自己又在 Y 轴方向上下运动。去掉容器盒子的边框,我们就得到了弧形路径。与其在 HTML 中用两个元素,还不如用伪元素实现嘞。如果 HTML 是这样:
<div class="dot"></div>
我们可以添加伪元素:
.dot { /* 容器:沿 X 轴运动 */ } .dot::after { /* 黑点儿,沿 Y 轴运动 */ }
然后,我们需要两块独立的动画代码:X 轴,Y 轴各一块。注意一处用了 ease-in
,另一处用了 ease-out
:
.dot { /*省略 一些布局代码...*/ animation: xAxis 2.5s infinite ease-in; } .dot::after { /* 渲染小黑点儿*/ animation: yAxis 2.5s infinite ease-out; } @keyframes xAxis { 50% { animation-timing-function: ease-in; transform: translateX(100px); } } @keyframes yAxis { 50% { animation-timing-function: ease-out; transform: translateY(-100px); } }
加上 WebKit 前缀,用一些自定义的贝塞尔曲线代替 ease-in
和 ease-out
,我们就可以实现文章最开头展示的效果:
.demo-dot { -webkit-animation: xAxis 2.5s infinite cubic-bezier(0.02, 0.01, 0.21, 1); animation: xAxis 2.5s infinite cubic-bezier(0.02, 0.01, 0.21, 1); } .demo-dot::after { content: ''; display: block; width: 20px; height: 20px; border-radius: 20px; background-color: #fff; -webkit-animation: yAxis 2.5s infinite cubic-bezier(0.3, 0.27, 0.07, 1.64); animation: yAxis 2.5s infinite cubic-bezier(0.3, 0.27, 0.07, 1.64); } @-webkit-keyframes yAxis { 50% { -webkit-animation-timing-function: cubic-bezier(0.02, 0.01, 0.21, 1); animation-timing-function: cubic-bezier(0.02, 0.01, 0.21, 1); -webkit-transform: translateY(-100px); transform: translateY(-100px); } } @keyframes yAxis { 50% { -webkit-animation-timing-function: cubic-bezier(0.02, 0.01, 0.21, 1); animation-timing-function: cubic-bezier(0.02, 0.01, 0.21, 1); -webkit-transform: translateY(-100px); transform: translateY(-100px); } } @-webkit-keyframes xAxis { 50% { -webkit-animation-timing-function: cubic-bezier(0.3, 0.27, 0.07, 1.64); animation-timing-function: cubic-bezier(0.3, 0.27, 0.07, 1.64); -webkit-transform: translateX(100px); transform: translateX(100px); } } @keyframes xAxis { 50% { -webkit-animation-timing-function: cubic-bezier(0.3, 0.27, 0.07, 1.64); animation-timing-function: cubic-bezier(0.3, 0.27, 0.07, 1.64); -webkit-transform: translateX(100px); transform: translateX(100px); } }
以下是文章起始处的例子:
[iframe src="http://jsbin.com/waqofexedu/1/embed?html,css,output" data-url="http://jsbin.com/waqofexedu/1/embed?html,css,output" style="border: 1px solid rgb(170, 170, 170); width: 100%; min-height: 300px; height: 38px;"]
DEMO: 点击这里
代码:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>JS Bin</title> <styel> .post-demo-content { background-color: #f4f4f6; padding: 2em 2em 2em 4em; margin-bottom: 2em; border-top: 1px solid #eee; border-bottom: 1px solid #eee; } .mnc-demo-container-inline { display: inline-block; position: relative; margin-right: 60px; margin-bottom: 30px; margin-top: 15px; } .mnc-demo-container { height: 100px; width: 100px; } .mnc-demo-label { position: absolute; bottom: -38px; color: #666; font-size: 11px; text-align: center; width: 100%; } .mnc-demo-grid { overflow: hidden; border: 2px solid rgba(0,0,0,0.2); height: 100%; width: 100%; } .mnc-demo-line { width: 100%; height: 2px; background-color: rgba(0,0,0,0.2); position: absolute; } .mnc-demo-line-vertical { width: 2px; height: 100%; background-color: rgba(0,0,0,0.2); position: absolute; } .mnc-demo-dot { will-change: transform; -webkit-animation: xAxis 2.5s infinite cubic-bezier(0.02, 0.01, 0.21, 1); animation: xAxis 2.5s infinite cubic-bezier(0.02, 0.01, 0.21, 1); position: absolute; bottom: -10px; left: -10px; } .mnc-demo-dot:after { content: ''; display: block; will-change: transform; width: 20px; height: 20px; border-radius: 20px; background-color: #333; -webkit-animation: yAxis 2.5s infinite cubic-bezier(0.3, 0.27, 0.07, 1.64); animation: yAxis 2.5s infinite cubic-bezier(0.3, 0.27, 0.07, 1.64); } @keyframes yAxis { 50% { -webkit-animation-timing-function: cubic-bezier(0.02, 0.01, 0.21, 1); animation-timing-function: cubic-bezier(0.02, 0.01, 0.21, 1); -webkit-transform: translateY(-100px); transform: translateY(-100px); } } @-webkit-keyframes yAxis { 50% { -webkit-animation-timing-function: cubic-bezier(0.02, 0.01, 0.21, 1); animation-timing-function: cubic-bezier(0.02, 0.01, 0.21, 1); -webkit-transform: translateY(-100px); transform: translateY(-100px); } } @keyframes xAxis { 50% { -webkit-animation-timing-function: cubic-bezier(0.3, 0.27, 0.07, 1.64); animation-timing-function: cubic-bezier(0.3, 0.27, 0.07, 1.64); -webkit-transform: translateX(100px); transform: translateX(100px); } } @-webkit-keyframes xAxis { 50% { -webkit-animation-timing-function: cubic-bezier(0.3, 0.27, 0.07, 1.64); animation-timing-function: cubic-bezier(0.3, 0.27, 0.07, 1.64); -webkit-transform: translateX(100px); transform: translateX(100px); } } </style> </head> <body> <div class="post-demo-content"> <div class="mnc-demo-container mnc-demo-container-inline"> <span class="mnc-demo-label">Curved path</span> <div class="mnc-demo-grid"> <div class="mnc-demo-line" style="top: 20px;"></div> <div class="mnc-demo-line" style="top: 40px;"></div> <div class="mnc-demo-line" style="top: 60px;"></div> <div class="mnc-demo-line" style="top: 80px;"></div> <div class="mnc-demo-line-vertical" style="left: 20px;"></div> <div class="mnc-demo-line-vertical" style="left: 40px;"></div> <div class="mnc-demo-line-vertical" style="left: 60px;"></div> <div class="mnc-demo-line-vertical" style="left: 80px;"></div> </div> <div class="mnc-demo-dot"></div> </div> </div> </body> </html>
你可能注意到我们在所有例子中都用了 @keyframes
,这纯粹是因为我们想展示黑点儿往返的两种状态。如果只想实现点 A 至点 B 的运动,使用 transition
属性做分层动画同样好用。
如果有个绝对定位的元素,通过给 left
和 bottom
属性加特效,就可以实现弧形路径运动,单个元素就可以,不需要容器元素。为什么不这么做呢:它性能稍差一些,动画的每一帧都会引起重绘。使用带伪元素的分层动画,translate
属性又开了硬件加速,动画效果更好,性能也更高。
译者自己搞了个绝对定位的例子:
代码:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>JS Bin</title> <style type="text/css"> #box{ width:50px; height:50px; border: 1px solid; position: absolute; left:100px; top:100px; animation-name: rightMove, bottomMove; animation-duration: 2.5s; animation-iteration-count: infinite; } @keyframes rightMove{ 50% { animation-timing-function: cubic-bezier(0.3, 0.27, 0.07, 1.64); left: 300px; } } @keyframes bottomMove{ 50% { animation-timing-function: cubic-bezier(0.02, 0.01, 0.21, 1); top: 300px; } } </style> </head> <body> <div id="box"></div> </body> </html>
DEMO:点击这里
转自:http://jinlong.github.io/2016/01/14/moving-along-a-curved-path-in-css-with-layered-animation/
更多参考:
相关推荐
【CSS3炫酷元素边框线条动画特效】是一种利用现代浏览器对CSS3特性的支持,创造出引人注目的视觉效果的技术。在这个项目中,开发者通过纯CSS3代码,不依赖JavaScript,实现了动态的边框线条动画。下面我们将深入探讨...
在本实例中,我们将深入探讨如何利用HTML5的`<canvas>`元素和CSS3的3D变换来创建一个3D立方体旋转动画。 首先,HTML5的`<canvas>`元素是一个强大的绘图工具,允许开发者通过JavaScript动态绘制图形。在这个3D立方体...
【纯CSS3实现汽车行驶动画】是一个利用现代CSS3技术创建的交互式网页特效,它无需JavaScript即可展示一辆汽车在页面上行驶的动态效果。这个技术对于提升网站的用户体验和视觉吸引力具有重要作用,尤其适用于儿童游戏...
【CSS3炫酷粒子动画特效】是一种利用现代浏览器对CSS3特性的支持,通过编程方式创建出视觉上引人入胜的动态效果。这个特效主要依赖于CSS3的动画(Animations)和转换(Transforms)特性,以及可能的伪元素(Pseudo-...
- 设置过渡和动画属性,如`transition`和`animation`,使球体在特定时间内按照预设路径运动。 - 可能需要添加鼠标交互,如悬停效果,使球体在用户交互时产生不同的动画响应。 通过以上技术,开发者可以创建出一个...
在本项目中,"纯css3展开扇形弧形多个菜单.rar" 提供了一个使用纯CSS3技术构建的扇形动画菜单。这个菜单设计简洁,动态效果独特且时尚,非常适合现代网页设计。然而,需要注意的是,这个菜单并不支持较旧的Internet ...
CSS3动画可以添加动态效果,例如,当用户触发某个事件时,流程图中的节点可以高亮或者沿特定路径移动,增强用户的交互体验。 4. **ElementUI**: ElementUI是一套基于Vue.js的开源UI组件库,它提供了一系列易于使用...
【CSS3鼠标hover悬停动画特效】是一种利用CSS3特性实现的交互效果,当鼠标指针悬停在某个元素上时,该元素会呈现出预先设定的动态变化。这些动画不仅提升了用户体验,还使网站或应用更具吸引力。在这个压缩包中包含...
SVG动画 - 前端及有SVG动画需求,html格式可直接用,可以参考其中内容改成其他格式
"css3 3D邮寄信封打开动画特效"是利用CSS3的3D转换和动画特性来模拟信封从关闭到打开的过程,为用户创造一种视觉上的惊喜。这种特效常见于网站的登陆页面、通知提示或者创意展示中,可以增强用户的浏览体验。 1. **...
本项目标题“纯CSS3实现的3D小球动画在线演示”所涉及的核心知识点,就是利用CSS3的3D转换和动画特性来创建一个立体的小球动态效果。这个特效模拟了小球落地后跳动的真实物理运动,不断循环,为用户带来沉浸式的交互...
在现代网页设计中,CSS3加载动画已经成为提升用户体验的重要元素之一。"齿轮"主题的CSS3加载动画尤其受到青睐,因为它既具科技感,又能直观地传达“正在处理”或“等待”的信息。本文将深入探讨如何利用CSS3创建轻量...
【CSS3音乐均衡器跳动动画特效】是一种利用CSS3特性来实现的视觉效果,它模拟了音频设备中的音乐均衡器,通过不同颜色的色块动态变化,展示音乐的节奏和韵律。这个特效通常用于网页设计,为用户提供更加生动且富有...
"H5 CSS3环形动画"这个主题,就是关于如何利用这两种技术来创建引人注目的环形动画效果。这篇博客文章可能是探讨如何通过CSS3的动画属性和HTML5的结构元素,来实现这种视觉上的创新。 首先,我们来了解一下HTML5。...
【纯CSS3雷达扫描模拟动画】是一种利用现代Web技术实现的动态效果,它不依赖JavaScript,完全基于CSS3属性和技巧来创建一个类似雷达探测的动画效果。这种动画在网页设计中可以用于增加互动性和视觉吸引力,比如在...
在本资源中,"CSS3制作3D...综上所述,这个压缩包中的代码应该是利用CSS3的3D变换和关键帧动画技术,创建了一个3D旋转的科幻球体动画效果。通过理解和应用这些知识点,开发者可以为网站添加更丰富、动态的视觉体验。
在3D螺旋动画中,通常会结合使用这些旋转函数,以创造出元素沿着螺旋路径运动的效果。 其次,关键帧动画(@keyframes)是CSS3中的另一项重要特性,它允许我们定义一个动画从开始到结束的多个中间状态。例如,我们...
在本文中,我们将深入探讨如何使用CSS3 Animation创建酷炫的文字动画特效。CSS3 Animation是现代网页设计中不可或缺的一部分,它允许我们为元素添加平滑、动态的效果,从而提升用户体验和视觉吸引力。在这个主题中,...
在CSS3的世界里,我们可以利用其强大的动画特性来创建各种引人入胜的视觉效果,其中之一就是“淡淡的雾气飞过动画特效”。这个特效能够为网页增添一种诗意和动态感,使得用户在浏览时获得更加沉浸式的体验。下面将...