你所不知道的 CSS 动画技巧与细节

怕标题起的有点大,下述技巧若是你已经掌握了看看就好,欢迎斧正,本文但愿经过介绍一些 CSS 不太经常使用的技巧,辅以一些实践,让读者能够更加深刻的理解掌握 CSS 动画。css

废话少说,直接进入正题,本文提到的动画不加特殊说明,皆指 CSS 动画。html

 

正负旋转相消

嗯。名字起的很奇怪,好像数学概念同样。image前端

(写完文章才发现这里应该叫正反旋转相消,图都截完了,你们内心清楚就好)git

在动画中,旋转是很是经常使用的属性,github

{
  transform: rotate(90deg);
}

那旋转有一些什么高级点的技巧呢?固然是能够改变 transfrom-origin ,改变旋转中心点啦。chrome

image

开个玩笑,改变旋转中心点这个估计你们都知道了,这里要介绍的技巧是利用父级元素正反两个方向的旋转,来制做一些酷炫的 3d 效果。浏览器

首先假设一下场景,咱们有这样的一层 HTML 结构:函数

<div class="reverseRotate">
    <div class="rotate">
        <div class="content">正负旋转相消3D动画</div>
    </div>
</div>

样式以下:工具

image

.content 内是咱们的主要内容,好了,如今想象一下,若是祖先元素 .rotate 进行正向 linear 360° 旋转,父级元素 .reverseRotate 进行反向 linear 360° 旋转,效果回是啥样?性能

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);
    }
}

神奇!由于一正一反的旋转,且缓动函数同样,因此整个 content 看上去依然是静止的!注意,这里整个 content 静止的很是重要。

有读者看到这里就要骂街了,做者你个智障,静止了不就没动画了吗?哪来的动画技巧?

image

别急!虽然看上去是静止的,可是其实祖先两个元素都是在旋转的!这会看上去风平浪静的效果底下实际上是暗流涌动。用开发者工具选取最外层祖先元素是这样的:

rotate

既然如此,咱们继续思考,若是我在其中旋转的一个祖先元素上,添加一些别的动画会是什么效果?想一想就很刺激啊。image

为了和文案里面的 3D 动画扯上关系,咱们先给这几个元素添加 3D 转换:

div {
    transform-style: preserve-3d;
    perspective: 500px;
}

接着,尝试修改上面的旋转动画,在内层旋转上额外添加一个 rotateX:

@keyframes rotate {
    0% {
        transform: rotateX(0deg) rotateZ(0deg);
    }
    50% {
        transform: rotateX(40deg) rotateZ(180deg);
    }
    100% {
        transform: rotateX(0deg) rotateZ(360deg);
    }
}

效果以下:

reverserotate

Wow,这里须要好好理解一下。因为内容 content 层是静止的但其实外层两个图层都在旋转,经过设置额外的 rotateX(40deg) ,至关于叠加多了一个动画,因为正反旋转抵消了,全部整个动画只能看到旋转的 rotateX(40deg) 这个动画,产生了上述的效果。

CodePen Demo -- Css正负旋转相消动画

 

动画相同,缓动不一样

好的,继续下一个小技巧。

有的时候咱们页面存在一些具备相同动画的元素,为了让动画不那么死板,咱们能够给相同的动画,赋予不一样的缓动函数,来达到动画效果。

假设咱们有以下的结构:

<div class="container">
    <div class="ball ball1"></div>
    <div class="ball ball2"></div>
    <div class="ball ball3"></div>
</div>

样式以下:

image

咱们给它们相同的动画,可是赋予不同的缓动函数(animation-timing-function),就像这样:

.ball1 {
    animation: move 1s ease-in infinite alternate;
}

.ball2 {
    animation: move 1s linear infinite alternate;
}

.ball3 {
    animation: move 1s ease-out infinite alternate;
}

@keyframes move {
    100% {
        transform: translateY(5vw);
    }
}

这样,一个简单的 loading 效果就制做好了。(固然这个技巧比较简单,学会合理运用是关键)

animationtimingf

CodePen Demo -- 动画相同,缓动不一样

奇妙的缓动

缓动函数 timing-function 在动画中占据了很是重要的地位。

当你不想使用 CSS 默认提供的 linearease-inease-out 之类缓动函数的,能够自定义 cubic-bezier(1, 1, 0, 0),这里有个很是好用的工具推荐,下面这个网站,能够方便的调出你须要的缓动函数而且拿到对应的 cubic-bezier 。

cubic-bezier.com

 

过渡取消

咱们在制做页面的时候,为了让页面更加有交互感,会给按钮,阴影,颜色等样式添加过渡效果,配合 hover 一块儿使用。

这个是常规思惟,若是咱们的元素一开始是没有过渡效果,只有 hover 上去才给它添加一个过渡,又或者一开始元素是有过渡效果的,当咱们 hover 上去时,取消它的过渡,会碰撞出什么样的火花呢?

使用这个技巧(也许算不上技巧,纯粹好玩),咱们能够制做出一些有趣的效果,例以下面这个感受是利用就 JS 才完成的动画,实际上是纯 CSS 动画:

transitionstop

其实就小圆圈是元素默认是带有 transition 的,只有在 hover 上去的时候,取消它的过渡,简单的过程:

  1. 因为一开始它的颜色的透明的,而 hover 的时候会赋予它颜色值,可是因为 hover 时过渡被取消了,全部它会直接显示。

  2. hover 离开的时候,它的本来的过渡又回来了,这个时候它会从有颜色到透明值缓慢渐变消失。

能够戳这里感觉一下:

CodePen Demo -- Cancle transition

 

动画层级的控制,保持动画层级在最上方

这个问题可能有一点难理解。须要了解 CSS 动画渲染优化的相关知识。

先说结论,动画层级的控制的意思是尽可能让须要进行 CSS 动画的元素的 z-index 保持在页面最上方,避免浏览器建立没必要要的图形层(GraphicsLayer),可以很好的提高渲染性能。

OK,再一次提到了图形层(GraphicsLayer),这是一个浏览器渲染原理相关的知识(WebKit/blink内核下)。

image

简单来讲,浏览器为了提高动画的性能,为了在动画的每一帧的过程当中没必要每次都从新绘制整个页面。在特定方式下能够触发生成一个合成层,合成层拥有单独的 GraphicsLayer。

须要进行动画的元素包含在这个合成层之下,这样动画的每一帧只须要去从新绘制这个 Graphics Layer 便可,从而达到提高动画性能的目的。

那么一个元素何时会触发建立一个 Graphics Layer 层?从目前来讲,知足如下任意状况便会建立层:

  • 硬件加速的 iframe 元素(好比 iframe 嵌入的页面中有合成层)
  • 硬件加速的插件,好比 flash 等等
  • 使用加速视频解码的 元素
  • 3D 或者 硬件加速的 2D Canvas 元素
  • 3D 或透视变换(perspective、transform) 的 CSS 属性
  • 对本身的 opacity 作 CSS 动画或使用一个动画变换的元素
  • 拥有加速 CSS 过滤器的元素
  • 元素有一个包含复合层的后代节点(换句话说,就是一个元素拥有一个子元素,该子元素在本身的层里)
  • 元素有一个 z-index 较低且包含一个复合层的兄弟元素

本题中说到的动画层级的控制,缘由就在于上面生成层的最后一条:

元素有一个 z-index 较低且包含一个复合层的兄弟元素。

这里是存在坑的地方,首先咱们要明确两点:

  1. 咱们但愿咱们的动画获得 GPU 硬件加速,因此咱们会利用相似 transform: translate3d() 这样的方式生成一个 Graphics Layer 层。
  2. Graphics Layer 虽好,但不是越多越好,每一帧的渲染内核都会去遍历计算当前全部的 Graphics Layer ,并计算他们下一帧的重绘区域,因此过量的 Graphics Layer 计算也会给渲染形成性能影响。

记住这两点以后,回到上面咱们说的坑。

假设咱们有一个轮播图,有一个 ul 列表,结构以下:

<div class="container">
    <div class="swiper">轮播图</div>
    <ul class="list">
        <li>列表li</li>
        <li>列表li</li>
        <li>列表li</li>
        <li>列表li</li>
    </ul>
</div>

假设给他们定义以下 CSS:

.swiper {
    position: static;
    animation: 10s move infinite;
}
    
.list {
    position: relative;
}

@keyframes move {
    100% {
        transform: translate3d(10px, 0, 0);
    }
}

因为给 .swiper 添加了 translate3d(10px, 0, 0) 动画,因此它会生成一个 Graphics Layer,以下图所示,用开发者工具能够打开层的展现,图形外的黄色边框即表明生成了一个独立的复合层,拥有独立的 Graphics Layer 。

image

可是!在上面的图中,咱们并无给下面的 list 也添加任何能触发生成 Graphics Layer 的属性,可是它也一样也有黄色的边框,生成了一个独立的复合层。

缘由在于上面那条元素有一个 z-index 较低且包含一个复合层的兄弟元素。咱们并不但愿 list 元素也生成 Graphics Layer ,可是因为 CSS 层级定义缘由,下面的 list 的层级高于上面的 swiper,因此它被动的也生成了一个 Graphics Layer 。

使用 Chrome,咱们也能够观察到这种层级关系,能够看到 .list 的层级高于 .swiper

image

因此,下面咱们修改一下 CSS ,改为:

.swiper {
    position: relative;
    z-index: 100;
}
    
.list {
    position: relative;
}

这里,咱们明确使得 .swiper 的层级高于 .list ,再打开开发者工具观察一下:

image

能够看到,这一次,.list 元素已经没有了黄色外边框,说明此时没有生成 Graphics Layer 。再看看层级图:

image

此时,层级关系才是咱们但愿看到的,.list 元素没有触发生成 Graphics Layer 。而咱们但愿须要硬件加速的 .swiper 保持在最上方,每次动画过程当中只会独立重绘这部分的区域。

总结

这个坑最先见于张云龙发布的这篇文章CSS3硬件加速也有坑,这里还要总结补充的是:

  • GPU 硬件加速也会有坑,当咱们但愿使用利用相似 transform: translate3d() 这样的方式开启 GPU 硬件加速,必定要注意元素层级的关系,尽可能保持让须要进行 CSS 动画的元素的 z-index 保持在页面最上方。

  • Graphics Layer 不是越多越好,每一帧的渲染内核都会去遍历计算当前全部的 Graphics Layer ,并计算他们下一帧的重绘区域,因此过量的 Graphics Layer 计算也会给渲染形成性能影响。

  • 可使用 Chrome ,用上面介绍的两个工具对本身的页面生成的 Graphics Layer 和元素层级进行观察而后进行相应修改。

  • 上面观察页面层级的 chrome 工具很是吃内存?好像仍是一个处于实验室的功能,分析稍微大一点的页面容易直接卡死,因此要多学会使用第一种观察黄色边框的方式查看页面生成的 Graphics Layer 这种方式。

 

数字动画

不少技巧单独拿出来可能都显得比较单薄,我以为最重要的是平时多积累,学会融会贯通,在实际项目中灵活组合运用,最近项目须要一个比较富有科技感的数字计数器,展现在线人数的不断增长。由于是内部需求,没有设计稿,靠前端自由发挥。

运用了上面提到的一些小技巧,参考了一些 CodePen 上的效果,整了个下述的 3D 数字计数效果,纯 CSS 实现,效果图以下:

numbercount

CodePen Demo -- 3d Number Count

这个例子主要是想告诉你们,不少小的细节小的技巧合在一块儿,是能够做出很是酷炫的动画的。

 

最后

还有一些技巧,感受本文的信息量已经够大了,因此可能会出个下篇。

系列 CSS 文章汇总在个人 Github ,持续更新,欢迎点个 star 订阅收藏。

好了,本文到此结束,但愿对你有帮助 :)

若是还有什么疑问或者建议,能够多多交流,原创文章,文笔有限,才疏学浅,文中如有不正之处,万望告知。

相关文章
相关标签/搜索