起因
- 第三节Css大会上(PPT)看到了微信 方潇仪 工程师分享的关于 svg动画的相关知识、
- 刚刚拿到百度实习offer (/∇\)、
- 喜欢萌萌的百度熊
样式
思路
原理
其实方潇仪 也提到了,就是利用svg 的filter标签,让两个圆高斯模糊后的边缘处虚化后再将两个源合并
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="0" height="0">
<defs>
<filter id="gooey">
<feGaussianBlur in="SourceGraphic" stdDeviation="10" result="step1"/>
<feColorMatrix in="step1" mode="matrix" values="
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 19 -9" result="step2" />
<feComposite in="SourceGraphic" in2="step2" operator="atop"/>
</filter>
</defs>
</svg>
其中 我们可以想像 每一步都是一个图层,每一个标签都是一个处理工具
in 属性将图层输入 result 将结果输出,但是不会将原来的图层改变,只会增加一个新的图层
那么实际上就很明显了
我们使用 feGaussianBlur 高斯模糊将原图层 模糊 10个单位 然后使用 feColorMatrix 调节图层整体对比度,让其回归清晰
再将之前未处理过的图层和处理好的图层进行合并(feComposite),让原来图层上的图标、文字等能够清晰显现(因为经过高斯模糊处理所以文字图标都没了,)
然后我们把处理过的图层对其进行引用
.nose {
...
filter: url(./baidu_beer.html#gooey);
}
@彦子 同学 和 @大漠 老师对svg研究的十分透彻和深入 大家可以去看 w3cplus svg 标签下的相关内容
布局
filter 只能影响被设置的元素,以及其下的子元素
如果设置过多的filter 又会使性能下降,所以我们将需要粘性变形的布局进行嵌套
<div class="nose">
<div class="nose-be"></div>
<div class="nose-mi"></div>
<div class="nose-af"></div>
<div class="l-eye-wrap">
<div class="eye eye-be"></div>
<div class="eye eye-mi"></div>
<div class="eye eye-af"></div>
<div class="l-eye-face"></div>
<div class="l-ear-wrap">
<div class="ear l-ear">
<div class="ear-hole l-ear-hole"></div>
<div class="ear-hole-mask l-ear-hole-mask"></div>
</div>
</div>
</div>
<div class="r-eye-wrap">
<div class="eye eye-be"></div>
<div class="eye eye-mi"></div>
<div class="eye eye-af"></div>
<div class="r-eye-face"></div>
<div class="r-ear-wrap">
<div class="ear r-ear">
<div class="ear-hole r-ear-hole"></div>
<div class="ear-hole-mask r-ear-hole-mask"></div>
</div>
</div>
</div>
</div>
这样布局的好处
- 给根元素添加粘性滤镜之外就能使所有的子元素都有粘性的效果
- 方便我们对动画进行分割,从动画中我们也可以看出来,动画是先从鼻子先变化,然后出来两个眼睛,然后眼睛再分别出来耳朵,层层分割,让我们便于使用js 进行控制
流程控制
不得不说,Promise 真的很好用
我们可以使用Promise 模拟一个 Sleep函数
function Sleep(timeout) {
return new Promise(function(resolve) {
setTimeout(function () {
resolve();
},timeout);
});
}
这样就可以使用Promise 很好的对动画进行控制
let process = Promise.resolve();
process.then(() => {
oNose.classList.add('show');
return Sleep(600);
})
.then(() => {
oFace.classList.add('show');
return Sleep(600);
})
.then(() => {
oFace.classList.add('face-mor');
oHeader.classList.add('show');
return Sleep(600);
})
.then(() => {
oNose.classList.add('nose-mor');
oLeyeWrap.classList.add('l-eye-wrap-mor');
oReyeWrap.classList.add('r-eye-wrap-mor');
return Sleep(300);
})
...
大家可以看出, 通过 很多个then 将一个连续的动画分割成了很多小的部分,通过控制class并配合 transition 和 keyframes animation ,我们就能画出这只萌萌哒的百度熊
源代码
想深入研究其他细节的同学,请参照源码
喜欢该效果的朋友可以不要吝惜您的star哦~