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,实现如下所示的动画效果:
上面的动画效果,非常有意思,核心有两点:
嗯?很有意思的效果。看上去,我们好像使用 CSS 实现了碰撞检测。
然而,实际情况真的是这样吗?让我们一起一探究竟!
这里其实我们并没有实现碰撞检测,因为小球和小球之间接触时,并没有发生碰撞效果。
我们只实现了,小球与边界之间的碰撞反应。不过这里,也并非碰撞检测,我们只需要设置好单个方向的运动动画,并且设置 animation-direction: alternate; 即可!
animation-direction: alternate;
下面,我们一起来实现单个方向上的运动动画:
<div></div>
div { position: absolute; top: 0; left: 0; width: 100px; height: 100px; border-radius: 50%; background: #0cf; animation: horizontal 3s infinite linear alternate; } @keyframes horizontal { from { left: 0; } to { left: calc(100vw - 100px); } }
简单解读一下:
position: absolute
left
div
left: calc(100vw - 100px)
100px
alternate
这样,我们就巧妙的实现了,在视觉上,小球元素移动到最右侧边界时,回弹的效果:
好,有了上面的铺垫,我们只需要再如法炮制 Y 轴方向的运动即可。
利用元素的 top 进行 Y 轴方向的运动:
top
div { position: absolute; top: 0; left: 0; width: 100px; height: 100px; border-radius: 50%; background: #0cf; animation: horizontal 3s infinite linear alternate, vertical 3s infinite linear alternate; } @keyframes horizontal { from { left: 0; } to { left: calc(100vw - 100px); } } @keyframes vertical { from { top: 0; } to { top: calc(100vh - 100px); } }
我们增加了一个 vertical 3s infinite linear alternate Y 轴的运动动画,实现小球从 top: 0 到 top: calc(100vh - 100px); 的运动。
vertical 3s infinite linear alternate
top: 0
top: calc(100vh - 100px);
这样,我们就成功的得到了 X、Y 两个方向上的小球运动,它们叠加在一起的效果如下:
颜色的变化可以忽略,GIF 录制问题。
当然,此时的问题在于,缺少了随机性,小球的始终在左上和右下角之间来回运动。
为了解决这个问题,我们需要添加一定的随机性,这个问题也要解决,我们只需要让两个方向上运动时间不一致即可。
我们修改一下代码,让 X、Y 轴的运动时长不一致即可:
div { position: absolute; // ... animation: horizontal 2.6s infinite linear alternate, vertical 1.9s infinite linear alternate; }
如此一来,整体的效果就好上了不少,由于整个动画是无限反复进行的,随着时间的推进,整个动画呈现出来的就是无序、随机的运动:
当然,上面的效果基本上没有什么太大的问题了,但是代码层面不够优雅,主要有两点问题:
transform
100px x 100px
上述两个问题,使用 transform: translate() 都可以解决,但是我们为什么一开始不用 transform 呢?
transform: translate()
我们来尝试一下,使用 transform 替代 top、left:
div { position: absolute; top: 0; left: 0; width: 100px; height: 100px; border-radius: 50%; background: #0cf; animation: horizontal 2.6s infinite linear alternate, vertical 1.9s infinite linear alternate; } @keyframes horizontal { from { transform: translateX(0); } to { transform: translateX(calc(100vw - 100%)); } } @keyframes vertical { from { transform: translateY(0); } to { transform: translateY(calc(100vh - 100%)); } }
上述代码中,我们使用了 transform 替代 top、left 运动。并且,将动画代码中的 100px 替换成了 100%,这一点的好处是,在 transform: translate 中,100% 表示的是元素本身的高宽,这样,当我们改变元素本身的大小时,就无需再改变 @keyframes 中的代码,通用性更强。
100%
transform: translate
@keyframes
我们来看看修改后的效果:
有点问题!预想中的效果并没有出现,整个动画只有 Y 轴方向上的动画效果。
这是什么原因呢?
其本质在于,定义的 vertical 1.9s infinite linear alternate 的垂直方向的动画效果覆盖了在其之前定义的 transform: translateX(calc(100vw - 100%)) 动画效果。
vertical 1.9s infinite linear alternate
transform: translateX(calc(100vw - 100%))
说人话就是 X、Y 轴的动画都使用了 transform 属性,两者之间造成了冲突。
在之前,这种情况基本是无解的,常见的解决方案就是:
不过,到今天,这个问题有了更好的解法!也就是 CSS animation 家族中的新属性 —— animation-composition。
animation-composition
这是一个非常新的属性,表示动画合成属性,从 Chrome 112 版本开始支持。
有三种不同的取值:
{ animation-composition: replace; // 表示动画值替换 animation-composition: add; // 表示动画值追加 animation-composition: accumulate; // 表示动画值累加 }
本文不会详细介绍 animation-composition,感兴趣的可以看看 MDN 的属性介绍或者 XBOXYAN 大佬的这篇文章 -- 了解一下全新的CSS动画合成属性animation-composition
这里,基于上面的代码,我们只需要再多设置一个 animation-composition: accumulate 即可解决问题:
animation-composition: accumulate
div { animation: horizontal 2.6s infinite linear alternate, vertical 1.9s infinite linear alternate; animation-composition: accumulate; }
此时,我们就能通过一个元素,利用 transform 得到 X、Y 两个方向位移动画的合成效果,也就是我们想要的效果:
解决了位移动画的问题,我们就只剩下最后一个问题了,如何在碰撞的瞬间,实现颜色的切换?
这里也非常好解决,由于我们是知道每一轮 X、Y 方向上的动画时长的,那我们只需要在每次这个结点上,切换一次颜色即可。
并且,由于颜色不是过渡变换,而是直接的跳变,所以,我们需要用到 animation 中的 animation-timing-function: steps(),也就是步骤缓动函数。
animation-timing-function: steps()
对 animation-timing-function: steps() 还不太了解的,可能需要先补一补基础,可以看看这一篇文章:深入浅出 CSS 动画
举个例子,假设 X 方向上,单次的动画时长为 3s,那我们可以设置一个 steps(10) 的颜色动画,总时长为 30s,这样,每隔 3s 就会触发一次 steps() 步骤动画,颜色的变化就能够和小球与边界的碰撞动画发生在同一时刻。
steps(10)
steps()
那如何快速实现颜色的变化呢?利用 filter: hue-rotate() 即可快速实现颜色的变化。
filter: hue-rotate()
理解一下下面的代码:
<div class="normal"></div> <div class="steps"></div>
div { width: 200px; height: 200px; background: #fc0; } .normal { animation: colorChange 10s linear infinite; } .steps { animation: colorChange 10s steps(5) infinite; } @keyframes colorChange { 100% { filter: hue-rotate(360deg); } }
这里,我们用 filter: hue-rotate(360deg) 的改变,实现颜色的变化,观察下面的动图,理解 steps(5) 的作用。
filter: hue-rotate(360deg)
steps(5)
animation: colorChange 10s linear infinite
animation: colorChange 10s steps(5) infinite
效果如下:
理解了这一步,我们就可以把颜色的变化,也一起叠加到上述的小球变化中:
div { animation: horizontal 2.6s infinite linear alternate, vertical 2s infinite linear alternate, colorX 26s infinite steps(10), colorY 14s infinite steps(7); animation-composition: accumulate; } @keyframes horizontal { from { transform: translateX(0); } to { transform: translateX(calc(100vw - 100%)); } } @keyframes vertical { from { transform: translateY(0); } to { transform: translateY(calc(100vh - 100%)); } } @keyframes colorX { to { filter: hue-rotate(360deg); } } @keyframes colorY { to { filter: hue-rotate(360deg); } }
这样,我们就成功的得到了题图中的效果:
完整的代码,你可以戳这里:Random Circle Path
OK,上面,我们就把整个效果的完整原理剖析了一遍。
掌握了整个原理之后,我们就可以把这个效果应用于不同场景中。
譬如,假设我们有这么一张图片:
基于上面的效果,稍加改造,我们就可以得到类似的如下效果:
div { width: 220px; height: 97px; background: linear-gradient(#f00, #f00), url(https://s1.ax1x.com/2023/08/15/pPQm9oT.jpg); background-blend-mode: lighten; background-size: contain; animation: horizontal 3.7s infinite -1.4s linear alternate, vertical 4.1s infinite -2.1s linear alternate, colorX 37s infinite -1.4s steps(10), colorY 28.7s infinite -2.1s steps(7); animation-composition: accumulate; } @keyframes horizontal { from { transform: translateX(0); } to { transform: translateX(calc(100vw - 100%)); } } @keyframes vertical { from { transform: translateY(0); } to { transform: translateY(calc(100vh - 100%)); } } @keyframes colorX { to { filter: hue-rotate(2185deg); } } @keyframes colorY { to { filter: hue-rotate(1769deg); } }
上面的 DEMO 是基于元素背景色的,本 DEMO 是基于图片的,因此这里多了一步,利用 mix-blend-mode,实现了图片颜色的变化。
mix-blend-mode
完整的代码,你可以戳这里:CodePen Demo -- Random DVD Path
OK,我们再进一步,基于上面的效果,我们可以实现各种有趣的粒子效果,如果同时让页面存在 1000 个粒子呢?
下面是我使用 CSS-Doodle 实现的纯 CSS 的粒子效果,其核心原理与上面的保持一致,只是添加了更多的随机性:
Amazing!是不是非常有趣,整个效果的代码基于 CSS-doodle 的语法,不超过 40 行。完整的代码,你可以戳这里:CSS Doodle - CSS Particles Animation
总结一下,本文介绍了如何巧妙的利用 CSS 中的各种高阶技巧,组合实现类似于碰撞场景的动画效果。创建出了非常有趣的 CSS 动画,期间各种技巧的组合运用,值得好好琢磨学习。
OK,本文到此结束,希望本文对你有所帮助 :)
想 Get 到最有意思的 CSS 资讯,千万不要错过我的公众号 -- iCSS前端趣闻 😄
更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。
如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。
The text was updated successfully, but these errors were encountered:
牛逼!
Sorry, something went wrong.
牛
牛哇👏
No branches or pull requests
本文,我们将一起学习,使用纯 CSS,实现如下所示的动画效果:
上面的动画效果,非常有意思,核心有两点:
嗯?很有意思的效果。看上去,我们好像使用 CSS 实现了碰撞检测。
然而,实际情况真的是这样吗?让我们一起一探究竟!
实现 X 轴方向的运动
这里其实我们并没有实现碰撞检测,因为小球和小球之间接触时,并没有发生碰撞效果。
我们只实现了,小球与边界之间的碰撞反应。不过这里,也并非碰撞检测,我们只需要设置好单个方向的运动动画,并且设置
animation-direction: alternate;
即可!下面,我们一起来实现单个方向上的运动动画:
简单解读一下:
position: absolute
绝对定位,利用left
进行 X 轴方向的运动div
运动的距离为left: calc(100vw - 100px)
,元素本身的高宽都是100px
,因此相当于运动到屏幕的最右侧alternate
也就是animation-direction: alternate;
的简写,表示动画在每个循环中正反交替播放这样,我们就巧妙的实现了,在视觉上,小球元素移动到最右侧边界时,回弹的效果:
如法炮制 Y 轴方向的运动
好,有了上面的铺垫,我们只需要再如法炮制 Y 轴方向的运动即可。
利用元素的
top
进行 Y 轴方向的运动:我们增加了一个
vertical 3s infinite linear alternate
Y 轴的运动动画,实现小球从top: 0
到top: calc(100vh - 100px);
的运动。这样,我们就成功的得到了 X、Y 两个方向上的小球运动,它们叠加在一起的效果如下:
当然,此时的问题在于,缺少了随机性,小球的始终在左上和右下角之间来回运动。
为了解决这个问题,我们需要添加一定的随机性,这个问题也要解决,我们只需要让两个方向上运动时间不一致即可。
我们修改一下代码,让 X、Y 轴的运动时长不一致即可:
如此一来,整体的效果就好上了不少,由于整个动画是无限反复进行的,随着时间的推进,整个动画呈现出来的就是无序、随机的运动:
使用 transform 替代 top、left
当然,上面的效果基本上没有什么太大的问题了,但是代码层面不够优雅,主要有两点问题:
top
和left
,性能相对较差,需要使用transform
进行替代100px
,由于 DEMO 中小球的大小是100px x 100px
,并且在动画的代码中也使用了100px
这个值进行了运动终态的计算,因此如果想修改小球的元素大小,需要改动地方较多上述两个问题,使用
transform: translate()
都可以解决,但是我们为什么一开始不用transform
呢?我们来尝试一下,使用 transform 替代 top、left:
上述代码中,我们使用了 transform 替代 top、left 运动。并且,将动画代码中的
100px
替换成了100%
,这一点的好处是,在transform: translate
中,100%
表示的是元素本身的高宽,这样,当我们改变元素本身的大小时,就无需再改变@keyframes
中的代码,通用性更强。我们来看看修改后的效果:
有点问题!预想中的效果并没有出现,整个动画只有 Y 轴方向上的动画效果。
这是什么原因呢?
其本质在于,定义的
vertical 1.9s infinite linear alternate
的垂直方向的动画效果覆盖了在其之前定义的transform: translateX(calc(100vw - 100%))
动画效果。说人话就是 X、Y 轴的动画都使用了
transform
属性,两者之间造成了冲突。使用 animation-composition 进行动画合成
在之前,这种情况基本是无解的,常见的解决方案就是:
top
、left
替代 transform不过,到今天,这个问题有了更好的解法!也就是 CSS animation 家族中的新属性 ——
animation-composition
。这是一个非常新的属性,表示动画合成属性,从 Chrome 112 版本开始支持。
有三种不同的取值:
本文不会详细介绍
animation-composition
,感兴趣的可以看看 MDN 的属性介绍或者 XBOXYAN 大佬的这篇文章 -- 了解一下全新的CSS动画合成属性animation-composition这里,基于上面的代码,我们只需要再多设置一个
animation-composition: accumulate
即可解决问题:此时,我们就能通过一个元素,利用 transform 得到 X、Y 两个方向位移动画的合成效果,也就是我们想要的效果:
使用 steps 实现颜色切换
解决了位移动画的问题,我们就只剩下最后一个问题了,如何在碰撞的瞬间,实现颜色的切换?
这里也非常好解决,由于我们是知道每一轮 X、Y 方向上的动画时长的,那我们只需要在每次这个结点上,切换一次颜色即可。
并且,由于颜色不是过渡变换,而是直接的跳变,所以,我们需要用到 animation 中的
animation-timing-function: steps()
,也就是步骤缓动函数。举个例子,假设 X 方向上,单次的动画时长为 3s,那我们可以设置一个
steps(10)
的颜色动画,总时长为 30s,这样,每隔 3s 就会触发一次steps()
步骤动画,颜色的变化就能够和小球与边界的碰撞动画发生在同一时刻。那如何快速实现颜色的变化呢?利用
filter: hue-rotate()
即可快速实现颜色的变化。理解一下下面的代码:
这里,我们用
filter: hue-rotate(360deg)
的改变,实现颜色的变化,观察下面的动图,理解steps(5)
的作用。animation: colorChange 10s linear infinite
表示背景动画的过渡变化animation: colorChange 10s steps(5) infinite
,这里表示 10s 的动画分成 5 步,每两秒,会触发一次动画:效果如下:
理解了这一步,我们就可以把颜色的变化,也一起叠加到上述的小球变化中:
这样,我们就成功的得到了题图中的效果:
完整的代码,你可以戳这里:Random Circle Path
应用于图片效果、应用与多粒子效果
OK,上面,我们就把整个效果的完整原理剖析了一遍。
掌握了整个原理之后,我们就可以把这个效果应用于不同场景中。
譬如,假设我们有这么一张图片:
基于上面的效果,稍加改造,我们就可以得到类似的如下效果:
效果如下:
上面的 DEMO 是基于元素背景色的,本 DEMO 是基于图片的,因此这里多了一步,利用
mix-blend-mode
,实现了图片颜色的变化。完整的代码,你可以戳这里:CodePen Demo -- Random DVD Path
实现多粒子碰撞
OK,我们再进一步,基于上面的效果,我们可以实现各种有趣的粒子效果,如果同时让页面存在 1000 个粒子呢?
下面是我使用 CSS-Doodle 实现的纯 CSS 的粒子效果,其核心原理与上面的保持一致,只是添加了更多的随机性:
Amazing!是不是非常有趣,整个效果的代码基于 CSS-doodle 的语法,不超过 40 行。完整的代码,你可以戳这里:CSS Doodle - CSS Particles Animation
最后
总结一下,本文介绍了如何巧妙的利用 CSS 中的各种高阶技巧,组合实现类似于碰撞场景的动画效果。创建出了非常有趣的 CSS 动画,期间各种技巧的组合运用,值得好好琢磨学习。
OK,本文到此结束,希望本文对你有所帮助 :)
想 Get 到最有意思的 CSS 资讯,千万不要错过我的公众号 -- iCSS前端趣闻 😄
更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。
如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。
The text was updated successfully, but these errors were encountered: