如此丝滑的按钮交互效果

今天分享一个很有特色的按钮交互效果,保证让你停不下来,原作者是Adam Kuhn,有兴趣的可以去codepen体验,地址:codepen,本文将核心功能逐一讲解,以下是在线效果图:

2023-03-20 16.23.23.gif

基于这个动图可以将主要实现的几个功能点拆分为以下几点:

  • 按钮的径向渐变背景色可以随着鼠标的移动变化
  • 按钮的背景区域会随着鼠标的移动产生弹性变化效果
  • 按钮的文字阴影会随着鼠标的变化而变化

鼠标位置获取

在正式开始前做一些准备工作,分析主要的这几个功能点可以发现每个功能都和鼠标的移动有关,都需要借助于鼠标移动的坐标,所以我们首先获取鼠标的位置并传递到css中,代码如下:

document.querySelectorAll(".inner").forEach((button) => {
  button.onmousemove = (e) => {
    const target = e.target;
    const rect = target.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;

    button.style.setProperty("--x", `${x}px`);
    button.style.setProperty("--y", `${y}px`);
    button.style.setProperty("--height", `${rect.height}px`);
    button.style.setProperty("--width", `${rect.width}px`);
  };
});

这里除开传递鼠标的位置,还传递了当前按钮的宽高用于后续按钮文案阴影的依赖。

径向渐变背景动起来

背景色默认是纯色,随着鼠标的产生变化,所以这里和两个关键点有关,鼠标移入hover,移动过程中的坐标变化。实现过程核心是通过background定义两个背景色,默认的显示部分background-size是100%,渐变部分的background-size是0,待hover时设置为100%,这时就会显示渐变背景色内容了。

  background: 
    // 渐变背景色
    radial-gradient(
      circle at center,
      var(--lightest),
      var(--light) 5%,
      var(--dark) 30%,
      var(--darkest) 50%
    ),
    // 默认显示背景色
    var(--darkest);
  background-size: 0px 0px, 100%;

  :hover {
    background-size: 100%, 100%;
  }

显示之后要动起来,基于js传入的坐标值应用到transformtranslate平移,这里注意移动是要基于当前元素的中心点位所以x和y都要减去自身的50%。

transform: translate(calc(var(--x) - 50%), calc(var(--y) - 50%));

如图所示,绿色区域是按钮部分,整个背景的中心点要和鼠标移动的坐标一致,所以要减去自身宽高的各一半。还有一点需要注意的是不能在移动的过程中让背景色漏出,所以背景区域是整个按钮的2倍。
[图片上传失败...(image-2fd66e-1679361810122)]

这时整个背景区域很大,这里使用了CSS3的混合模式mix-blend-mode: lighten,最终只会应用亮色部分也就是中间的绿色区域。这里的混合模式给下一步中的弹性伸缩效果起到重要的作用。

此时的效果就是这样的,原代码在此基础上还增加了transition和filter体验让效果更佳,因涉及篇幅较长这里就不一一说明了,

[图片上传失败...(image-eea2b2-1679361810122)]

背景区域弹性变化交互效果

背景弹性交互效果需要增加一个元素,与当前按钮同级别。此时的html如下:

<div class="inner">
  <button type="button">南城FE</button>
  <div class="blob"></div>
</div>

blob元素和button都使用了绝对定位,因为按钮上面有文字,所以层级上button更高。blob元素增加了两个伪元素,先看after

&:after {
  width: calc(100% - 4rem);
  height: calc(100% - 4rem);
  top: 2rem;
  left: 2rem;
  border-radius: 5rem;
  box-shadow: 0 0 0 8rem #fff;
}

基于当前界面减少实际按钮的区域,并通过定位居中,再通过box-shadow填充白色背景,还增加了圆角,此时按钮的背景变成如下所示,按钮的雏形已经有了。
[图片上传失败...(image-7727d3-1679361810122)]
然后before主要也是通过box-shadow来增加额外的元素显示,分为三个部分,中间部分跟随鼠标移动,上下两个部分为鼠标移动到边界的反向效果区域。核心代码如下:

box-shadow: 0 0 0 0.75rem #fff, 0 -8rem 0 2rem #fff, 0 8rem 0 2rem #fff;

再配合基于js传入的坐标值应用到translate平移,box-shadow部分的内容即可跟随鼠标动起来了。这里用到了一个css3的函数clamp,它可以用来限制一个值的范围。clamp函数接受三个参数,分别表示最小值、推荐值和最大值。函数的返回值为推荐值,但是它会被限制在最小值和最大值之间。所以这里超出按钮的显示区域会有临界点,不会完全脱离,核心代码如下:

transform: translate(
  clamp(5%, calc(var(--x) - 50%), 550%),
  clamp(1rem, calc(var(--y) - 50%), 5rem)
);

此时按钮的效果如下,圆形部分即是上面的0 0 0 0.75rem #fff,下面的半圆即是0 8rem 0 2rem #fff,因为增加了圆角border-radius: 100%所以都是圆形。为什么下面的是半圆白色,因为after中的box-shadow白色背景遮挡了,所以不会完全显示,又因为是白色阴影加上混合模式所以这块区域以亮色白色显示。

[图片上传失败...(image-d57138-1679361810122)]

是不是和目标效果有些接近了,加上一行关键代码即可。

filter: blur(12px) contrast(50);

这里使用filter属性处理,首先对元素进行模糊处理,如果只是增加模糊的效果如下,可以看到增加的伪元素圆形都被磨平了,完美的融入到了按钮本身的背景色中。

[图片上传失败...(image-5019dd-1679361810122)]

再加上contrast调整元素的对比度即可达到最终的效果,这里切记执行的顺序不能写反。在CSS中 filter 属性中的函数是按照从左到右的顺序执行的。如果你在 filter 属性中使用了多个函数,那么它们会按照从左到右的顺序依次执行。

[图片上传失败...(image-2d51d9-1679361810122)]

按钮的文字阴影变化

文字的阴影变化主要是改变其水平和垂直的偏移量,以及模糊半径,这里就要用到最开始传入的按钮宽高的数据了,因为偏移量的计算会基于整个按钮的面积,这样才会显得更逼真。

先看水平和垂直的偏移量,核心还是基于clamp函数,设置最小值,最大值,中间的推荐值则会随着鼠标的坐标值变化而变化,具体的数值有兴趣的可以调整体验,以下是文字阴影的水平和垂直的偏移量计算的代码:

clamp(-6px, calc((var(--width) / 2 - var(--x)) / 12), 6px)
clamp(-4px, calc((var(--height) / 2 - var(--y)) / 16), 4px)

然后是模糊半径的计算,这里用到了max函数,最大取5px,其他情况基于坐标值和宽高计算得出。

max(
  calc((var(--width) / 2 - var(--x)) / 8 +
      ((var(--height) / 2 - var(--y)) / 3)),
  calc((
        ((var(--width) / 2 - var(--x)) / 8) +
        ((var(--height) / 2 - var(--y)) / 3)
      ) * -1
  ),
  5px
)

最终的效果如下:

[图片上传失败...(image-5074de-1679361810122)]

最后

到此整个核心的实现过程就结束了,整个代码中我们使用了box-shadowtext-shadowmix-blend-modefilter等属性,还有CSS3函数maxclampcalc。还有transition动画相关没有说明,涉及的知识点比较多,有兴趣的同学可以看源码了解。

在线代码预览:https://code.juejin.cn/pen/7212194628471095336

到此本文就结束了,看完本文如果觉得有用,记得点个赞支持,收藏起来说不定哪天就用上啦~

专注前端开发,分享前端相关技术干货,公众号:南城大前端(ID: nanchengfe)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • CSS编码技巧 尽量减少代码重复 多种尺寸的按钮 使用em、rem作为边距的单位,可以让按钮尺寸随着于字号进行缩放...
    alfalfaw阅读 276评论 0 0
  • 22、JQ的基础语法、核心原理和项目实战 jQ的版本和下载 jQuery版本 1.x:兼容IE6-8,是目前PC端...
    萌妹撒阅读 1,740评论 0 0
  • CSS参考手册 一、初识CSS3 1.1 CSS是什么 CSS3在CSS2.1的基础上增加了很多强大的新功能。目前...
    没汁帅阅读 3,552评论 1 13
  • CSS:全称Cascading Style Sheets(层叠样式表) CSS 规则由两个主要部分构成,选择器(给...
    张_何阅读 184评论 0 0
  • CSS3的新特性大致分为以下六类 1.CSS3选择器2.CSS3边框与圆角3.CSS3背景与渐变4.CSS3过渡5...
    yaoyao妖妖阅读 561评论 0 0