你有设想过,当你鼠标移入头像时,展现出从圆圈或洞中探出的那种作用吗?我有相似的想法,但采用了不同的方式并添加了一些动画。我感觉非常实用,并且能够产生简洁的悬停作用,能够在您自己的头像之类的东西上运用。

照例,先看作用!!

【CSS】如何给自己头像打造3D动态悬浮效果?(慎入!有点难)

如何完成

HTML

这个作用的结构元素不多,只需求一行代码就能够。

<img src="" alt="随机头像图片" >

CSS

开端写 CSS 之前,咱们先来剖析一下作用。悬停时图画会变大,因而咱们肯定会transform: scale()在那里运用。头像后边有一个圆圈,径向突变就能够了。最后,咱们需求一种在圆圈底部创立边框的方法,以创立圆圈后边头像的外观。

缩放作用

咱们能够经过添加transform特点来完成缩放作用:

img {
  width: 280px;
  aspect-ratio: 1;
  cursor: pointer;
  transition: .5s;
}
img:hover {
  transform: scale(1.35);
}

那么咱们的作用就会是这样的:

【CSS】如何给自己头像打造3D动态悬浮效果?(慎入!有点难)

圆形

咱们说过布景将是一个径向突变。能够在径向突变的色彩之间创立硬边,使其看起来像是用实线制作的圆形。

img {
  --b: 5px; /* 边框宽度 */
  width: 280px;
  aspect-ratio: 1;
  background:
    radial-gradient(
      circle closest-side,
      #ECD078 calc(99% - var(--b)),
      #C02942 calc(100% - var(--b)) 99%,
      #0000
    );
  cursor: pointer;
  transition: .5s;
}
img:hover {
  transform: scale(1.35);
}

请注意我在那里运用的 CSS 变量 --b。它表明“边框”的厚度,实践上仅仅用于界说径向突变赤色部分的硬色彩中止点。

在这段代码中,咱们首要界说了一个名为 --b 的 CSS 变量,用于表明边框的宽度。然后,咱们设置了图画的宽度和纵横比。

background 特点中,咱们运用 radial-gradient 创立了一个径向突变布景。该 radial-gradient 的参数指定了以下内容:

  • circle closest-side:以离元素最近的边为圆心的圆形突变。
  • #ECD078 calc(99% - var(--b)):从 #ECD078 开端突变,直到元素鸿沟距离到达 99% 减去边框宽度 –b 的方位。
  • #C02942 calc(100% - var(--b)) 99%:从 #C02942 突变到 #0000,从元素鸿沟距离到达 100% 减去边框宽度 –b 的方位,一直到到达 99% 的方位。
  • #0000:最后一个色彩为通明。

这样,咱们运用径向突变完成了一个由两种色彩构成的圆形布景,就像是用实线制作的圆形一样。

一同,咱们依然保留了之前的图画缩放作用,如图!!!

【CSS】如何给自己头像打造3D动态悬浮效果?(慎入!有点难)

下一步是在悬停时调整突变的巨细。圆形需求坚持其巨细不变,即便图画增大。由于咱们运用了 scale() 改换,实践上咱们需求减小圆形的巨细,由于不然它会随着头像的缩放一同增大。因而,在图画缩放的一同,咱们需求使突变缩小。

首要,让咱们界说一个 CSS 变量 --f,用于界说缩放参数,并运用它来设置圆形的巨细。我将默认值设置为 1,由于这是图画和咱们从中进行改换的圆形的初始缩放份额。

下面是一个演示,悬停鼠标能够看到背面发生的事情:

【CSS】如何给自己头像打造3D动态悬浮效果?(慎入!有点难)

我在径向突变中添加了第三个色彩,以更好地标识悬停时突变的区域:

radial-gradient(
  circle closest-side,
  #ECD078 calc(99% - var(--b)),
  #C02942 calc(100% - var(--b)) 99%,
  lightblue
);

现在,咱们需求将布景定位到圆形的中心,并保证它占有整个高度。我喜欢直接在 background 简写特点上声明所有内容,这样咱们能够添加布景定位,并经过在 radial-gradient() 后边添加这些值来保证它不重复:

background: radial-gradient() 50% / calc(100% / var(--f)) 100% no-repeat;

布景被放置在中心方位(50%),宽度等于 calc(100%/var(--f)),高度等于100%

--f 等于1时,没有任何缩放,这是咱们的初始缩放份额。一同,突变占有了容器的整个宽度。当咱们添加 --f 时,元素的巨细会添加——感谢 scale() 改换——而突变的巨细会减小。


为了创立一个完整的圆形,咱们结合了 outline(概括)和突变创立的“边框”。咱们依然需求躲藏概括的部分内容(顶部和侧边),稍后会讲到这一点。

以下是到目前为止的代码,包含一些能够用来装备图片巨细(--s)和“边框”色彩(--c)CSS 变量:

img {
  --s: 280px; /* 图片巨细 */
  --b: 5px; /* 边框厚度 */
  --c: #C02942; /* 边框色彩 */
  --f: 1; /* 初始缩放份额 */
  width: var(--s);
  aspect-ratio: 1;
  cursor: pointer;
  border-radius: 0 0 999px 999px;
  outline: var(--b) solid var(--c);
  outline-offset: calc((1 / var(--f) - 1) * var(--s) / 2 - var(--b));
  background: 
    radial-gradient(
      circle closest-side,
      #ECD078 calc(99% - var(--b)),
      var(--c) calc(100% - var(--b)) 99%,
      #0000
    ) 50% / calc(100% / var(--f)) 100% no-repeat;
  transform: scale(var(--f));
  transition: .5s;
}
img:hover {
  --f: 1.35; /* 悬停时的缩放份额 */
}

由于咱们需求一个圆形的底部边框,咱们在底部添加了一个 border-radius,使得概括能够与突变的曲线相匹配。

outline-offset 中运用的计算实践上比看起来更简单明了。默认情况下,概括是制作在元素框的外部。而在咱们的情况下,咱们需求它与元素堆叠。更精确地说,咱们需求它依照突变创立的圆形来呈现。

【CSS】如何给自己头像打造3D动态悬浮效果?(慎入!有点难)

当咱们对元素进行缩放时,咱们会看到圆形和边际之间的空白。不要忘掉,咱们的想法是在缩放改换运转后坚持圆形的巨细不变,这就给咱们留下了用来界说概括偏移的空间,如上图所示。

不要忘掉第二个元素被缩放了,所以咱们的成果也被缩放了… 这意味着咱们需求将成果除以 f 来获取实践的偏移值:

偏移量 = ((f - 1) * S/2) / f = (1 - 1/f) * S/2 由于咱们需求概括从外部到内部,所以咱们添加了一个负号:

偏移量 = (1/f - 1) * S/2

这一步的作用还是有点差别,可是咱们依然需求底部的概括堆叠在圆形上,而不是让它透过圆形漏出来。咱们能够经过从偏移量中减去边框的巨细来完成:

outline-offset: calc((1 / var(--f) - 1) * var(--s) / 2 - var(--b));

现在咱们需求找到如何从概括中移除顶部部分。换句话说,咱们只想要图片概括的底部部分。

首要,咱们能够经过运用 padding 在顶部添加空间来避免顶部的堆叠:

img {
  --s: 280px; /* 图片巨细 */
  --b: 5px;   /* 边框厚度 */
  --c: #C02942; /* 边框色彩 */
  --f: 1; /* 初始缩放份额 */
  width: var(--s);
  aspect-ratio: 1;
  padding-block-start: calc(var(--s)/5);
  /* 其他特点 */
}
img:hover {
  --f: 1.35; /* 悬停时的缩放份额 */
}

经过在顶部添加 padding-block-start,咱们为顶部留出了一些空间,避免了堆叠。

这个顶部的 padding 没有特定的逻辑。主要是为了保证概括不会触碰到头像的头部。我运用元素的巨细来界说这个空间,以坚持相同的份额。

在布景中添加了 content-box 的值:

background:
  radial-gradient(
    circle closest-side,
    #ECD078 calc(99% - var(--b)),
    var(--c) calc(100% - var(--b)) 99%,
    #0000
  ) 50%/calc(100%/var(--f)) 100% no-repeat content-box;

咱们需求这么做是由于咱们添加了 padding,咱们只想让布景设置到内容盒子(content box),所以咱们有必要清晰告诉布景中止在那里。

接下来咱们将运用 mask 特点来躲藏一些部分。为此,咱们将依赖于突变。以下是一个图示,阐明咱们需求躲藏或显示的部分:

【CSS】如何给自己头像打造3D动态悬浮效果?(慎入!有点难)

左图是咱们目前的姿态,右图是咱们想要的姿态。绿色部分表明咱们有必要运用于原始图画的遮罩(mask),以取得终究成果。

咱们能够确认遮罩的两个部分:

底部的圆形部分具有与咱们用来创立头像后边的圆形突变相同的尺寸和曲率。 顶部的矩形部分覆盖了概括内的区域。请注意,概括在顶部的绿色区域之外 – 这是最重要的部分,由于它答应概括被剪切,只显示底部部分。

下面是咱们最最最后的 CSS 代码:

img {
  --s: 280px; /* 图片尺寸 */
  --b: 5px; /* 边框厚度 */
  --c: #C02942; /* 边框色彩 */
  --f: 1; /* 初始缩放份额 */
  --_g: 50% / calc(100% / var(--f)) 100% no-repeat content-box;
  --_o: calc((1 / var(--f) - 1) * var(--s) / 2 - var(--b));
  width: var(--s);
  aspect-ratio: 1;
  padding-top: calc(var(--s)/5);
  cursor: pointer;
  border-radius: 0 0 999px 999px;
  outline: var(--b) solid var(--c);
  outline-offset: var(--_o);
  background: 
    radial-gradient(
      circle closest-side,
      #ECD078 calc(99% - var(--b)),
      var(--c) calc(100% - var(--b)) 99%,
      #0000) var(--_g);
  mask:
    linear-gradient(#000 0 0) no-repeat
    50% calc(-1 * var(--_o)) / calc(100% / var(--f) - 2 * var(--b)) 50%,
    radial-gradient(
      circle closest-side,
      #000 99%,
      #0000) var(--_g);
  transform: scale(var(--f));
  transition: .5s;
}
img:hover {
  --f: 1.35; /* 鼠标悬停时的缩放份额 */
}

让咱们解析一下 mask 特点。首要,注意到其间包含了与 background 特点中的 radial-gradient() 相似的部分。我创立了一个新的变量 –_g,以减少代码的混乱程度。

--_g: 50% / calc(100% / var(--f)) 100% no-repeat content-box;
mask:
  radial-gradient(
    circle closest-side,
    #000 99%,
    #0000) var(--_g);

接下来,还有一个 linear-gradient():

--_g: 50% / calc(100% / var(--f)) 100% no-repeat content-box;
mask:
  linear-gradient(#000 0 0) no-repeat
    50% calc(-1 * var(--_o)) / calc(100% / var(--f) - 2 * var(--b)) 50%,
  radial-gradient(
    circle closest-side,
    #000 99%,
    #0000) var(--_g);

这创立了遮罩的矩形部分。它的宽度等于径向突变的宽度减去两倍的边框厚度:

calc(100% / var(--f) - 2 * var(--b))

该矩形的高度等于元素尺寸的一半,即 50%

咱们还需求将线性突变放置在水平中心(50%)并从顶部偏移与概括的偏移值相同的方位。我创立了另一个 CSS 变量 --_o,用于之前界说的偏移量:

--_o: calc((1 / var(--f) - 1) * var(--s) / 2 - var(--b));

这里有一个令人困惑的地方是,咱们需求对概括运用负偏移(将其从外部移到内部),但对突变运用正偏移(从顶部移到底部)。所以,假如你想知道为什么咱们将偏移值 --_o乘以 -1,现在你就知道了!

看下面演示,用于阐明遮罩突变的装备:

【CSS】如何给自己头像打造3D动态悬浮效果?(慎入!有点难)

把鼠标悬停在上面,看看所有东西是如何一同移动的。中心的方框是由两个突变组成的遮罩层。幻想它是左图画的可见部分,你就能得到右边的终究成果!

总结一下

咱们完成了一个漂亮的悬停动画,并且只用了一个 HTML 的 img标签 元素和不到 20 行 CSS 就完成了。

当然,咱们依靠了一些小技巧和数学公式来完成这种杂乱作用。可是咱们事先就知道应该做什么,由于咱们确认了需求的各个部分。(干事之前多剖析)

假如咱们答应运用更多的 HTML,咱们是否能够简化 CSS?当然能够。可是咱们在这里是为了学习新的 CSS 技巧!这是一个很好的练习,能够探究 CSS 突变遮罩outline 特点的行为、变形等等。假如你在任何时候感到苍茫,那么一定要检查我系列文章中运用相同的基本概念的比如。有时候看到更多的示例和用例有助于加深理解。

本文同步我的技术文档