Such a silky button interaction effect

Today I will share a very distinctive button interaction effect, as shown in the cover picture, it is guaranteed to make you unable to stop. The original author is, if you are Adam Kuhninterested, you can go to codepen to experience it. Address: codepen . This article will explain the core functions one by one.

Based on this animation, the main functional points can be divided into the following points:

  • The radial gradient background color of the button can change with the movement of the mouse
  • The background area of ​​the button will have an elastic change effect with the movement of the mouse
  • The text shadow of the button will change with the mouse

get mouse position

Do some preparatory work before the official start. By analyzing the main function points, you can find that each function is related to the movement of the mouse and needs the coordinates of the mouse movement, so we first obtain the position of the mouse and pass it to css ,code show as below:

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`);
  };
});
复制代码

Here, in addition to passing the position of the mouse, the width and height of the current button are also passed for the dependence of the shadow of the subsequent button copy.

radial gradient background moving

The background color is a solid color by default, and changes with the mouse, so it is related to two key points, the mouse moves into the hover, and the coordinates change during the movement. The core of the implementation process is to define two background colors through the background. The default display part background-sizeis 100%, and the gradient part background-sizeis 0. When hovering, set it to 100%, and then the gradient background color content will be displayed.

  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%;
  }
复制代码

transformAfter the display, it needs to move, based on the translation applied to the coordinate value passed in by js translate. Note here that the movement is based on the center point of the current element, so x and y must subtract 50% of themselves.

transform: translate(calc(var(--x) - 50%), calc(var(--y) - 50%));
复制代码

As shown in the figure, the green area is the button part, and the center point of the entire background must be consistent with the coordinates of the mouse movement, so half of its own width and height must be subtracted. Another thing to note is that the background color cannot leak out during the movement, so the background area is twice the size of the entire button.

At this time, the entire background area is very large. The CSS3 blending mode is used here mix-blend-mode: lighten, and only the bright part, which is the green area in the middle, will be applied in the end. The blending mode here plays an important role in the elastic scaling effect in the next step.

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

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

背景弹性交互效果需要增加一个元素,与当前按钮同级别。此时的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填充白色背景,还增加了圆角,此时按钮的背景变成如下所示,按钮的雏形已经有了。

然后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白色背景遮挡了,所以不会完全显示,又因为是白色阴影加上混合模式所以这块区域以亮色白色显示。

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

filter: blur(12px) contrast(50);
复制代码

The filter attribute is used here to process the element. First, the element is blurred. If you just increase the blur effect as follows, you can see that the added pseudo-element circle is smoothed and perfectly integrated into the background color of the button itself.

In addition, contrastadjusting the contrast of the elements can achieve the final effect. Here, remember that the order of execution cannot be reversed. In CSS, functions in filterattributes are executed in order from left to right. If you use multiple functions in filterthe attribute , they will be executed sequentially from left to right.

Button text shadow change

The shadow change of the text is mainly to change its horizontal and vertical offsets, as well as the blur radius. Here we need to use the data of the width and height of the button that was first passed in, because the calculation of the offset will be based on the area of ​​the entire button. This will make it appear more realistic.

First look at the horizontal and vertical offsets. The core is still based on clampfunctions. Set the minimum and maximum values. The recommended value in the middle will change with the coordinates of the mouse. If you are interested in specific values, you can adjust the experience. The following is The code for calculating the horizontal and vertical offsets of the text shadow:

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

Then there is the calculation of the blur radius. The function is used here max, and the maximum value is 5px. In other cases, it is calculated based on the coordinate value and width and height.

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
)
复制代码

The final effect is as follows:

at last

At this point, the entire core implementation process is over. In the entire code, we use attributes such as box-shadow, text-shadow, mix-blend-mode, filterand CSS3 functions max, clamp, calc. There is also transitionno explanation about the animation, and there are many knowledge points involved. Students who are interested can read the source code to understand.

Online code preview:

This is the end of this article. If you find it useful after reading this article, remember to like it and support it. You may use it someday~

Focus on front-end development, share front-end related technology dry goods, public account: Nancheng University Front-end (ID: nanchengfe)

This article is participating in the "Golden Stone Project"

おすすめ

転載: juejin.im/post/7212516589060849720