前言

有一天散会,产品经理在大家背后慷慨激昂的说道:

最近刷抖音刷微博啥的常常能看到鸿蒙的音讯,看到中国终于呈现了一个有可能会在将来成气候的操作系统也是很开心。感觉谷歌被啪啪打脸,刚刚发表安卓12不给华为用,完了转头人家就拿进去个鸿蒙OS,间接对标谷歌还在襁褓中的Fuchsia OS。谷歌这就很难堪,跟吧?安卓咋整?这可刚官宣安卓12啊!总不能像华为似的间接提醒用户降级新零碎吧,那就证实要淘汰掉安卓了!不跟吧?当初华为的万物互联操作系统曾经能用了,如果不公布Fushsia的话那就会被疾速的抢占市场份额,尤其是当鸿蒙的生态成气候了之后,再想要夺回市场份额那可就是难上加难了!

我集体甚至认为反而是美国的制裁帮忙了鸿蒙零碎,为什么这么说呢?首先,尽管鸿蒙之前在始终在开发中,但华为其实并没有押宝在这个零碎上,也就是说给予该我的项目了肯定的反对,但反对的水平并不特地大。起初美国一顿制裁,大家都感觉到了迟早会有一天安卓也不给华为用了,于是华为大大增加了对鸿蒙这个我的项目的反对,开发这个我的项目的开发者们也铆足了劲势要冲破美国的技术封闭,鸿蒙也就大大放慢了它后退的脚步。起初全世界都晓得美国是怎么欺侮华为的了,尤其是中国人,感觉这也太欺侮人了吧!既然咱们出了新零碎,很多人还是想要尽本人的一份力反对一下的。

构想一下,如果川建国(Trump)同志没有高举贸易爱护的大旗来痛下杀手的话、华为也能照常洽购芯片等各种半导体产品、谷歌的GMS华为也用的好好的、手机市场也没有朝气蓬勃、每年赚它个百八十亿的、安卓12发布会也邀请华为一起加入…

那么此时华为推出一个 Harmony OS,大家还会和当初这种态度一样吗?会不会感觉这个零碎只是华为出于本人的商业利益而开发进去的零碎?安卓零碎好好的瞎折腾啥?华为手机的用户还会有多少人违心降级到鸿蒙零碎?而且大家对国货普遍存在质疑态度,在相差不大甚至小幅度当先的状况下大家都宁愿多花钱购买外国货。OPPO如果还是和前阵子那样喷一下鸿蒙,大家还会说:如果OPPO不适配鸿蒙当前就不买OPPO了吗?抖音快手等各大短视频平台以及央视各种新闻还会给鸿蒙这么大的曝光度吗?就算给了这么大的曝光度,大家不会恶感吗?


听了他的演讲我还认为这是要让咱们开发鸿蒙利用了,还好我做过功课,看了一下语法,感觉跟小程序有些相似,这下前端又要开始卷了… 当前面试的时候预计还要问鸿蒙利用的常识…

就在这时产品从他的口袋里掏出了一台搭载了鸿蒙操作系统的华为mate40,问:大家都升鸿蒙零碎了么?答:咱们都用iPhone… 当然哈,我本人用的是安卓,不过也不是华为,而是便宜的realme(留下了没钱的泪水),所以也没法降级。

产品:来让你们看看我的开机动画:

我心愿这个字母的动画可能移植到咱们的网站下面去,因为咱们的好多产品字母里同样也有个

剖析动画

既然需要明确了下来,那么咱们就要开始对这个动画进行剖析了。第一次看的时候感觉挺惊艳的,因为感觉就像是一轮空心的明月在水面上升起,水面倒映着月影,让我想起了唐朝驰名浪漫主义诗人李白的那句:举杯邀明月,对影成三人

前半秒我竟然没看进去这到底是个什么,等这个空心的满月全副升起的时候我才晓得原来这是一个字母:

既然是倒映,那么就证实高低的显示是统一的,只不过是倒了过去,那么咱们有(包含但不仅限于)如下几种抉择:

  • -webkit-box-reflect (专门做倒影或侧影的一个属性)(火狐和IE不反对)
  • -moz-element() (能够将DOM的某局部当作图片渲染)(只有火狐反对)
  • 复制一遍DOM 而后用transform: rotate(180deg);把它给倒过去

想了一下尽管最初那个最麻烦,但最合适的还是它,不仅仅因为它的兼容性最好,而是因为仔细观察了一下鸿蒙的收场动画,那个倒影是有肯定的含糊水平的。-webkit-box-reflect只能管制方向及透明度或突变透明度,但无奈增加含糊成果。-moz-element()尽管十分弱小,但只有火狐反对那是必定不行的,要晓得目前火狐在浏览器市场的占比曾经非常低了,所以只好用不那么优雅的第三个形式了,首先咱们须要绘制一个半圆形的圆环,你能想到几种形式?

第一种:

一大一小两个半圆,小半圆的背景色放弃与页面背景色统一的色彩,而后盖在大半圆上(就像日环食那样),这样看起来就像是个圆环啦(原理示意图):

第二种:

先写进去个半圆,不给加背景色,只给加边框,最初把下边框去掉,于是看起来就是个半圆环啦(原理示意图):

第三种:

间接写个圆,而后写上边框,圆环外套个容器,外层容器高度为圆的一半,最初overflow: hidden;暗藏掉露在里面那半局部(原理示意图):

第四种:

把第三种的overflow: hidden;换成clip-path(原理示意图):

第五种:
间接用SVGCanvas来进行绘制(原理示意图):


最终还是抉择了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属性都是从SVG那里取得的灵感,比如说咱们较为罕用的pointer-eventsfilter等,还有一些不罕用的clip-pathmask等…

因为CSS提供给咱们的含糊只能各个方向都含糊,而在目前这种状况下咱们须要的是沿着Y轴含糊,那么SVG的代码就能够写成这样:

<svg>  <filter id="blur">    <feGaussianBlur in="SourceGraphic" stdDeviation="0 5"/>  </filter></svg>

看不懂没关系啊,大家只须要记住stdDeviation这个属性是管制含糊的就能够了,如果只给一个数字的话,就相当于全方位含糊,跟CSS的filter: blur();成果是一样的。但如果给了两个数字,那么第一个数字就代表X轴含糊水平,第二个数字就代表Y轴含糊水平。在这里咱们让X轴含糊水平为0Y轴含糊水平为5,留神不要像写CSS的时候给加单位(px),这里只写数字就好了,不要带单位。

因为CSS的滤镜属性filter原本就是从SVG那边排汇过去的,所以在CSS中能够应用SVG滤镜!用法如下:
filter: url(#blur);

咱们之前不是在SVG的<filter>标签上加了一个id属性么,这个id就能够写在CSS滤镜url里。但也不知是谷歌浏览器的filter在动态变化的元素上渲染不好还是怎么着,总之在Chrome浏览器里显示成果是这样的:

而在Safari浏览器里是这样的:

在火狐浏览器里成果最为完满:

那这可不行啊,谷歌浏览器可是市场占有率最高的浏览器了,产品那边必定通不过的!不过也不是没方法解决啦。在谷歌浏览器那显示的问题不就是一开始会有个缝嘛!那咱们就margin-top: -2px;来让这两个半圆先负间隔接触,对于它俩来说也不必-18px-2px就够啦:

最初一步,就是把下半圆的含糊成果去掉,让它真正的变成一个字母

没想到用了SVGCSS 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>

正文的那局部代码就是为了解决谷歌浏览器有缝隙的代码,能够解开正文比照一下在谷歌浏览器里的成果。不解开正文的话拿火狐浏览器关上成果是最好的。最重要的一点是,咱们能够通过批改代码里的数字来扭转这个动画的成果:

大家感觉这仨哪个更好看呢?当然如果像鸿蒙那样作为开机动画来说,必定是越快越好。因为这个动画可能也就前两次看着能有点新鲜感。但每次开机都看这么个动画,很快就会审美疲劳了,只心愿可能快点开机。

不过如果抛开这些利用场景的话,大家感觉是第一张那样让含糊缓缓隐没难看,还是最初那张一边升起一边就把含糊度给擦除掉了难看呢?

本文首发于公众号:前端学不动