18326051278

O2O解决方案>>

社区物业O2O
连锁电商O2O
上门维修O2O
农村电商O2O
多用户商城

行业平台类

汽车服务平台
家居服务平台
综合电商平台
家政服务平台
多门店商城系统

网站解决方案

全能型企业站
营销型网站
高端定制网站
品牌设计站
HTML5网站

APP解决方案

生鲜APP开发
物流APP开发
家居服务APP
汽车金融APP
多用户商城APP

定制开发类

APP开发
微信开发
小程序开发
网站建设
平台合作
返回列表
安徽毅耘科技有限公司,安徽app开发,合肥APP开发,经验分享多屏复杂动画CSS技巧三则
2017-09-29毅耘科技1895

经验分享多屏复杂动画CSS技巧三则

【毅耘科技】

经验分享多屏复杂动画CSS技巧三则

当下CSS3应用已经相当广泛,其中主要成员之一就是CSS3动画。并且,随着CSS动画的逐渐深入与普及,更复杂与细腻的动画场景也如雨后春笋般破土而出。例如上个月做的「企业QQ-新年祝福」运动:

感谢shirley协助录制上面的视频,虽然视频内容是手机上的显示效果,但是,这个“企业新年祝福运动”原本只针对桌面端,移动端是后来辅助增强(增添了相当于运动页面UV 5.7%的点击)。而目前大多数类似页面只针对移动端,例如其他同事实现的QQ空间5.0预约页第二版:

经验分享多屏复杂动画CSS技巧三则

扫码(需登录)或者链接二选一:

经验分享多屏复杂动画CSS技巧三则

访问demo戳这里

因此,需要多一点适配的技巧。但是,对于动画效果实现,其实都是一脉相承的,最终的实现需要许多点滴积累,我这里讲三个部分同窗可能不知道的相关CSS技巧。

注:示例代码的私有前缀均省略,大家自行脑补

技巧一、使用animation-play-state控制每屏动画播放

1. 类名active与动画触发
首先,使用active触发每一屏的动画,几乎已经约定俗成,应该也建议成为默认的行业规范。

一般做法是,当对应一屏内容进入的时候,使用JS给容器添加类名active:

container.classList.add("active");

假如你做的动画逼格较高,希望每次浏览这一屏内容的时候,动画都走一遍,可以使用reflow重新触发一下animation:

container.classList.remove("active");
container.offsetWidth = container.offsetWidth;
container.classList.add("active");

2. 类名active与动画控制技巧
如何具体控制动画的播放呢?我们通常第一反应是使用下面的方法实现,动画的完整CSS代码在active状况下呈现,如:

.element1 { /* 尺寸与定位 */ }
.element2 { /* 尺寸与定位 */ }
.element3 { /* 尺寸与定位 */ }
...

.active .element1 { animate: name1 1s; }
.active .element2 { animate: name2 1s; }
.active .element3 { animate: name2 1s; }
...

从实现和功能上将,上面方法是很不错的,通俗易懂,不易犯错。不过我小我更喜好使用配合CSS3的animation-play-state属性对每屏动画进行控制,实现如下:

  1. 动画相关CSS代码直接写在元素上:
    .element1 { /* 尺寸与定位 */ animate: name1 1s; }
    .element2 { /* 尺寸与定位 */ animate: name2 1s; }
    .element3 { /* 尺寸与定位 */ animate: name3 1s; }
    ...
  2. 创建一个类名,如.animate,凡是使用到了animation动画的元素都添加这个类名;
  3. 如下CSS代码:
    .animate {
        animation-play-state: paused;
    }
    .active .animate {
        animation-play-state: running;
    }

之所以小我更喜好后面的方法,是因为有一种“无侵入”的感觉,代码条理清晰,控制关系明确。有利于后期的维护与扩展。

然而,使用animation-play-state照旧有些需要注重的,对于IE10/IE11浏览器,animation-play-state是不能简写的。如:

.element { animate: shake 4s 2s both infinite paused; }

只会让整个CSS声明挂掉的!如下写法支撑:

.element {
    animate: shake 4s 2s both infinite;
    animation-play-state: paused;
}

有人可能要新鲜了,怎么倏忽IE浏览器乱入了??经验分享多屏复杂动画CSS技巧三则

首先,我们不能无视主流手机之Windows Phone. 其次,帅气的翻屏动画并不是移动端专有,桌面端也适用。稍稍用力,桌面移动全适配,何乐而不为!

技巧二、不同状况下的延续动画

有时候,动画可能不是一波流,分状况。

例如,我们的小火箭,先是淡出动画,然后无限上下悬浮。怎么实现呢?

经验分享多屏复杂动画CSS技巧三则

关键点就是动画分解与延时。

据我所知,没办法只使用一个keyframes关键帧声明就实现这个效果,因为,这里有动画状况的转变:一个只执行一次的动画和一个无限循环动画。

怎么办?我们可以将动画分解,写2个animation?keyframes动画关键帧描述。

@keyframes fadeIn { /* ... */ }
@keyframes float { /* ... */ }

然后,再分别应用这些关键帧动画。如何应用呢?有2个小技巧:

1. 逗号与多animation动画值
如下:

小火箭
.element { animation: fadeIn 1s, float .5s 1s infinite; } /* 我淡出, 需要1秒;我1秒后开始无限漂浮 */

其中float .5s 1s infinite这里的1s就是无限漂浮动画执行延迟的时间,于是,两个动画完美配合,感觉就像是一个动画。现实上,就是一个动画,所有CSS3 animation动画走统一个UI线程,这也是为何推荐使用CSS实现动画效果的原因。

此写法没有兼容性问题,大家可以开开心心地使用。

2. 标签嵌套与自力动画
我们还可以通过嵌套标签的形式实现延续动画,例如:

小火箭
.element-wrap { animation: fadeIn 1s; } /* 我淡出, 需要1秒 */ .element { animation: float .5s 1s infinite; } /* 我1秒后开始无限漂浮 */

有人可能会新鲜了。animation自己就支撑多动画并行,你还搞个标签嵌套,没有任何使用的理由啊!没错,单纯看我们这个例子,确实是这样。但是:

① 提取公用动画
这类多屏动画是有N多元素同时执行不同的动画。比方说,火箭是淡出,然后上下漂浮;火箭的火焰是淡出,然后大小转变;黑洞是淡出,然后左右随波。你如何实现?

假如纯粹借助animation语法,应该是:

.element1 { animation: fadeIn 1s, float .5s 1s infinite; }  /* 我淡出, 需要1秒;我1秒后开始无限漂浮 */
.element2 { animation: fadeIn 1s, size .5s 1s infinite; }   /* 我淡出, 需要1秒;我1秒后开始大小转变 */
.element3 { animation: fadeIn 1s, move .5s 1s infinite; }   /* 我淡出, 需要1秒;我1秒后开始左右移动 */

可以看到,淡出是公用的动画效果,我们可以借助嵌套标签,实现公用语法的合并,方面后期维护:

.element-wrap { animation: fadeIn 1s; }          /* 大家都1秒淡出 */
.element1 { animation: float .5s 1s infinite; }  /* 我1秒后无限漂浮 */
.element2 { animation: size .5s 1s infinite; }   /* 我1秒后忽大忽小 */
.element3 { animation: move .5s 1s infinite; }   /* 我1秒后左右移动 */

②避免变换冲突
有个元素动画是边360度旋转、边放大(从0放大到100%),像这种具有典型特征的动画我们显然要自力提取与公用的:

@keyframes spin { /* transform: rotate... */ }
@keyframes zoomIn { /* transform: scale... */ }

好了,现在问题来了,变放大边旋转:

.element { animation: spin 1s, zoomIn 1s; }  /* 旋转:啊,完蛋啦,我被放大覆盖啦! */

因为都是使用transform, 发生了残忍的覆盖。当然,有好事的人会说,你使用zoom不就好了!确实,假如只是移动端,使用zoom确实棒棒哒!但是,我们这个企业运动,PC是主战场,因此,FireFox浏览器(FF不识zoom)是不能无视的。

怎么办?重新建一个名为spinZoomIn的动画关键帧描述照旧?

对啊,你直接外面套一层标签不就万事大吉了?经验分享多屏复杂动画CSS技巧三则

.element-wrap { animation: spin 1s; }   /* 我转转转 */
.element { animation: zoomIn 1s; }      /* 我大大大 */

技巧三、无侵入定位和居中定位准则

1.?这里的“无侵入定位”指不受animation影响的元素定位,包含两部分:一是不使用keyframes关键帧决定初始位置;二是不要使用keyframes中出现的属性定位。

①. 不使用keyframes决定初始位置
应该都知道,CSS3?animationfill-mode可以决定元素动画结束前后的位置,也就是也具有定位的作用。此时,可能就会有小伙伴,故作聪明,行使animation?keyframes0% {}form {}去做定位,貌似,还省了写代码。看上去很赞,现实上狭隘了,这对于对animation支撑不佳或不支撑的浏览器现实上是不友爱的,例如Android2.3不支撑animation-fill-mode, IE6-IE9不支撑CSS3?animation,于是乎,当遭遇这些浏览器的时候,页面动画元素的布局现实上是毁掉的。所以,这些动画元素定位的时候,需要使用“无侵入定位”,也就是,就算页面没有animation, 我也是个“标致人儿”。

②. 不使用keyframes中出现的属性定位
举个例子,有个球,正好定位在模块的中间,同时有个无限旋转效果。使用transform: translate(-50%,-50%)居中定位再合适不过了,不用我心里难受,于是,使用了transform定位。此时,冲突发生,旋转动画也是需要transform变换的。

@keyframes spin {
    0% { transform: rotate(0); }
    100% { transform: rotate(360deg); }
}

要么使用业界约定俗成spin覆盖,要么另起炉灶没法重用:

@keyframes spin-trans {
    0% { transform: rotate(0) translate(-50%,-50%); }
    100% { transform: rotate(360deg) translate(-50%,-50%); }
}

显然,都是不合适的。建议使用传统left/top/margin进行定位,与transform变换动画“无侵入”。

2.?这里的“居中定位准则”包含两部分:一是元素定位在容器中心位置;二是元素的定位体例为居中定位。

①. 元素定位在容器中心
容器以及容器内的动画元素可以看成是一个动画模块,为了这个模块可以轻松驾驭水平布局和垂直局部,里面的动画元素形成的整体一定要在容器的中心,不要被设计稿或周围环境影响。

举个简单例子,本文一开始展示的「企业QQ-新年祝福」运动。

企业产品用户特点比较鲜明:一是访问主要集中在桌面端,二是有70~80%用户使用的是webkit/blink内核浏览器。所以,大家可以理解为何设计稿明明针对桌面端,却有如此多细腻的动画设计了。

故事是这样的,桌面版做好了,1024-1224自适应,IE7以上都兼容(无侵入定位准则)(除了没动画),好棒经验分享多屏复杂动画CSS技巧三则!此时负责视觉的晓玲同窗希望也能适配移动端,可以增添一定的传播,我觉得挺好的,于是,决定通过技术手段,让运动页面能游走于桌面和移动之间,同时,保证各种动画效果棒棒哒!

 

效果,发现自己留了一个坑,拿第2屏举例,桌面版,长这样,右侧动画内容并不是完全居中的:

经验分享多屏复杂动画CSS技巧三则

本着高度还原设计稿的原则,所有动画元素都经过测量定位,按照PSD中的参考线左上角(left/top),效果整体左侧冒出60像素:

经验分享多屏复杂动画CSS技巧三则

于是,问题来了,当移动端做响应式适配时候,因为容器内的动画元素不是居中的,所以——经验分享多屏复杂动画CSS技巧三则

经验分享多屏复杂动画CSS技巧三则

后来,进行了修改,内部动画元素整体居中,外部容器桌面端做左侧60像素偏移,于是,适配移动端时候,就正好是居中的啦。

经验分享多屏复杂动画CSS技巧三则

②. 定位体例为居中定位
所谓“居中定位”是相对“传统定位”而言的。Web页面中的模块、文字什么的默认都是相对于左上角堆砌的,所以,很天然地,我们在重构页面,做布局,写交互效果的时候,也都是相对左上角定位。活用元素自己的定位特征,这是很赞的也推荐这么做!但是,假如你和多元素CSS动画打交道,可能就需要改变下惯性思维了,很主要的一点就是“从以左上角为参考点变成以中间点为参考点”。

经验分享多屏复杂动画CSS技巧三则?经验分享多屏复杂动画CSS技巧三则

我们在实现多元素动画效果时候,会出现两类角色:一是容器;二是容器里面诸多动画元素。

其中,对于容器元素,尤其在做移动端产品时候,我们很天然会让其居中定位:

.container {
    position: absolute; left: 50%; top: 50%;
    transform: translate3d(-50%, -50%, 0);
}

这样,各种尺寸的手机,我们都能让其居中显示(大尺寸可能需要一定的缩放)。

但是,我们有没有想过让容器里面的诸多动画元素也居中定位显示呢?

用代码来诠释就是从左上角定位(或右上角定位):

.example {
    position: absolute; left: 100px; top: 100px;
}

变成中间点定位+?margin偏移:

.example {
    position: absolute; left: 50%; top: 50%;
    margin-left: -100px; margin-top: -100px;
}

有同窗可能要疑问了,why? 前面一步到位不挺好的,后面这样分两步走岂不是多余?

在大多数情况下,我们的应用场景比较单一,或只需要玩转移动端,或只需要驾驭桌面端,此时,上面两种定位的优劣是看不出来的。

但是,碰到一些复杂的应用场景,尤其涉及到容器尺寸或定位体例改变的时候,后面的定位优势就可以看出来。

比方说一开始提到的qzone5.0的例子,假如我们把容器宽度加大(现实是不会的,示意目的),如414像素:

经验分享多屏复杂动画CSS技巧三则

会发现,宇航员和飞船在小行星之外了,也就是动画元素不是聚拢状况了。

所以,大家看出居中定位的优势来了没有:

  1. 动画元素之间的位置关系不受容器尺寸影响;
  2. 居中特征遭遇多场景时适应性更强;

照旧拿去年年底做的「企业QQ-新年祝福」运动举例,第8屏:

经验分享多屏复杂动画CSS技巧三则

其中,中心的“王强”和“马老板”这些数据有可能是没有的,也就是很有可能这一屏只有文字和宇航员,但同时还要保持整体垂直居中。很显然,宇航员和火箭所在的容器不能是绝对定位,否则脱离文档流,不能和上面元素保持合适垂直间距同时垂直居中。我们仍然有2种实现方法:

  1. 固定容器宽度,例如350像素宽,然后,里面左上角定位等,自己margin: auto水平居中;
  2. 容器不设定width大小,直接里面动画元素居中定位;

方法1问题在于:

  1. 第7屏是类似结构,但是其动画容器宽度不是350像素,没法重用;
  2. 当在iPhone5/iPhone5s下,屏幕320像素宽(小于350像素),因为左上角定位,因此,整体不是居中效果;

而方法2,屏幕尺寸再小,也是居中的,只不过两侧有所剪裁。最终,移动端适配时候,我们不必关心定位问题,只要合适缩放就可以了?经验分享多屏复杂动画CSS技巧三则

经验分享多屏复杂动画CSS技巧三则

以上两屏示意demo戳这里

结语

首先,大家要晓畅,本文所展示的三个技术技巧属于小我经验建议,注重,是建议。里面所提到的所有解决方法都有更加直观、通俗的实现,对于大多数的产品而言,技术的价值体现已经足够;同时应用场景千万万,没有什么一方通行的方法,例如居中定位准则,有时候,可能就是需要非居中定位。

但是,作为一个有技术追求的技术从业人员,对技术的精益求精一定是有价值的,无论是对自己,照旧公司。有人可能会反驳,我们这个项目明明只会针对移动端,你还花心思考虑低配的事情,岂不是白白虚耗时间和人力成本。古人有云:“不以善小而不为”,这种去粗取精的小经验虽然看上去没什么实质性成长,对眼前项目也没多少价值体现,但是积累足够多,会产生质变的,填坑的事情少了,工作也更轻松与快乐,对公司产生的价值也更大。

高瞻远瞩积跬步,登峰造极至千里。

好了,以上就是自己对于多屏CSS动画方面的一些技巧体味,希望可以对大家的学习有所帮助。当然,资历有限,要是文中有什么表述不准确的地方,迎接指正;也迎接针锋相对的讨论,共同成长。

本文出处:?腾讯ISUX?

相关解决方案