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

🔴 前言

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

这里引用罗翔老师的一句话吧:说真的,你对这个专业的知识,你可能连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延后多久,想破脑袋可能做出来都没达到完美交稿的效果。

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

相关推荐
木子七3 分钟前
vue2-路由Router
前端·vue
未 顾21 分钟前
HTML-CSS-JS-day01:html常见的标签
javascript·css·html
知野小兔25 分钟前
【Angular】eventDispatcher详解
前端·javascript·angular.js
苦逼的猿宝40 分钟前
Echarts中柱状图完成横向布局
前端·javascript·echarts
禾戊之昂42 分钟前
【Electron学习笔记(一)】Electron基本介绍和环境搭建
前端·javascript·electron·node.js
加班是不可能的,除非双倍日工资1 小时前
js 原生拖拽排序功能 简单实现
前端·javascript
放逐者-保持本心,方可放逐1 小时前
dom 元素应用 + for 循环应用
前端·javascript·for
冰冻果冻1 小时前
vue--制作购物车
前端·javascript·vue.js
前端设计诗1 小时前
CSS clamp() 函数:构建更智能的响应式设计
前端·css·less·css3·html5
大梦百万秋1 小时前
React前端框架基础知识详解
前端·react.js·前端框架