我闲着没事浏览 CodePen 的 feed,寻找一些赏心悦目的东西,还没翻到第一页就发现了一个由 Adam Argyle 制作的 简洁的 CSS 悬停效果。
我足足盯着演示看了 10 分钟,惊叹不已。它有一种非常像 app 的感觉。我认为可能是因为它在上下文上非常准确,背景颜色从左侧滑入,然后从右侧滑出。这正是我期望从鼠标移入、移出交互中看到的行为。
无论如何,我打开了一个新的 pen,开始着手重现它。它并不超级复杂,而是巧妙地利用了过渡和变换,并搭配了合适的偏移量。非常优雅!我其实有点尴尬,我花了这么长时间才意识到鼠标移出部分是如何工作的。
下面是我解决它的方法,包括所有细节。
background
上的过渡。”
“我敢打赌它使用了 这是我的第一个想法。定义背景颜色,设置 background-size
和 background-position
,然后对 background-position
进行过渡。过去我经常用这种方法实现“扩展”背景颜色。我自己在一些项目中也使用过这种方法,比如这个
如果我能做同样的事情,只是从左到右,那么剩下的就只是鼠标移出,对吧?不。问题在于,没有方法可以真正让 background-position
从左到右再到左到右进行过渡。我可以让它做其中一个,但不能两个都做。
transform
而不是 background
。”
“也许它是一个 我的下一个尝试是转向变换。transform
属性提供了很多函数,可以将它们组合在一起进行过渡,从而实现稍微复杂的运动。例如,background
可以通过改变元素的 scale()
来“扩展”或“收缩”。或者,在这种情况下,可以通过 scaleX()
仅沿 x 轴进行缩放。
但是就像我提到的,没有办法将元素的 background
隔离出来进行这种操作。从 scaleX(0)
到 scaleX(1)
会缩放整个元素,因此它基本上会将链接(包括内容)压缩成零,然后将其拉伸回其自然大小,这完全是不同的效果。此外,这意味着从 scaleX(0)
开始,默认情况下会隐藏整个东西,使其无法使用。
但是伪元素可以工作!它是否会被压缩或隐藏并不重要,因为它不是实际内容的一部分。我们必须将 background
放到它上面,并将其直接放在链接的下方。
a {
/* Keeps the pseudo-element contained to the element */
position: relative;
}
a::before {
background: #ff9800;
content: "";
inset: 0; /* Logical equivalent to physical offsets */
position: absolute;
transform: scaleX(0); /* Hide by default */
z-index: -1; /* Ensures the link is stacked on top */
}
::before
在悬停时发生变化。”
“现在我需要 我知道我可以通过将 ::before
与链接元素的 :hover
状态链接起来,让它从 0
缩放至 1
。
a:hover::before {
transform: scaleX(1)
}
不错!我找到了一些东西。
在上面撒一点 transition
魔法粉,事情就开始变得生动起来。
a::before {
background: #ff9800;
content: "";
inset: 0;
position: absolute;
transform: scaleX(0);
transition: transform .5s ease-in-out;
z-index: -1;
}
“嗯,过渡在两个方向都移动。”
再次,这是我有点卡住的地方。我脑子里的某个地方就是卡住了,不知道为什么。像往常一样,我跑到 CSS-Tricks 年鉴 上查看是否有遗漏的属性。
啊,是的。应该是 transform-origin
。它允许我设置 transform
开始的位置,这与之前尝试设置 background-position
并不完全不同。transform
可以从左侧开始,而不是其默认的 50% 50%
位置。
a::before {
background: #ff9800;
content: "";
inset: 0;
position: absolute;
transform: scaleX(0);
transform-origin: left;
transition: transform .5s ease-in-out;
z-index: -1;
}
是的,就像这样
我已经对链接悬停进行了 ::before
到 scaleX(1)
的过渡。如果我同时将 transform-origin
从 left
反转为 right
,那么也许当鼠标移出时,高亮就会从与进入方向相反的方向移出?
a:hover::before {
transform: scaleX(1);
transform-origin: right;
}
🤞
哎呀,反了!我们交换一下 left
和 right
的值。🙃
太棒了。感谢 Adam 的灵感!
这是一个 使用
background-size
和线性渐变实现的效果 pen。使用背景来做这件事的优势在于,它适用于可能跨越多行的链接,例如散文中的链接文本。在过去几年中,我在很多项目中都使用过这种效果。太棒了!
我感谢这篇文章展示了思维过程,更重要的是,也展示了哪些方法行不通。
很多作者都喜欢成为房间里最聪明的人,他们的答案都是来自神来之笔,所以看到有人分享我的“往墙上扔东西,向前失败”的方法,真是让人耳目一新。
我的意思是,这里有很多问题。
链接基本上必须是一个按钮。在文本块中使用它会破坏它,尤其是当链接文本换行时。
如果你快速地反复悬停它,过渡会跳到最后,然后重新开始。
… 使用边框,或者更好的方法是使用内阴影,并扩展它们的大小,这可能有助于解决第一个问题。
更好的(更紧凑的)过渡语句可能会帮助解决第二个问题。
酷哥。也许你可以写一篇自己的文章,详细介绍你的思维过程,让它变得更好。我会读的。
我第二个支持,如果你写一篇关于如何优化它,我会读的!我非常想用它,我更希望它能尽可能干净。
Graham 先生,
讨厌的人总会讨厌。我真的很喜欢这篇文章。
有趣的是,你只需要使用背景过渡就能实现原始效果!
诀窍是在
background-size
上使用过渡,而不是background-position
。这样,你就可以在背景大小动画开始之前更改背景位置,用户将永远无法察觉,因为背景将始终是完全填充或完全为空!:DCodepen: https://codepen.io/sloanfinger/pen/XWePVGj
哈哈,是的。我的第一反应是正确的,但我发现当我的样式开始变得混乱时,我选择了不同的方法。当然,当我还在
transform
中挣扎时,我开始意识到我在背景方法中犯了什么错误。这就是事后诸葛亮有趣的地方,也是 CSS 的伟大之处——有太多方法可以实现类似的效果。更有趣的是,我最终使用了与 Adam 相同的方法!或者,你可以使用 before。并交换方向
不错 - 我猜你也可以用内嵌的 box-shadows 来实现。唯一的缺点是,你必须为 box-shadow 的宽度设置一个魔法数字。
正如其他人提到的,使用 `background` 和 `background-position` 绝对是最好的方法。我写了一篇关于 5 种不同变体的文章,大家可能会觉得有用 https://nerdcowboy.com/blog/sliding-underlined-links/
我做了一个类似的东西,但它是对角线。
在 2018 年的这篇文章 中详细解释了。
“动画 `transform`,但突然改变 `transform-origin`” 的策略可以帮助你在 3D 中实现很多很酷的效果,就像 2016 年初的这个演示系列一样
blocks
flair
[这个有一个缺点]https://codepen.io/thebabydino/pen/qZJevJ)
a matter of timing
snake motion
一如既往,Ana,太棒了!感谢分享。
我能挑战你同步改变(字体)颜色吗?!
哇,太棒了。只是想知道这是否可以同时改变字体颜色,以便获得完全的 A11y 颜色对比度,同时仍然看起来很棒。
–bg-h: 这意味着什么?