⚠️Este artículo es el primer artículo firmado por la comunidad de los Nuggets y está prohibido reimprimirlo sin autorización.
prefacio
Un día, en una reunión, el gerente de producto preguntó: ¿Todos se actualizaron al sistema Hongmeng? Entonces un grupo de personas respondió: Todos lo usamos iPhone…
, claro, yo uso Android, pero Huawei no ( 留下了没钱的泪水
)…
Después de escuchar su pregunta, pensé que era para nosotros desarrollar la aplicación Hongmeng. Afortunadamente, hice mi tarea y aprendí su sintaxis de antemano. Se siente un poco similar a un programa pequeño. En las entrevistas futuras, se estima que Preguntaré sobre el conocimiento de la aplicación Hongmeng...
En este momento, el producto sacó una computadora equipada con el sistema operativo Hongmeng de su bolsillo 华为mate40
: le mostraremos mi animación de arranque:
¡Espero que esta 〇
animación de carta se pueda portar a nuestro sitio web, porque muchas de nuestras cartas de productos también tienen una 〇
!
¡Dañino! ¡Resultó no ser para desarrollar aplicaciones Hongmeng!
Analizar animación
Ahora que los requisitos están claros, comenzaremos a analizar esta animación. La primera vez que lo vi, fue increíble, porque se sentía como una luna hueca saliendo de la superficie del agua, y la sombra de la luna se reflejaba en la superficie del agua, lo que me recordó la frase del famoso poeta romántico de la dinastía Tang, Li Bai: 举杯邀明月,对影成三人
:
No me di cuenta de lo que era durante el primer medio segundo, y cuando la luna llena estaba llena de huecos, me di cuenta de que era una letra:〇
Como es un reflejo, prueba que la visualización superior e inferior es consistente, pero está invertida, entonces tenemos ( 包括但不仅限于
) las siguientes opciones:
-webkit-box-reflect
(Especializado como atributo de reflejo o silueta) (火狐和IE不支持
)-moz-element()
(Puede representar una parte del DOM como una imagen) (只有火狐支持
)- Duplica el DOM e
transform: rotate(180deg);
inviértelo con
想了一下虽然最后那个最麻烦,但最合适的还是它,不仅仅因为它的兼容性最好,而是因为仔细观察了一下鸿蒙的开场动画,那个倒影是有一定的模糊程度的。-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属性都是从
SVG
那里获得的灵感,比如说我们较为常用的pointer-events
、filter
等,还有一些不常用的clip-path
、mask
等…
由于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
),这里只写数字就好了,不要带单位。
由于CSS的滤镜属性
filter
本来就是从SVG
那边吸收过来的,所以在CSS中可以使用SVG滤镜
!用法如下:
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>
复制代码
注释的那部分代码就是为了解决谷歌浏览器有缝隙的代码,可以解开注释对比一下在谷歌浏览器里的效果。不解开注释的话拿火狐浏览器打开效果是最好的
。最重要的一点是,我们可以通过修改代码里的数字来改变这个动画的效果:
大家觉得这仨哪个更好看呢?当然如果像鸿蒙那样作为开机动画来说,肯定是越快越好。因为这个动画可能也就前两次看着能有点新鲜感。但每次开机都看这么个动画,很快就会审美疲劳了,用户只希望能够快点开机少整点那些花里胡哨的。
不过如果抛开这些应用场景的话,大家觉得是第一张那样让模糊慢慢消失好看,还是最后那张一边升起一边就把模糊度给擦除掉了好看呢?
更多精彩内容请关注公众号:前端学不动
往期精彩文章
- 《不依赖任何库打造属于自己的可视化数据地图》
- 《尤雨溪国外教程:亲手带你写个简易版的Vue!》
- 《Vue第二波ref语法提案来袭 这次会进入到标准吗?》
- 《产品经理:能不能让这串数字滚动起来?》
- 《[译]尤雨溪:Vue3将不会支持IE11 精力会投入到Vue2.7》
- 《Vue超好玩的新特性:在CSS中引入JS变量》
- 《什么?仅靠H5标签就能实现收拉效果?》
- 《整治GitHub不文明现象!微软推出评论区!》
- 《Vue 3.0.3 : 新增CSS变量传递以及最新的Ref提案》
- "¿La caja negra pequeña doble 11 es genial? ¡Mejorémoslo con variables CSS! 》
- "¡No subestimes el hecho de que una sola pregunta en Jiugongge puede revelar el verdadero carácter de un candidato! 》
- "Las preguntas de la entrevista de diseño móvil examinan exhaustivamente sus habilidades de CSS (centro)"
- "Una serie de comportamientos confusos después de configurar el objeto prototipo en Proxy"
- "Nueva característica súper divertida de Vue: portal DOM"
- "Uso de la biblioteca CSS-in-JS súper popular de React en proyectos Vue: componentes con estilo"
- "¿Finalmente es el turno de Vue de Inspire React? 》
- "Un pequeño hoyo de Vue3 bajo IOS"
- "El uso de ganchos en la nueva versión de vue-router"
- "[Traducción] React 17 finalmente lanzó la versión RC, ¡el funcionario dijo que 17 es una versión de transición! 》
- "[Traducción] Yuxi You: El proceso de diseño de Vue3"
- "El padre del Deno refactorizado de Node finalmente se lanzó, ¿reemplazará eventualmente a Node?" 》