首页 > 其他分享 >CSS3: 利用分层动画让元素沿弧形路径运动

CSS3: 利用分层动画让元素沿弧形路径运动

时间:2023-04-21 21:07:23浏览次数:54  
标签:CSS3 动画 cubic bezier 100px timing 分层 animation webkit


译者注:部分代码示例中可以看效果(作者写在博文里面了…),我偷懒把它做成Gif图了。

 

CSS 的 animations (动画) 和 transitions(变换)擅于实现从点 A 到点 B 的直线运动,运动轨迹是直线路径。给一个元素添加了 animation 或者 transition 以后,无论你如何调整贝塞尔曲线,都无法让它沿着弧形路径运动。你可以通过自定义 timing function 属性,做出弹动的效果,但是它沿着 X 和 Y 轴相对移动的值永远是相同的。

 

与 其使用 JavaScript 实现外观自然的运动,不如尝试用这种简单的方式:分层动画,绕过已有的限制。通过使用两个或多个元素实现动画效果,我们可以更加细粒度地控制某个元素的路 径,沿着 X 轴运动使用一种 timing function ,沿着 Y 轴运动使用另一种 timing function 。

问题所在



CSS3: 利用分层动画让元素沿弧形路径运动_html



当我们深入探讨解决方案之前,看看到底问题在哪。CSS animationstransitions 限制我们只能沿直线路径运动。元素总是沿着点 A 到点 B 的最短路径运动,如果我们另辟蹊径,告诉 CSS 沿着“更好的路径”,而不是“最短路径”运动呢?

 

用 CSS (开启硬件加速)实现两点之间的运动,最直截了当的方式是使用 transformtranslate 在一定时间内移动某个元素。这就产生了直线运动。在 @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,两个方向联合作用使元素沿着一个角度运动。



CSS3: 利用分层动画让元素沿弧形路径运动_ViewUI_02



解决方案:每个轴执行自己的动画函数

那么,原先展示的例子中我们如何实现的弧形路径呢?为了让创建的路径不是直线,我们想让元素沿 X 轴和 Y 轴的运动速度不同步

 

先前例子中都用到了 linear 线性运动函数,如果我们给运动的元素包裹一个容器,我们可以为 X 轴应用一种动画函数,Y 轴应用另一种动画函数。以下例子,我们在 X 轴使用 ease-in ,Y 轴使用 ease-out



CSS3: 利用分层动画让元素沿弧形路径运动_html_03



每个轴元素的具体实现

不幸的是,我们不能只把 transform 动画简单叠加:因为只有最后声明的动画会执行。那么我们如何把两个动画效果联合起来呢?可以把一个元素放入另一个元素内部,给容器元素加一种动画,给里面的子元素添加另一种动画。

 

在以上例子中,你已经看到一个点沿着弧形路径运动,看到两个独立的元素一起做动画,只不过容器元素是完全透明的。为了清晰地看到两个元素沿着弧形路径是如何相互作用的,我们给容器元素加个边框看看呗:



CSS3: 利用分层动画让元素沿弧形路径运动_html_04



那个点藏在带边框的盒子内部,跟随盒子一起沿 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-inease-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 属性做分层动画同样好用。

 

如果有个绝对定位的元素,通过给 leftbottom 属性加特效,就可以实现弧形路径运动,单个元素就可以,不需要容器元素。为什么不这么做呢:它性能稍差一些,动画的每一帧都会引起重绘。使用带伪元素的分层动画,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:点击这里


更多参考:

SVG 系列教程列表

SVG动画入门

SVG动画入门(二)

SVG技术入门:线条动画实现原理

如何使用CSS来修改SVG原点和制作SVG动画

纯CSS实现帅气的SVG路径描边动画效果

SVG矢量绘图 path路径详解(基本画法)

SVG矢量绘图 path路径详解(贝塞尔曲线及平滑)

HTML5: 利用SVG动画动态绘制文字轮廓边框线条


标签:CSS3,动画,cubic,bezier,100px,timing,分层,animation,webkit
From: https://blog.51cto.com/u_8895844/6214185

相关文章

  • HTML5: 利用SVG动画动态绘制文字轮廓边框线条
    DEMO:点击这里看效果 简要教程这是一款很酷的html5svg线条动态绘制文字轮廓边框动画特效。SVG路径动画在网页设计中是一项热门的技术,它允许我们绘制各种简单、精美的图标和文字。关于使用SVG制作图标方面的知识,请参考阅读ESSENTIALICONS。制作流程先......
  • 蓝牙Sig Mesh 概念入门③——分层结构Layered architecture
    文章目录一、Modellayer二、FoundationModellayer三、Accesslayer四、Transportlayer五、Networklayer六、Bearerlayer一、Modellayermodel定义了一个节点支持的功能特性,每一个model都定义了自己的opcode和status。比如genericonoffmodel,定义了GenericON/OFF/G......
  • vue实现的常见的动画效果
    本文包括的动画:zoom-inzoom-in-leftzoom-in-rightzoom-in-topzoom-in-bottomzoom-in-center-xzoom-in-center-yslideslide-leftslide-rightslide-topslide-bottomzoom-in-left.ivy-zoom-in-left-enter-active,.ivy-zoom-in-left-leave-active{transi......
  • 直播平台开发,Clip-path实现按钮流动边框动画
    直播平台开发,Clip-path实现按钮流动边框动画1.实现步骤添加div标签<div>苏苏_icon</div>div{ position:relative; width:220px; height:64px; line-height:64px; text-align:center; color:#fff; font-size:20px; background:#55557f; cursor:poin......
  • 11-CSS3属性详解(一)
    title:11-CSS3属性详解(一)publish:true前言我们在上一篇文章中学习了CSS3的选择器,本文来学一下CSS3的一些属性。本文主要内容:文本盒模型中的box-sizing属性处理兼容性问题:私有前缀边框背景属性渐变文本text-shadow:设置文本的阴影格式举例: text-s......
  • 12-CSS3属性详解:动画详解
    title:12-CSS3属性详解:动画详解publish:true前言本文主要内容:过渡:transition2D转换transform3D转换transform动画:animation过渡:transitiontransition的中文含义是过渡。过渡是CSS3中具有颠覆性的一个特征,可以实现元素不同状态间的平滑过渡(补间动画),经常......
  • 13-CSS3属性:Flex布局图文详解
    title:13-CSS3属性:Flex布局图文详解publish:true前言CSS3中的flex属性,在布局方面做了非常大的改进,使得我们对多个元素之间的布局排列变得十分灵活,适应性非常强。其强大的伸缩性和自适应性,在网页开中可以发挥极大的作用。flex初体验我们先来看看下面这个最简单的布局:......
  • 14-CSS3属性详解:Web字体
    title:14-CSS3属性详解:Web字体publish:true前言开发人员可以为自已的网页指定特殊的字体(将指定字体提前下载到站点中),无需考虑用户电脑上是否安装了此特殊字体。从此,把特殊字体处理成图片的方式便成为了过去。支持程度比较好,甚至IE低版本的浏览器也能支持。字体的常见格......
  • 17-CSS3的常见边框汇总
    title:17-CSS3的常见边框汇总publish:trueCSS3常见边框汇总<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>CSS3边框</title><style>body,ul,li,dl,dt,dd,h1,......
  • web页面播放spine动画及播放相关使用及总结spine-player.js
    1.官方git,里面有些例子可以参考。https://github.com/EsotericSoftware/spine-runtimes.git2.官方播放器:http://zh.esotericsoftware.com/spine-player目前测试4.0以上的js支持动画模型透明3.最基本的资源初始化html代码里面:<divid="player-container"style="width:640......