前言
有一天开会,产品经理问:大家都升鸿蒙系统了么?紧接着一群人答:我们都用iPhone…
当然哈,我自己用的是安卓,不过也不是华为(留下了没钱的泪水
)…
听了他这么一问我还以为这是要让我们开发鸿蒙应用了,还好我做过功课,有提前了解过它的语法,感觉跟小程序有些类似,这下前端又要开始卷了… 以后面试的时候估计还要问鸿蒙应用的知识…
就在这时产品从他的口袋里掏出了一台搭载了鸿蒙操作系统的华为mate40
:来让你们看看我的开机动画:
我希望这个字母〇
的动画能够移植到咱们的网站上面去,因为咱们的好多产品字母里同样也有个〇
!
分析动画
既然需求明确了下来,那么我们就要开始对这个动画进行分析了。第一次看的时候感觉挺惊艳的,因为感觉就像是一轮空心的明月在水面上升起,水面倒映着月影,让我想起了唐朝著名浪漫主义诗人李白的那句:举杯邀明月,对影成三人
:
前半秒我居然没看出来这到底是个什么,等这个空心的满月全部升起的时候我才知道原来这是一个字母:〇
既然是倒映,那么就证明上下的显示是一致的,只不过是倒了过来,那么我们有(包括但不仅限于
)如下几种选择:
-webkit-box-reflect
(专门做倒影或侧影的一个属性)(火狐和IE不支持
)-moz-element()
(可以将DOM的某部分当作图片渲染)(只有火狐支持
)- 复制一遍DOM 然后用
transform: rotate(180deg);
把它给倒过来
想了一下虽然最后那个最麻烦,但最合适的还是它,不仅仅因为它的兼容性最好,而是因为仔细观察了一下鸿蒙的开场动画,那个倒影是有一定的模糊程度的。-webkit-box-reflect
只能控制方向及透明度或渐变透明度,但无法添加模糊效果。-moz-element()
虽然非常强大,但只有火狐支持那是肯定不行的,要知道目前火狐在浏览器市场的占比已经非常低了,所以只好用不那么优雅的第三个方式了,首先我们需要绘制一个半圆形的圆环,你能想到几种方式?
第一种:
一大一小两个半圆,小半圆的背景色保持与页面背景色一致的颜色,然后盖在大半圆上(就像日环食那样
),这样看起来就像是个圆环啦(原理示意图
):
第二种:
先写出来个半圆,不给加背景色,只给加边框,最后把下边框去掉
,于是看起来就是个半圆环啦(原理示意图
):
第三种:
直接写个圆,然后写上边框,圆环外套个容器,外层容器高度为圆的一半,最后overflow: hidden;
隐藏掉露在外面那半部分(原理示意图
):
第四种:
把第三种的overflow: hidden;
换成clip-path
(原理示意图
):
第五种:
直接用SVG
或Canvas
来进行绘制(原理示意图
):
最终还是选择了overflow: hidden;
,因为用它来做圆环升起的效果很合适,把露在外面的那部分圆隐藏掉,然后控制圆的位置,看起来就像是一轮空心的明月从海面上升起来了一样(原理示意图
):
接下来再把两个半圆环拼接到一起去就可以了(原理示意图
):
去掉为了向大家展示原理的那些杂七杂八的动画之后,显示出来的最终效果如下:
是不是有那么一点点神似了呢?不过在细节上跟鸿蒙的那个开场动画比起来还是差了许多,比方说后来我又找到了一版鸿蒙开场动画,如果跟以前的动画比起来的话,现在这版本在细节上的处理就更加的游刃有余了:
首先我们可以看到这个〇
有一个外发光的效果,在黑色背景的衬托下显得格外明亮,鸿蒙第一版的那个动画其实也有外发光,大家可以翻上去仔细对比一下,那一版的外发光没有这一版明显,而且细节处理的也没有这版好。那版是在〇
全部显现之后立刻消除掉外发光,有些略显生硬。而仔细看这版的话可以发现外发光是在不知不觉的过程中消失的。CSS的外发光效果其实很好做,就是在黑色背景下用box-shadow
给元素添加一个适当模糊的白色阴影,然后求阴影部分面积:
此时溢出隐藏(overflow: hidden;
)这个方案的缺点就会被暴露出来,由于我们的阴影部分面积
在上下左右四个方向已经超出了外面盒子的宽高,所以被隐藏掉了,我们只好为外面的盒子加入内边距padding
来解决掉这个缺陷:
我们也把我们的〇
变白变粗,但仔细看又会发现新的问题:那就是box-shadow
默认只会在元素的外部添加阴影,我们〇
这个圆圈的内部却没有阴影,好在box-shadow
是支持多重阴影和内阴影的:
而且这种效果用filter: drop-shadow();
也同样可以实现,不过由于在谷歌内核的浏览器中,filter: drop-shadow();
在动态变化的元素上渲染效果并不如box-shadow
那样理想:
所以我们决定还是采用box-shadow
内外双阴影的方案,现在看起来已经不错了,但还是少了点什么,少的就是圆环倒映在水面上的模糊效果。要知道在日常生活中,倒映在水面上的图案通常会比真正的视图稍稍模糊一点:
这是因为水面其实并不是一个完全平整的平面,哪怕再小的风也会导致水面上产生一定的水波:
正是这些水波导致了倒映在水面上的图案会产生一定的模糊度,水波的波纹越细,模糊程度就会越精致。正如上面那张图一样,水波的波纹不够细,就会导致我们就能够看到水波的纹理,就像鸿蒙的效果图那样:
他这水波的纹理搞得跟指纹一样… 如果要咱们写出这样的一个滤镜的话还是非常困难的,但好在鸿蒙的开场动画并没有能够看到水波的纹理,所以咱们就可以用模糊效果(filter: blur(2px);
)来写:
这个效果跟鸿蒙的开场效果比起来差距可就不是一星半点了,所以说鸿蒙那个动画虽然看起来简单,好像就是一个圆环从水面上升起来的效果,但实际上蕴含的细节只有亲自动手试一遍才会知道。
模糊细节
我们来把咱们做的圆环升起时的效果和鸿蒙圆环升起时的效果截张图放在一起对比一下:
发现没有?咱们用的CSS模糊,模糊方向是上下左右东南西北等各个方向的,而鸿蒙的模糊方向是沿着Y轴
也就是上下方向的模糊,如果还是看着不太明显的话那咱们再来截一张图看看:
这个是圆环未完全升起时的效果,这回应该能比较明显的看出来,水面下的圆环越靠下模糊程度就越高,并且它的模糊主要是沿着上下两个方向来进行模糊的。而且在向下方向的模糊程度要比在向上方向时的模糊程度要高上许多,这样看起来就会比较真实,才能给用户一种在水面上升起的错觉。
如果不分青红皂白的按照各个方向一顿模糊的话,那么圆环看起来的效果就怎么也不像是在水面上的感觉了:
对于这种带着方向带着渐变带着不同程度的模糊效果,我们就不能指望CSS了。这种场景下需要用到的是更为底层也更加复杂的SVG滤镜
!
由于CSS提供给我们的模糊只能各个方向都模糊,而在目前这种情况下我们需要的是沿着Y轴模糊
,那么SVG
的代码就可以写成这样:
<svg>
<filter id="blur">
<feGaussianBlur in="SourceGraphic" stdDeviation="0 5"/>
</filter>
</svg>
看不懂没关系啊,大家只需要记住stdDeviation
这个属性是控制模糊的就可以了,如果只给一个数字的话,就相当于全方位模糊,跟CSS的filter: blur();
效果是差不多的。但如果给了两个数字,那么第一个数字就代表X轴
模糊程度,第二个数字就代表Y轴
模糊程度。在这里我们让X轴的模糊程度为0
、Y轴的模糊程度为5
,注意不要像写CSS的时候给加单位(px
),这里只写数字就好了,不要带单位。
filter: url(#blur);
我们之前不是在SVG的<filter>
标签上加了一个id
属性么,这个id
就可以写在CSS滤镜
的url
里。但也不知是谷歌浏览器的filter
在动态变化的元素上渲染不好还是怎么着,总之在Chrome
浏览器里显示效果是这样的:
而在Safari
浏览器里是这样的:
在火狐
浏览器里效果最为完美:
那这可不行啊,谷歌浏览器可是市场占有率最高的浏览器了,产品那边肯定通不过的!不过也不是没办法解决啦。在谷歌浏览器那显示的问题不就是一开始会有个缝嘛!那咱们就margin-top: -2px;
来让这两个半圆先负距离接触
,对于它俩来说也不用-18px
,-2px
就够啦:
最后一步,就是把下半圆的模糊效果去掉,让它真正的变成一个字母〇
:
没想到用了SVG
的CSS filter
居然没有任何的过渡效果,那就只好用requestAnimationFrame
来动态改变SVG
里的<feGaussianBlur>
上的stdDeviation
属性啦:
把这个效果拿给产品经理看,他很满意并对此赞不绝口。说看看咱们哪个产品名字里带〇
的,全给换上这个动画!
但实际上吧,我觉得这个动画在很多细节的处理上跟鸿蒙的开机动画还是有差距。不得不佩服开发鸿蒙的工程师团队,就在这转瞬即逝的一两秒里居然能蕴含那么多小细节。大家可以找一找细节上的差距,有空的话咱们再优化一下。
完整代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>公众号:前端学不动</title>
<style>
* {
padding: 0;
margin: 0;
}
html, body { height: 100% }
body {
background: black;
display: flex;
align-items: center;
justify-content: center
}
.ul {
position: relative;
width: 100px;
height: 50px;
padding: 10px;
list-style: none;
overflow: hidden
}
.ul:first-of-type {
padding-bottom: 0
}
.ul:last-of-type {
padding-top: 0;
/* margin-top: -2px; */
/* animation: container-move .1s 1.2s forwards */
}
.harmony {
position: absolute;
top: 10px;
left: 10px;
width: 70px;
height: 70px;
border: 15px solid white;
border-radius: 50%;
transform: translateY(50%);
box-shadow: 0 0 6px white, inset 0 0 6px white;
animation: move 1.2s forwards
}
.ul:last-of-type > .harmony {
top: auto;
bottom: 10px;
transform: translateY(-50%);
filter: url(#blur)
}
svg {
width: 0;
height: 0
}
@keyframes move {
to { transform: none }
}
/* @keyframes container-move {
to { margin-top: 0 }
} */
</style>
</head>
<body>
<div class="container">
<ul class="ul">
<li class="harmony"></li>
</ul>
<ul class="ul">
<li class="harmony"></li>
</ul>
</div>
<svg>
<filter id="blur">
<feGaussianBlur in="SourceGraphic" stdDeviation="0 6"/>
</filter>
</svg>
<script>
const filter = document.querySelector('feGaussianBlur')
const clearFilter = () => {
const value = parseFloat(filter.getAttribute('stdDeviation').split(' ')[1]) - 0.06
if (value > 0) {
filter.setAttribute('stdDeviation', `0 ${value}`)
requestAnimationFrame(clearFilter)
} else {
return
}
}
setTimeout(clearFilter, 1200)
</script>
</body>
</html>
注释的那部分代码就是为了解决谷歌浏览器有缝隙的代码,可以解开注释对比一下在谷歌浏览器里的效果。不解开注释的话拿火狐浏览器打开效果是最好的
。最重要的一点是,我们可以通过修改代码里的数字来改变这个动画的效果:
大家觉得这仨哪个更好看呢?当然如果像鸿蒙那样作为开机动画来说,肯定是越快越好。因为这个动画可能也就前两次看着能有点新鲜感。但每次开机都看这么个动画,很快就会审美疲劳了,用户只希望能够快点开机少整点那些花里胡哨的。
不过如果抛开这些应用场景的话,大家觉得是第一张那样让模糊慢慢消失好看,还是最后那张一边升起一边就把模糊度给擦除掉了好看呢?
往期精彩文章
- 《[译]尤雨溪:Vue3将不会支持IE11 精力会投入到Vue2.7》
- 《不依赖任何库打造属于自己的可视化数据地图》
- 《Vue超好玩的新特性:在CSS中引入JS变量》
- 《什么?仅靠H5标签就能实现收拉效果?》
- 《整治GitHub不文明现象!微软推出评论区!》
- 《Vue 3.0.3 : 新增CSS变量传递以及最新的Ref提案》
- 《双11小黑盒很炫酷?咱们用CSS变量来改进一下!》
- 《千万别小瞧九宫格 一道题就能让候选人原形毕露!》
- 《移动端布局面试题 全面考察你的CSS功底(居中篇)》
- 《将原型对象设置成Proxy后的一系列迷惑行为》
- 《Vue超好玩的新特性:DOM传送门》
- 《在Vue项目中使用React超火的CSS-in-JS库: styled-components》
- 《终于轮到Vue来带给React灵感了?》
- 《Vue3在IOS下的一个小坑》
- 《新版vue-router的hooks用法》
- 《[译]React 17终于发布RC版本了 官方竟说17是个过渡版!》
- 《[译]尤雨溪:Vue3的设计过程》
- 《Node之父重构的Deno终于发布了,它终究会取代Node吗?》
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!