🏆🚀🎉前端开发,实现头像从圆圈⭕️伸出来的效果🕳

🔴 前言

动机
:为什么要写这篇?
:之前在一个国外网站看过这个动画,当时扪心自问了一下:"让你来做你怎么做,会做吗,要多久..."
自己想了一些方案,最后陷入深深的沉思...

这里引用罗翔老师的一句话吧:说真的,你对这个专业的知识,你可能连1%都掌握不了。承认自己的无知,乃是开启智慧的大门。

所以,有了这篇文的记录📝。

3d卡通人物头像

效果:

🔴 正文

⭕ 思路

简单画背景和边

给我们来做,可能首当其冲冒出来的第一个思路

html 复制代码
<div class="avatar">
    <img src="./avatar.png" />
</div>

<style>
  body {
    margin: 0;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .avatar {
    width: 280px;
    height: 280px;
    border-radius: 50%;
    background: #ecd078;
  }

  img {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    transition: 0.5s;
  }

  .avatar:hover img {
    transform: scale(1.2);
  }
</style>

div,都。鼠标移入,图放

没达到我们要的效果。

再来。

径向渐变画背景和边

1、不搞border,搞径向渐变画背景(其中背景包括 色+边)。

2、用outline代替border。

区别:(1)、outline不占空间,画在周围 说明:属性可使用以下(1、2、3)任意一个值来声明,顺序不重要 -> outline: color style width offset

3、色块用色,框用色。

css 复制代码
--backgroundColor: #ecd078;
--borderColor: #c02942;

(1) 大色块黄色扩散,是个圆。
(2)closest-side最短边做圆的半径。
(3) background: radial-gradient():用来创渐变背景的,我们这整个效果,能做到这个,其实中心思想还是靠渐变画色的。


小课堂

-- 本质 :从元素的背景的中心去画颜色,从内而外去渐变。

-- 参数 :各个参数的怎么定怎么设 --->
background: radial-gradient(circle at center, red 0, blue, green 100%)

说的是:在容器中心的渐变,从红开始,然后蓝,最后绿。

从红渐变到蓝色,绿色在100%的位置,蓝色的范围填充了整个渐变区域,

绿色设置在最后位置,将不会显示出来。

如果想要看到绿色,那么调整100%50%,像这样background: radial-gradient(circle at center, red 0, blue, green 50%);


css 复制代码
background: radial-gradient(
    circle closest-side, 
    var(--backgroundColor) calc(100% - var(--borderWidth)), 
    var(--borderColor) calc(100% - var(--borderWidth)), 
    var(--borderColor) 100%, 
    green 100%);

closest-side用来指定径向渐变的尺寸

以背景的最近的边作为渐变的尺寸。

宽度都要减去边的宽。(用calc计算属性calc(100% - var(--borderWidth))

也就是说,渐变从中心到最近的边去画。

通过background径向渐变去画背景框的效果是这样的;

鼠标进去,人大,但景不得大。

设背景图,(1)、不重复;(2)、居中。

css 复制代码
background: radial-gradient(
    circle closest-side, 
    var(--backgroundColor) calc(100% - var(--borderWidth)), 
    var(--borderColor) calc(100% - var(--borderWidth)), 
    var(--borderColor) 100%, 
    green 100%) no-repeat center;

当scale(2),那么背景要½,才能保持原样。½ x 2 = 1这样。

css 复制代码
img {
    --size: 280px;

    --backgroundColor: #ecd078;
    --borderColor: #c02942;

    --borderWidth: 5px;

    --scaleTimes: 1; /* 放大倍数 */

    width: var(--size);
    height: var(--size);

    cursor: pointer;
    border-radius: 50%;

    background: radial-gradient(circle closest-side,
        var(--backgroundColor) calc(100% - var(--borderWidth)),
        var(--borderColor) calc(100% - var(--borderWidth)),
        var(--borderColor) 100%, green 100%) no-repeat center / calc(100% / var(--scaleTimes)) 100%;

    transition: 0.5s;
    transform: scale(var(--scaleTimes));
 }

img:hover {
    // transform: scale(1.35)
    --scaleTimes: 1.35
}

no-repeat center / calc(100% / var(--scaleTimes)) 100%

背景寸设置为calc(100% / 放大倍数)

鼠标移入,改变--scaleTimes,背景横尺寸根据这个放大倍数改而改。

效果如下:

是不是有那了。
人大背景保持不变

变量去搞背景的尺寸问题,使背景保持不变。

至于那个绿色,还记得吗?是这一部分,延伸到四面八方的,设置了green,也就是这个值:

连接红线

借助outline画线。

css 复制代码
outline: var(--borderWidth) solid var(--borderColor);
border-radius: 0 0 999px 999px;
outline-offset: calc(0px - var(--borderWidth)); // 即border的offset设置为-5px,目的是为了跟原来的渐变画的border重叠。

鼠标进,outline边的尺寸保持不变,所以outline-offset要动态变。

offset的值(也就是变化的差距的值)的计算,就是放大后的宽度减去原来的宽度除以2.

就是(size * scaleTimes - size) / 2

再就是要除以一个放大倍率(size * scaleTimes - size) / 2 / scaleTimes,得到真正被收缩的值。

(size * scaleTimes - size) / 2 / scaleTimes 最终会得到 (size - size / scaleTimes) / 2

注:
(size * scaleTimes - size) / 2 / scaleTimes最后再去除以scaleTimes的意思是,如果宽度是200的话,咱offset最多顶天了就是-100,也就是缩到极限了,缩到中心点了。我们没有除以倍率是因为我们一开始假设默认的倍率是1的情况。

放大到无限大的时候,这个offset的差距值就远远超过100,所以,正确的最终计算还要除以倍率。也就是(size * scaleTimes - size) / 2 / scaleTimes


计算过程

x是size, y是scaleTimes:

上面式子简化成这样:

然后拆成这样:

也就是(size - size / scaleTimes) / 2。 这个得到是正数。收缩的offset是个负值,那么就是反过来(size / scaleTimes - size) / 2

css 复制代码
outline-offset: calc((var(--size) / var(--scaleTimes) - var(--size)) / 2 - var(--borderWidth));

防挡发

padding-top:

css 复制代码
padding-top: 100px;

挡是不挡了, 但是不对了,人下移了。

那么,设置背景图就搞content的内容就好了,padding不要管它就行了。也就是说,设个content-box给背景图叫它只管content,不管padding。

css 复制代码
background: radial-gradient(circle closest-side,
            var(--backgroundColor) calc(99% - var(--borderWidth)),
            var(--borderColor) calc(99% - var(--borderWidth)),
            var(--borderColor) 100%, green 100%) no-repeat center / calc(100% / var(--scaleTimes)) 100% content-box;

已经完成了差不多全部了。

但是圈外的东西能不能不要了

如果想要一个东西看不到

我们就一股脑要不是overflow hidden,要不就是用mask

多余的,不要

mask

css 复制代码
mask: radial-gradient(circle closest-side, #000 99%, transparent) content-box no-repeat center / calc(100% / var(--scaleTimes)) 100%;

这个mask途径的地方才显示,其他的都不显示。

所以我们拿上面那个渐变的圆来搞这个mask的圆。就可以了。

效果如下:

那圆外的头被搞掉了。

那么接着。

遮罩的区域

区域范围:

遮罩区域:上面一部分 + 下面头像那个正圆

mask上面部分
css 复制代码
img {
    background: linear-gradient(#000 0 0) no-repeat center; // 全黑的渐变
}

看鼠标移入的效果,背景变大了,但是呢边outline没动。所以,背景要下移,至于下移多少,就看outline的收缩距离的值,也就是outline-offset这个值。

加个收缩变量值--shrink:

css 复制代码
// border收缩的变量
--shrink: calc((var(--size) / var(--scaleTimes) - var(--size)) / 2 - var(--borderWidth));

outline-offset: var(--shrink);
background: linear-gradient(#000 0 0) no-repeat center calc(0px - var(--shrink));

至于为啥0px - 收缩值,因为这个收缩值是负数,我们背景是要下移,所以0 减去一个负数得正数,就是下移的距离。

所以得到的效果如下:

接下来就是mask的尺寸了,你看上面效果是不是黑色区域随着鼠标进去,变大了。我们要它鼠标进去,不要大,就是跟之前圈圈一样,鼠标一进去头像大两倍,但背景保持不变,也就是乘以二分之一。

css 复制代码
background: linear-gradient(#000 0 0) no-repeat center calc(0px - var(--shrink)) / calc(100% / var(--scaleTimes)) 50%;

注意这里:纵向写50%就好了。

这样,mask遮罩上面部分就完成了。

mask下面部分

下面部分是个圆。radial-gradient(circle closest-side, #000 99%, transparent) var(--backgroundOption)

css 复制代码
--backgroundOption: content-box no-repeat center / calc(100% / var(--scaleTimes)) 100%;


-webkit-mask: 
    linear-gradient(#000 0 0) no-repeat center calc(0px - var(--shrink)) / calc(100% / var(--scaleTimes)) 50%, 
    radial-gradient(circle closest-side, #000 99%, transparent) var(--backgroundOption);

接下来就是要去除上面那两条竖边框。就是也是用mask

横向的背景就是边的线的宽度:calc(99% / var(--scaleTimes) - 2 * var(--borderWidth))

css 复制代码
-webkit-mask: linear-gradient(#000 0 0) no-repeat center calc(0px - var(--shrink)) / calc(99% / var(--scaleTimes) - 2 * var(--borderWidth)) 50%, radial-gradient(circle closest-side, #000 99%, transparent) var(--backgroundOption);

至此遮罩写完。

头出洞🕳效果也随之完成。

🔴 总结

真的,我觉得前端把css得特的人绝非等闲之辈。

你说,我js可能不会的能查上一查,

css那些风骚奇淫怪技的一些效果,肚子里没点存货没点墨水,ddl延后多久,想破脑袋可能做出来都没达到完美交稿的效果。

☎️ 希望对大家有所帮助,本文有些地方可能考虑不够周到,有些纰漏,就当抛砖引玉,还望您海涵,如有错误,望不吝赐教,欢迎评论区留言互相学习。感谢阅读,祝您开发有乐趣。

相关推荐
腾讯TNTWeb前端团队2 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰5 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪5 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪5 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy6 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom6 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom7 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom7 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom7 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom7 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试