《CSS Secrets》是@Lea Verou最新著作,这本书讲解了有关于CSS中一些小秘密。是一本CSSer值得一读的一本书,经过一段时间的阅读,我、@南北和@彦子一起将在W3cplus发布一系列相关的读后感,与大家一起分享。

问题

几年前,当CSS动画刚出来的时候是多么的令人兴奋,那时Chris Coyier问我,有没有什么方式使用CSS让元素绕一个圆形的路径运动。当时,它只是一个有趣的想法,但我在无意中发现有很多这方面的用例。例如,Google+添加新成员就使用了这样一个动画。如下图所示:

一个与众不同而又有趣的例子可以看看俄罗斯科技网站的404页面,如下图所示:

通常在404页面上是一个很好的实践地方,下如上图所示,他提供网站主要几个领域的导航菜单。这几个菜单绕着一个圆形路径运动。

然而,每一个菜单项类似行星绕着地球转上一圈,而且上有的文字写着“飞往其他星星的宇宙”。当然,如果只移动行星绕着循环的路径转而文字不旋转,这将使这些文本几乎无法阅读。这只是众多例子之中的一个。但我们怎样才能使用CSS动画达到这样的效果呢?

我们来写一个非常简单的示例,一个头动绕着圆形的路径循环的旋转,这个有点像前面提到的Google+效果的简化版。其结构如下:

<div class="path"><img src="lea.jpg" class="avatar" />
</div>

在还没有开始制作动画之前,我们先设置一些基本样式(例如:大小、背景、外距等),看起来如下图所示:

因为这些都是基本样式,这里没有写出来,但如果你有什么困难,可以查看示例中的代码。最主要的要记住,路径直径是300px,因此半径是150px

我们已经完成了基本样式之后,就可以开始考虑动画怎么写。将头像移到圆中,绕着橙色的路径旋转一圈。我们可能使用CSS动画来实现,那这样动画怎么写呢?当面对这个问题时,我们想到的是这样:

@keyframes spin {to { transform: rotate(1turn); }
}
.avatar {animation: spin 3s infinite linear;transform-origin: 50% 150px; /* 150px = path radius */
}

虽然这朝着正确的方向迈进了一步,头像在绕着圆形的路径旋转,如下图所示:

正如上图所示,头像在绕圆形路径旋转时,你也发现头像自身也颠倒了。如果是文本,文本也会被翻个底朝天,这对于阅读来说是一个相当糟糕的事情。我们只希望头像绕着圆路径运动,同时自身保持同一个方向。

当时我和Chris都没有想出一个合理的方式来解决这个问题。我们可以想出的最好方法是通过多个关键帧绘制近似一个圆形的路径,显然这不是一个好的主意,也没有任何方式能定义出来这样的圆形路径。那么我们必须得想出一个更好的方法,对吗?

使用两个元素的解决方案

我根据Chris提供的参考意见,我终于想出了一个解决方案。这个解决方案背后的主要思想是来自于前面介绍的"平形四边形"和"钻石图片":通过取消嵌套中的transform。然而,这是一个动画,它发生在每一帧的动画之中。需要特别说明的是,就像前面提到的内容,这里需要两个元素。因此,我们需要在HTML中添加一个额外的HTML元素<div>来包裹头像:

<div class="path"><div class="avatar"><img src="lea.jpg" /></div>
</div>

让我们把前面的动画效果用到.avatar容器上。现在我们看到的效果和前面出现的效果是一样的,这并不是我们需要的,因为它也旋转元素自身。但是,如果我们给.avatar设置一个旋转,并且给头像img设置一个相反的旋转,而且他们旋转的值都是相同的,将会发生什么呢?如此一来,两个旋转将相互对冲,我们只会看到他们绕着旋转的原点做圆周运动。

不过有一个问题:这里没有表态的旋转,他们都是经过一系列的角度旋转。例如,如果角度是60deg,那么取消的旋转角度应该是-60deg(或300deg),如果旋转的角度是70deg,那么取消的旋转角度应该是-70deg(或290deg)。它们都是发生在0360deg之间(或01turn之间)。那么我们要怎么设置角度呢?答案比看起来要容易得多。我们只需要给动画的反向设置360deg0deg,如下所示:

@keyframes spin {to { transform: rotate(1turn); }
}
@keyframes spin-reverse {from { transform: rotate(1turn); }
}
.avatar {animation: spin 3s infinite linear;transform-origin: 50% 150px; /* 150px = path radius */
}
.avatar > img {animation: spin-reverse 3s infinite linear;
}

现在,在任何时间,当第一个动画旋转x deg,第二个旋转360 - x deg,其中一个增加多少,另一个就要减少多少。这才是我们想要的,比如下图所示的效果就是我们期望的效果。

代码我们需要改进一些。首先,我们动画的所有参数重复两次。如果我们要调整时间,我们就需要调整两次,这样做较为麻烦。其实可以通过inherit属性继承父元素的animation

@keyframes spin {to { transform: rotate(1turn); }
}
@keyframes spin-reverse {from { transform: rotate(1turn); }
}
.avatar {animation: spin 3s infinite linear;transform-origin: 50% 150px; /* 150px = path radius */
}
.avatar > img {animation: inherit;animation-name: spin-reverse;
}

然而,我们不需要一个全新的动画,只需要最初的一个动画。记得我们在介绍“闪烁”动画一节中,有介绍过animation-direction属性,其中有一个alternate值是非常有用的。在这里我们将使用reverse值,得到一个反向的原动画,因此不需要创建第二个动画:

@keyframes spin {to { transform: rotate(1turn); }
}
.avatar {animation: spin 3s infinite linear;transform-origin: 50% 150px; /* 150px = path radius */
}
.avatar > img {animation: inherit;animation-direction: reverse;
}

我们继续吧!这可能不是最理想的解决方案,因为他需要添加额外的元素,但只使用了不到十行的CSS代码实现了相当复杂的动画效果。

使用单个元素的解决方案

在前一节中,我们解决了问题,但这不是最优的方案,因为它需要修改HTML。当初我给CSS工作组提了一个建议,建议可以在相同的元素指定多个转换源。这应该能够在一个元素上实现,也似乎是一个合理的要求。

在讨论过程中,Aryeh Gregor给CSS的transform规范中提了这样一个声明,似乎令人困惑不解:

transform-origin就是一个语法糖。你可以使用translate()替代。—— @Aryeh Gregor

有关于相关的讨论可以点击这里阅读。

事实证明,每个transform-origin可以模拟两次translate()。例如下面的两个代码段是等价的:

transform: rotate(30deg);
transform-origin: 200px 300px;transform: translate(200px, 300px)rotate(30deg)translate(-200px, -300px);
transform-origin: 0 0;

这看起来很奇怪,让我们对transform了解的更清楚,transform函数不是独立的。每个transform属性不仅应用在元素上,而且整个坐标系统运用在同一个元素上,也将影响所有的transform。这也说明为什么不同的transfrom顺序很重要,不同顺序的相同转换可能前生的结果会完全不同。如果你还不了解这一点,下图可以帮助你更好的理解:

因此,我们可以利用这个方法来处理我们的动画:

@keyframes spin {from {transform: translate(50%, 150px) rotate(0turn) translate(-50%, -150px);}to {transform: translate(50%, 150px) rotate(1turn) translate(-50%, -150px);}
}
@keyframes spin-reverse {from {transform: translate(50%,50%) rotate(1turn) translate(-50%, -50%);}to {transform: translate(50%, 150px) rotate(0turn) translate(-50%, -50%);}
}
.avatar {animation: spin 3s infinite linear;
}
.avatar > img {animation: inherit;animation-name: spin-reverse;
}

这样看起来很笨拙,但不要担心,接下来我们会改善。请注意,我们现在不再有不同的transform-origin,但我们要记住,我们要需要两个元素和两个动画。现在所有都使用相同的transform-origin,可以在.avatar上结合这两个动画:

@keyframes spin {from {transform: translate(50%, 150px) rotate(0turn) translate(-50%, -150px) translate(50%,50%) rotate(1turn) translate(-50%,-50%) }to {transform: translate(50%, 150px) rotate(1turn) translate(-50%, -150px) translate(50%,50%) rotate(0turn) translate(-50%, -50%);}
}
.avatar { animation: spin 3s infinite linear;
}

这代码是得到了改善,但仍然让人感到困惑。我们还能让它变得更简洁吗?我们进一步来改进它:

我们连续做了多次translate()特别是translate(-50%,-150px)translate(50%,50%)。不幸的是,百分比和绝对长度不能结合在一起(除非我们使用calc())。然而,水平的translate相互取消了,但还有两个次translateY(translateY(-150px)translateY(50%))。因为为了取消翻转,我们可以对关键帧这样做:

@keyframes spin{from{transform: translateY(150px) translateY(-50%) rotate(0turn) translateY(-150px) translateY(50%) rotate(1turn);}to {transform: translateY(150px) translateY(-150%) rotate(1turn) translateY(-150px) translateY(50%) rotate(0turn);}
}
.avatar {animation: spin 3s infinite linear;
}

代码变得更少了,重复的也变得更少,但仍然不是很好。我们可以做到更好吗?如果我们的头像在圆的中心,如下图所示:

我们可以继续减少两个translate,然后动画就变成:

@keyframes spin{from{transform: rotate(0turn) translateY(-150px) translateY(50%) rotate(1turn);}to {transform: rotate(1turn) translateY(-150px) translateY(50%) rotate(0turn);}
}
.avatar {animation: spin 3s infinite linear;
}

这似乎是我们今天做得最好的了。这可能是最短的代码。现在最少的重复和没有多余的HTML元素。

原文:  http://www.w3cplus.com/css3/css-secrets/animation-along-a-circular-path.html  ©  w3cplus.com

CSS秘密花园: 沿着路径的动画相关推荐

  1. html逐帧动画,CSS秘密花园: 逐帧动画

    <CSS Secrets>是@Lea Verou最新著作,这本书讲解了有关于CSS中一些小秘密.是一本CSSer值得一读的一本书,经过一段时间的阅读,我.@南北和@彦子一起将在W3cplu ...

  2. 纯CSS实现SVG路径描边动画效果

    SVG中有一个比较重要度属性,stroke.stroke有很多兄弟属性: 1)stroke:线的颜色: 2)stroke-width:线的宽度: 3)stroke-linecap:线的端点,可用值有b ...

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

    一.应该人人皆会的基础技术 简而言之,就是让SVG的描边像是有人绘制一样的动画效果. 国外很多相关介绍的文章,来看看一些效果gif吧~ 纯CSS实现帅气的SVG路径描边动画效果 纯CSS实现帅气的SV ...

  4. css图像描边,纯CSS实现帅气的SVG路径描边动画效果

    一.应该人人皆会的基础技术 简而言之,就是让SVG的描边像是有人绘制一样的动画效果. 国外很多相关介绍的文章,来看看一些效果gif吧~ 我至少看到了4篇外文对此技术介绍(参见文末参考文章),觉得挺有意 ...

  5. UI设计师SVG动画进阶篇——路径变形动画(上篇)

    之前分享了一些自己平时整理的可以通用的SVG动画的教程基本都是最基础的变化,旋转也好,缩放也好,沿路径运动也好,只需要定义CSS3的一些动画属性值或者SVG的动画属性标签,当然,运用得当的话,依靠这些 ...

  6. 纯CSS制作加div制作动画版哆啦A梦

    纯CSS代码加上<div>制作动画版哆啦A梦(机器猫) 哆啦A梦(机器猫)我们大家一定都很熟悉,今天给大家演示怎么用纯CSS代码,来做一个动画版的哆啦A梦. 效果图: ###下面代码同学可 ...

  7. SVG——入门,路径变形动画

    刚学了两天svg基础,随手记个笔记,通过改变svg锚点路径创作动画效果,今天的demo是一个播放和暂停的按钮 动画的原理,无论是帧动画,还是位移动画,无非就是将一个图形从a状态转变为b状态的一个过程 ...

  8. python animation path_帅气的SVG路径描边动画 (path animation) 实战应用

    这是我的一个关于SVG的应用的技术分享网站svgtrick.com,会同步一些文章到这里来,更多关于SVG技术应用可以去网站看看. 要是觉得文章还不错的话,可以多多推荐哦. 今天这篇文章来聊聊SVG路 ...

  9. 谷歌地图路径回放动画的实现(总结)

    因为公司有一些特殊的需求,前几天在做上一个上一个项目的时候,用到了谷歌地图,路径回放这个功能再百度地图和高德地图是有API直接可以使用的,奈何公司领导只让用谷歌地图,搜索发现网上并无多少相关文章,所以 ...

  10. HTML那个函数用于实现平移,巧妙使用 transform 实现环形路径平移动画

    原标题:巧妙使用 transform 实现环形路径平移动画 最近在<CSS Secrets>一书看到了这样一节:让一个元素沿环形路径平移.这是一个 css 动画的问题,但却没有看上去那么简 ...

最新文章

  1. 数据挖掘终篇!一文学习模型融合!从加权融合到stacking, boosting
  2. php两个按钮左右怎么做,css布局两个button在同父标签中左右两侧分布的方法
  3. 升级Firefox8后watir-webdriver出现错误“unable to obtain stable firefox connection in 60 seconds”...
  4. vue上传录音_vue用到H5+的录音功能 真机模拟的时候不能实现
  5. 项目中遇到难题一 : 多条件筛选(同一本小说具有多个特征)
  6. 分析容灾备份建设需求
  7. 乌版图 read-only file system
  8. [游戏服务器]第一章:多人聊天室-服务端
  9. c# 调用java webservice 参数获取不到_用C#.NET调用Java开发的WebService传递int,double问题,出现java无法获得值!...
  10. RCP之病人信息系统开发总结(4):MVC模式之View层—透视图
  11. 局域网电脑屏幕桌面监控怎么样
  12. 拯救我们的健康:戒烟应用大盘点
  13. AdapterVIew
  14. testbed与 c++test 的几点区别
  15. python实现聊天工具_python开发简单的聊天工具
  16. Python 数据分析微专业课程--项目实战09 房价影响因素挖掘1.项目说明2.项目具体要求3.实现思路:4.实现过程:5.结论:
  17. 物联网嵌入式开发平台和开发流程
  18. 强烈推荐收藏!3W 字Python 操作 Excel 报表自动化指南
  19. MySQL基础 - 连接查询
  20. hass智能 小米扫地机器人_Siri能控制小米扫地机器人吗_小米智能家居控制系统...

热门文章

  1. 17、MG90S舵机使用
  2. 淘系学妹分享阿里的20—60KJava岗位JD,真的太难了
  3. 2019java面试3年_Java回顾#3 – 2019年对于社区而言最重要的事情
  4. java机票实时比价系统计算机毕业设计MyBatis+系统+LW文档+源码+调试部署
  5. VUE项目打包后posy代理失效Nginx解决
  6. 用户互动功能,微信商城系统
  7. 【共享经济】披着共享经济外衣的租赁经济
  8. java excel导出 jxl_JAVA利用JXL导出/生成 EXCEL
  9. ckeditor 工具栏配置
  10. 【Nginx】第二十二节 redirect跟permanent区别