阅读更多

0顶
0踩

移动开发

转载新闻 你所不知道的 CSS 动画技巧与细节

2017-09-19 14:00 by 副主编 jihong10102006 评论(0) 有14709人浏览
css
怕标题起的有点大,下述技巧如果你已经掌握了看看就好,欢迎斧正,本文希望通过介绍一些 CSS 不太常用的技巧,辅以一些实践,让读者可以更加深入的理解掌握 CSS 动画。

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

正负旋转相消

嗯。名字起的很奇怪,好像数学概念一样。

在动画中,旋转是非常常用的属性,
{
  transform: rotate(90deg);
}

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


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

首先假设一下场景,我们有这样的一层 HTML 结构:
<div class="reverseRotate">
    <div class="rotate">
        <div class="content">正负旋转相消3D动画</div>
    </div>
</div>

样式如下:

.content 内是我们的主要内容,好了,现在想象一下,如果祖先元素 .rotate 进行正向 linear 360° 旋转,父级元素 .reverseRotate 进行反向 linear 360° 旋转,效果回是啥样?
.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 静止的非常重要。

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

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

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

为了和文案里面的 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);
    }
}

效果如下:

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>

样式如下:

我们给它们相同的动画,但是赋予不一样的缓动函数(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 效果就制作好了。(当然这个技巧比较简单,学会合理运用是关键)

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

奇妙的缓动

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

当你不想使用 CSS 默认提供的 linear、ease-in、ease-out 之类缓动函数的,可以自定义 cubic-bezier(1, 1, 0, 0),这里有个非常好用的工具推荐,下面这个网站,可以方便的调出你需要的缓动函数并且拿到对应的 cubic-bezier 。

cubic-bezier.com

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

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

使用这个技巧(也许算不上技巧,纯粹好玩),我们可以制作出一些有趣的效果,例如下面这个感觉是利用就 JS 才完成的动画,其实是纯 CSS 动画:

其实就小圆圈是元素默认是带有 transition 的,只有在 hover 上去的时候,取消它的过渡,简单的过程:
  • 由于一开始它的颜色的透明的,而 hover 的时候会赋予它颜色值,但是由于 hover 时过渡被取消了,所有它会直接显示。
  • hover 离开的时候,它的原本的过渡又回来了,这个时候它会从有颜色到透明值缓慢渐变消失。
可以戳这里感受一下:
CodePen Demo -- Cancle transition

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

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

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

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

简单来说,浏览器为了提升动画的性能,为了在动画的每一帧的过程中不必每次都重新绘制整个页面。在特定方式下可以触发生成一个合成层,合成层拥有单独的 GraphicsLayer。

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

那么一个元素什么时候会触发创建一个 Graphics Layer 层?从目前来说,满足以下任意情况便会创建层:
  • 硬件加速的 iframe 元素(比如 iframe 嵌入的页面中有合成层)
  • 硬件加速的插件,比如 flash 等等
  • 使用加速视频解码的 元素
  • 3D 或者 硬件加速的 2D Canvas 元素
  • 3D 或透视变换(perspective、transform) 的 CSS 属性
  • 对自己的 opacity 做 CSS 动画或使用一个动画变换的元素
  • 拥有加速 CSS 过滤器的元素
  • 元素有一个包含复合层的后代节点(换句话说,就是一个元素拥有一个子元素,该子元素在自己的层里)
  • 元素有一个 z-index 较低且包含一个复合层的兄弟元素
本题中说到的动画层级的控制,原因就在于上面生成层的最后一条:
元素有一个 z-index 较低且包含一个复合层的兄弟元素。

这里是存在坑的地方,首先我们要明确两点:
  • 我们希望我们的动画得到 GPU 硬件加速,所以我们会利用类似 transform: translate3d() 这样的方式生成一个 Graphics Layer 层。
  • 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 。

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

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

使用 Chrome,我们也可以观察到这种层级关系,可以看到 .list 的层级高于 .swiper:

所以,下面我们修改一下 CSS ,改成:
.swiper {
    position: relative;
    z-index: 100;
}
    
.list {
    position: relative;
}

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

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

此时,层级关系才是我们希望看到的,.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 实现,效果图如下:

CodePen Demo -- 3d Number Count
  • 大小: 47.1 KB
  • 大小: 16.3 KB
  • 大小: 5.4 KB
  • 大小: 41.1 KB
  • 大小: 981.2 KB
  • 大小: 621.2 KB
  • 大小: 600 Bytes
  • 大小: 116 KB
  • 大小: 1.5 MB
  • 大小: 69.7 KB
  • 大小: 76.2 KB
  • 大小: 36.5 KB
  • 大小: 14 KB
  • 大小: 32.5 KB
  • 大小: 1.7 MB
来自: github
0
0
评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • 浅析可复用性,可维护性的相关概念

    简单的介绍了一下软件构造中两个比较重要的外部属性:可维护性和可复用性,他们的一些概念。

  • 可维护性测试指南

    维护的主要定义是保持或维持特定状态的过程。软件的可维护性由开发人员负责,他们定期修改软件以满足不断变化的客户需求并解决客户提出的问题。软件维护需要增强软件的功能,以包含客户需要的新功能,修改代码以避免将来出现问题,修复代码中的缺陷或错误,并确保不存在安全漏洞。此外,软件维护通常包括发布更新,以提高适应性和有效性,并替换不受欢迎的功能。软件维护在很大程度上受到软件和代码质量的影响。质量较低的软件需要更多的维护。对于低质量软件,增加新需求或扩展现有代码的工作量和成本要高得多。

  • 可维护性的指标

    5.1 Metrics and Construction Principles for Maintainability 可维护性的度量与构造原则 1. 可维护性的指标 软件维护的类型:纠错性维护(25%)、适应性维护(21%)、完善性维护(50%)、预防性维护(4%) 可维护性(Maintainability)、可扩展性(Extensibility)、灵活性(Flexibility)、可适应性(Adaptability)、可管理性(Manageability)、支持性(Supportabil...

  • 软件的可维护性

    软件的可维护性 软件维护的四种类型 纠正性维护 : 这是改BUG 适应性维护 : 这是更换操作系统与数据库等外部环境时的修改 完善性维护 : 这是有新需求的修改 预防性维护 : 确定可以改进质量或者是预防未来出现的BUG的修改 1. 坚持简单的原则最有助于提高可维护性. 2. 可维护性不是项目开发完成后才去考虑的,而应该是在项目开发的一开始就加以考虑. 每个人的贡献都应当计算在内. 3.各个原则的影响不同 可维护性与编程语言无关,与行业无关,也不等价于BUG数量的多少. 可维护性表示高效,有效地进行

  • 可维护性原则

    好的软件总是需要可维护性,那么这究竟需要遵循哪些原则呢? 众所周知,一个好的软件需要有好的可维护性。但是我们构造的软件系统往往有 着许多问题,导致一个软件的可维护性较低的原因有四个: 1.过于僵硬(Rigidity):很难在系统中加入新功能。因为会波及其它模块,最后会变成跨越几个模块的大改动。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.过于脆弱(Fragility):与过于僵硬同时存在。对一个地方的修改,往往导致看上去没有什么关系...

  • 可维护性

    什么是可维护的代码 可维护的代码有以下特点: 1、可理解性——其他人可以接手代码并理解它的意图和一般途径,而无需开发人员的完全解释。 2、直观性——代码中的东西一眼就能明白,不管其操作过程多么复杂。 3、可适应性——代码以一种数据上的变化不要求完全重写的方法撰写。 4、可扩展性——在代码架构上已考虑到在未来允许对核心功能进行扩展。 5、可调试性——当有地方出错时,代码可以给予你...

  • 软件可维护性综述

    软件可维护性综述 1. 软件维护的目标,任务,分类与特点 软件维护的目标: 通过必要的维护工作使得系统持久的满足用户的需要。 各类维护活动的根本目的是:延长软件生存期 软件维护的分类: 1 )改正性维护;2 )适应性维护; 3 )完善性维护;4 )预防性维护。 改正性维护:是改正在系统开发阶段已发生而系统测试阶段尚未发现的错误。 任务:为了识别和纠正软件错误、改正软件性能上的缺陷、排除实施中的误...

  • 什么是“可维护性”?

    从InfoQ上面看到的一个讨论,国外的牛人在抱怨NHibernate 2.1的“可维护性”太差,改个东西要牵动全身。接着有人回应,说NHibernate 2.1其实很好维护。争论到最后,就变成了对“可维护性”的定义了,毕竟大家各执一词,可能只是因为标准不同。 原文的链接:[url]http://www.infoq.com/cn/news/2009/08/what-is-maintainabl...

  • 如何提高软件可维护性

    软件工程中把软件开发大概分了六步:可行性分析、需求分析、设计、编码、测试、运行与维护,在这几大部分中,维护占有重要地位,一般我们不想把大分分精力、财力花费在维护上,这就需要我们提高软件的可维护性。 一个好的程序应该是可理解的、可靠的、可测试...

  • 【软件质量】软件可维护性

    本文介绍软件的可维护性

  • 如何编写复用性、可读性和可维护性的代码

    - 平时我们在写HTML、CSS时会为类的命名耗费脑汁,本文总结了一下平时编码的心得CSS结构化组织思想 目的是讲用户界面划分为独立的块,即使使用复杂的UI,这也使界面开发变得简单快捷,并且允许重复使用现有的代码,而无需复制和粘贴。 CSS(块+元素+修饰符) 块所谓的“块”其实就是该DOM元素共有的最基本的特性,在其命名上我们可以采取按照其目的来取名(btn或者search-f

  • 代码质量之可维护性

      我的心态变化 第一次接触编程,学习C语言,交换两个数的值:  c = a  a = b  b = c  后来我我从师兄那学到了下面这段代码,觉得写的比我之前的更漂亮: a = a + b  b = a - b  a = a - b  最后参加工作了,看到很多别人的代码,最后又觉得最漂亮的代码是这样的:  c = a  a = b  b = c  请问大家,为什么我的...

  • 非功能测试第一篇------可靠性、可移植性、 易用性 (了解即可)

    可靠性 什么时候需要关注可靠性? 涉及人身安全财产安全的时候 医疗 金融 客户的信息 ,资源等 关注点 ? ...

  • 提高程序的可读性以及可维护性

    对于简单的一个for循环,如: for(int i =1; i { //proceeding } 从语法上来讲,上述语句完全没有问题。但是可读性及可扩展性差,为什么呢? 因为使用了100这个具体的值作为循环上届,其意义不明确,i与100比较究竟是什么意义,不知道,所以不方便他人理解你的程序 另一方面,如果程序中有多处这样的100,一旦程序将来发生更改(假设100要改为1000),那么

  • 软件构造——可维护性

    本文是对软件构造课程软件可维护性相关内容的整理与理解,使用的编程语言为 Java。

  • 程序可维护性

    一、概念 1.什么是软件维护 在软件发布后,修改软件以修正错误 和提升性能 维护不只是运维工程师的工作 软件维护不仅仅是运维工程师的工作,而是从设计和开发阶段就开始了 设计和开发者需要考虑软件未来的变化和扩展 设计方案的“easy to change” 这也就是我们说的软件构造的可维护性、可扩展性和灵活性。 面向可维护性的软件构造的例子 模块化、OO设计原则、OO设计模式、基于状态的构造技术、表驱动的构造技术、基于语法的构造技术 软件演化:对软件进行持续的更新 软件的大部分成本来自于维护阶段 软件生命周期中

  • 常用的可维护性度量标准

    文章目录前言一、圈复杂度1.定义2.计算方法3.计算示例二、可维护性指数三、模块耦合度总结 前言 常用的可维护性度量标准有: 圈复杂度: 度量代码的结构复杂度。 代码行数: 指示代码中的大致行数。 可维护性指数: 计算介于0和100之间的索引值,表示维护代码的相对容易性。 高价值意味着更好的可维护性。 继承的层次数: 表示扩展到类层次结构的根的类定义的数量。 等级越深,就越难理解特定方法和字段在何处被定义或重新定义。 类之间的耦合度: 通过参数,局部变量,返回类型,方法调用,泛型或模板实例化,基类,接口

Global site tag (gtag.js) - Google Analytics