基于上次翻译的 🔥🔥一个炫酷的头像悬停效果 收获了不少同学的喜欢,原作者近期进行了优化升级。本文将升级后的核心实现过程进行梳理讲解,如果没看过第一期的推荐先看看第一期的实现过程。升级后的效果如下图所示。
gif动画效果如下:
相对于上次的效果主要增加了背景的变化,增加了默认的旋转动画以及背景花瓣的效果。核心实现技术点如下:
- 不需要额外的元素,仅使用
<img>
标签 - 不使用伪元素
- 使用future CSS,mask,@property,三角函数和大量的数学函数
- 使用Sass和CSS变量优化代码量
- 小圆的大小和数量可配置
对于实现过程的相关三角函数及Sass相关函数不过多解析,有兴趣的可以详细了解。
基础变量定义
为了方便后面操作与更改配置,首先定义几个变量方便调整配置和后续代码引用。
背景圆中的小圆数量 $n
:
$n: 15;
控制小圆半径和主体的尺寸大小:
--r: 50px;
控制小圆放大比例基数,控制数值在1.2和2之间:
--f: 2;
主体背景颜色:
--c: #E4844A;
除此之外还通过 @property
定义了2个变量,控制旋转的角度及小圆之间的间距。
通过
@property
声明的变量可以定义其语法、继承性和初始值。这样做的好处是可以在文档中明确地声明变量,并指定其用途和限制条件。这种声明方式更适合需要详细定义的场景,例如自定义属性。
@property --a {
syntax: "<angle>";
initial-value: 0deg;
inherits: true;
}
@property --i {
syntax: "<length>";
initial-value: 0px;
inherits: true;
}
背景绘制
背景图形上有多个小圆组成,小圆的数量是可配置的,所以背景的小圆需要基于所配置的数量动态生成,这里需要用到几个Sass
的函数。
由于小圆的数量$n
支持配置,所以整个元素的大小会随之影响发生变化。通过设置aspect-ratio
,我们只需要控制width
的变化即可。宽度的最终值基于小圆的半径和小圆的数量计算得出。
width: calc(var(--r)*(1 + 1/tan(180deg/#{$n})));
aspect-ratio: 1;
border-radius: 50%;
接下来开始绘制附属在大圆上面的小圆。
$m: ();
@for $i from 1 through ($n) {
$m: append($m,
radial-gradient(var(--c) 70%,#0000 72%) no-repeat
calc(50% + (50% -var(--i,0px))*cos(360deg*#{$i/$n} + var(--a,0deg)))
calc(50% + (50% -var(--i,0px))*sin(360deg*#{$i/$n} + var(--a,0deg)))/
var(--r) var(--r),
comma);
}
首先,我们定义一个变量 $m
,并将其初始化为空。然后使用 @for
循环从 1 到 $n
小圆的数量进行遍历。
在循环内部,使用 Sass
的 append()
函数将新生成的 radial-gradient
样式追加到 $m
变量中。append()
函数用于在列表类型的变量后面添加一个新的元素,并返回新的列表。
radial-gradient
样式由以下几部分组成:
var(--c)
70%:表示渐变的颜色和渐变的位置,其中颜色使用 CSS 变量--c
。#0000
72%:表示渐变的结束颜色和结束位置。- no-repeat:表示不重复渐变。
calc(50% + (50% - var(--i,0px))*cos(360deg*#{$i/$n} + var(--a,0deg)))
和calc(50% + (50% - var(--i,0px))*sin(360deg*#{$i/$n} + var(--a,0deg)))
:计算渐变的圆心位置,其中变量--i
和--a
是自定义变量,默认值分别为0px
和0deg
。- /
var(--r) var(--r)
:表示渐变的尺寸,其中尺寸使用 CSS 变量--r
。 comma
:表示多个背景图像之间使用逗号分隔。
循环结束后,变量 $m
将包含所有生成的 radial-gradient
样式,可以在后续的样式中使用 $m
来应用这些背景图像。
基于上面的代码继续完善,将最终生成的图形绘制到背景中。
--_m:
radial-gradient(var(--c) calc(72% -var(--r)/2 -var(--i,0px)),#0000 0),
#{$m};
-webkit-mask:
linear-gradient(#000 0 0) top/100% 50% no-repeat,
var(--_m);
background: var(--_m);
在上面的代码中,定义了一个新的CSS变量 --_m
。它的值由两部分组成:
- 一个
radial-gradient
背景图像样式,其中渐变的颜色和位置使用var(--c)
和calc(72% - var(--r)/2 - var(--i,0px))
表示,这个渐变的结束颜色是#0000
,结束位置是0
。这部分内容就是整个背景的中心大圆部分。 - 以插值的方式引用之前定义的变量
$m
。
接着使用 -webkit-mask
属性为元素设置背景遮罩效果。它包含两部分:
- 一个线性渐变
linear-gradient
,表示从顶部开始的黑色渐变。其中渐变的颜色为#000
,渐变的起始位置、结束位置分别为0
和0
。设置了top/100% 50%
表示linear-gradient
的尺寸是水平方向占满整个宽度,垂直方向占高度的一半。no-repeat
表示不重复渐变。 - 引用之前定义的变量
--_m
,将其作为元素的遮罩图像。
最后使用 background
属性将之前定义的变量 --_m
作为元素的背景图像。这样整个元素的背景就会显示之前生成的 radial-gradient
多个小圆的样式。
动画绘制
元素hover
后动画细节拆分:
- 背景圆旋转动画运行速度加快
- 大圆附属小圆放大配置比例
- 中心人物放大
hover
前后动画速度不一样是两段不同执行时间的动画在切换,默认设置的动画如下:
--_a: rotatelinearinfinite;
animation:
var(--_a) 10s,
var(--_a) 16sreverse;
@keyframes rotate {
to{--a:360deg}
}
当hover
时将第一段动画设置running
,第二段动画设置paused
。
animation-play-state: running, paused;
上面绘制小圆的时候是基于--r
半径绘制,我们还定义了--f
控制hover
时小圆放大比例的基数。--i
在绘制小圆的时候设置了默认值是0px
当hover
时基于设定的变量进行计算赋值到--i
,即可对校园进行放大的动画控制。
--i: calc(var(--r)/var(--f));
对中心人物图像的放大使用如下代码,核心使用了小圆数量 $n
,小圆半径--r
进行计算最终放大的比例。
scale: calc((1 + 1/tan(180deg/#{$n}))/(1 - 2/var(--f) + 1/tan(180deg/#{$n})));
另外还对主要的动画增加了过渡的效果,针对--i
和scale
的切换增加0.4s
的过渡时间,使动画更加丝滑。
transition: --i.4s, scale.4s;
在线源码
https://code.juejin.cn/pen/7269700151160078348
最后
到此整体核心实现的逻辑就结束了,整个实现过程用到了不少Sass
函数以及CSS3相关能力,定义了部分配置项使整个代码更加灵活可控,简洁高效。有兴趣的可以自己尝试看看。
看完本文如果觉得有用,记得点个赞支持,收藏起来说不定哪天就用上啦~
专注前端开发,分享前端相关技术干货,公众号:南城大前端(ID: nanchengfe)
参考
A Fancy Hover Effect For Your Avatar II: css-tip.com/avatar-hover-effect-2/