日常开发过程中,会遇到不少按钮鼠标悬停的效果,实现这类悬停效果的方式有很多,借助伪元素,CSS3变换及过渡等都可以实现。今天的文章将使用背景色实现类似的效果,当我们遇到一个问题时,你的脑海中的方案不止一种时,我想这肯定是极好的,使用不同的方法达到同一的效果,或者某天所遇到的问题就迎刃而解了。
今天主要实现的鼠标悬停效果如下GIF图所示。
悬停效果一
上图所示的效果代码如下所示,只需要4行代码即可实现效果,是否很惊讶代码为何如此精简,接下来将详细说明是如何做到的。
.hover-1 {
background: linear-gradient(#1095c1 0 0) var(--p, 0) / var(--p, 0) no-repeat;
transition: .4s, background-position 0s;
}
.hover-1:hover {
--p: 100%;
color: #fff;
}
首先,我们从一个简单的background-size
过渡开始,如上图所示,背景色的高度是一直保持100%,我们只需要改变其宽度从0%到100%之间的切换。因为使用了background-size
改变宽度,所以使用 background-image: linear-gradient
设置背景色。因为只有一个颜色值,使用此#1095c1 0 0
简写方式,不需要写两个色值。
background-image: linear-gradient(#1095c1 0 0);
使用background-size时,我们可以省略高度,因为默认情况下渐变是全高。我们使用background-size: 0
过渡到background-size: 100%
。
.hover-1 {
background-size: 0;
}
.hover-1:hover {
background-size: 100%;
}
进一步优化,引入一个自定义属性以避免重复background-size
,--p
最初没有定义,因此将使用0%
。在悬停时,我们定义--p
为100%
替换初始值0%
.hover-1 {
background-size: var(--p, 0%);
}
.hover-1:hover {
--p: 100%;
}
到此我们的效果如下所示
接下来引入background-position
实现反转的效果,看最开始的GIF图可以分开2步完成。
- 鼠标悬停时背景是从右往左增加尺寸
- 鼠标移出时背景是从左往右减小尺寸
并且在悬停时不能增加transition
过渡动画,此属性是需要及时生效的,所以增加了background-position 0s
。
.hover-1 {
background-position: left;
transition: .4s,background-position 0s;
}
.hover-1:hover {
--p: 100%;
background-position: right;
}
还可以进一步优化,background-position
的值使用百分比。
.hover-1 {
background-position: 0%;
transition: .4s,background-position 0s;
}
.hover-1:hover {
--p: 100%;
background-position: 100%;
}
聪明的你可能已经发现了,悬停时的两个值都是100%,那么我们可以进一步优化都使用自定义属性--p
。
.hover-1 {
background: linear-gradient(#1095c1 0 0) no-repeat;
transition: .4s,background-position 0s;
background-size: var(--p, 0%);
background-position: var(--p, 0%);
}
.hover-1:hover {
--p: 100%;
}
针对 background
我们使用复合写法,进一步精简代码,使用 /
做分割,前面是 background-position
后面是 background-size
。
.hover-1 {
background: linear-gradient(#1095c1 0 0) var(--p, 0%) / var(--p,0%) no-repeat;
transition: .4s, background-position 0s;
}
.hover-1:hover {
--p: 100%;
}
到此就完整的实现悬停效果一且精简了代码,基于此设计,还可以稍微改动代码让悬停效果达到相反的效果,修改background-position
从100% 到 0%,而不是上面的 0% 到 100%。为了保持 --p
自定义属性不变,我们使用calc()
函数处理。
background: linear-gradient(#1095c1 0 0) calc(100% - var(--p,0%)) / var(--p,0%) no-repeat;
悬停效果二
如上图所示,相比较效果一更为复杂,整个效果是由多个动画步骤组成。最开始的背景区域在可视区域之外,从左往右移动到覆盖到整个元素底部,然后改变背景色到高度到100%覆盖到整个元素。
这里需要使用到background-position
的百分比使用方式,不理解其使用方式的话可以看看文末的参考文章。诀窍是将宽度改为200%,但不用担心背景色超出后的溢出问题,对于元素溢出的背景色都是隐藏的,代码如下。
.hover-2 {
background-image: linear-gradient(#1095c1 0 0);
background-size: 200% .08em;
background-position: 200% 100%;
background-repeat: no-repeat;
transition: background-size .3s, background-position .3s .3s;
}
.hover-2:hover {
transition: background-size .3s .3s, background-position .3s;
background-size: 200% 100%;
background-position: 100% 100%;
}
然后继续开始优化代码,首先使用background
的复合写法精简,减少额外的声明。
.hover-2 {
background:
linear-gradient(#1095c1 0 0) no-repeat
var(--p, 200%) 100% / 200% var(--p, .08em);
transition: .3s var(--t, 0s), background-position .3s calc(.3s - var(--t, 0s));
}
.hover-2:hover {
--p: 100%;
--t: .3s;
}
这里增加一个自定义变量--t
,在鼠标悬停时,我们设置为.3s,最终代码如下:
transition: .3s .3s, background-position .3s 0s;
鼠标移出时,--t
未定义,最终代码如下:
transition: .3s 0s, background-position .3s .3s;
到此为止,鼠标悬停时声明了两个变量,我们还可以进一步优化,通过一个属性更新多个属性,关于如何生成这样的代码可以看文末的参考链接,最终代码修改如下:
.hover-2 {
background:
linear-gradient(#1095c1 0 0) no-repeat
calc(200% - var(--i, 0) * 100%) 100% / 200% calc(100% * var(--i, 0) + .08em);
transition: .3s calc(var(--i, 0) * .3s), background-position .3s calc(.3s - calc(var(--i, 0) * .3s));
}
.hover-2:hover {
--i: 1;
}
--i
最终是未定义则是0,悬停时更新为1,该变量就如同在JS中的一个开关变量,到此为止,整个效果只需要三行css声明完成。
悬停效果三
此效果在效果二的基础上扩展为两个渐变动画效果,最初会有两个渐变溢出的元素,默认都不在视野范围内,每一个的宽度为整个元素的一半。当我们鼠标移入的时候修改这两个溢出的元素到可见区域,第一个渐变位于左下角,第二个渐变位于右上角,最后增加高度覆盖到整个元素。
初始CSS代码如下,与效果二的代码几乎相同,唯一的区别就是具有两个不同的位置同时发生动画效果,这里同样用到了百分比的background-position
。
.hover-3 {
background-image:
linear-gradient(#1095c1 0 0),
linear-gradient(#1095c1 0 0);
background-repeat: no-repeat;
background-size: 50% .08em;
background-position:
-100% 100%,
200% 0;
transition: background-size .3s, background-position .3s .3s;
}
.hover-3:hover {
background-size: 50% 100%;
background-position:
0 100%,
100% 0;
transition: background-size .3s .3s, background-position .3s;
}
接下来开始优化代码,background
复合写法,自定义属性以及calc()进一步整理,这里新增了一个额外的--c自定义属性,因为在background
中用到了两次。
.hover-3 {
--c: no-repeat linear-gradient(#1095c1 0 0);
background:
var(--c) calc(-100% + var(--p, 0%)) 100% / 50% var(--p, .08em),
var(--c) calc( 200% - var(--p, 0%)) 0 / 50% var(--p, .08em);
transition: .3s var(--t, 0s), background-position .3s calc(.3s - var(--t, 0s));
}
.hover-3:hover {
--p: 100%;
--t: 0.3s;
}
接下来使用开关变量进一步优化,只有一个变量--i
.hover-3 {
--c: no-repeat linear-gradient(#1095c1 0 0);
background:
var(--c) calc(-100% + var(--i, 0) * 100%) 100% / 50% calc(100% * var(--i, 0) + .08em),
var(--c) calc( 200% - var(--i, 0) * 100%) 0 / 50% calc(100% * var(--i, 0) + .08em);
transition: .3s calc(var(--i, 0) * .3s), background-position .3s calc(.3s - var(--i, 0) * .3s);
}
.hover-3:hover {
--i: 1;
}
悬停效果四
这个效果相对于上面的难度较大,更多的用到了圆锥渐变和更多的计算。主要可以分为以下几个步骤:
- 有左右两个圆锥渐变在元素可视区外
- 鼠标移入增加两个圆锥渐变的宽度,直到覆盖元素
- 改变整个背景区域的位置,这也是最重要的步骤
- 改变后的位置,因为两个圆锥渐变是同一个颜色,所以视觉上没有任何变化
- 鼠标移出减小圆锥渐变的宽度,则可以看到反差后的动画
两个渐变都需要有默认的0宽度和两倍的元素高度(0% 200%),每个渐变的配置如下图所示:
background-image:
conic-gradient(from -135deg at 100% 50%, var(--c) 90deg, #0000 0),
conic-gradient(from -135deg at 1.2em 50%, #0000 90deg, var(--c) 0);
视觉上,每个渐变的宽度都是元素的一半,但是实际上并不止,因为有锥形的空隙。所以需要在一半宽度的基础上额外增加一定的数值,这个值可以大一点,以便覆盖到整个元素。
.hover-4:hover {
background-size: calc(50% + .6em) 200%;
}
优化后的代码如下:
.hover-4 {
--c: #1095c1;
line-height: 1.2em;
background:
conic-gradient(from -135deg at 100% 50%, var(--c) 90deg, #0000 0)
0 var(--p, 0%) / var(--s, 0%) 200% no-repeat,
conic-gradient(from -135deg at 1.2em 50%, #0000 90deg, var(--c) 0)
100% var(--p, 0%) / var(--s, 0%) 200% no-repeat;
transition: .4s, background-position 0s;
}
.hover-4:hover {
--p: 100%;
--s: calc(50% + .6em);
}
总结
以上总共分析了四种悬停效果,虽然效果不同,但主要都用到了 CSS background
属性、自定义属性和calc()
,不同的组合情况制作出来不同的效果,但是最后的代码都是类似,最终有了极其简洁可维护的代码。基于此,这只是冰山一角,现代CSS的强大还可以产出各种神奇的效果。你是否有想法来试试呢~
看到最后如果觉得有用,点赞,关注,收藏起来吧,说不定哪天就用上啦~
专注前端开发,分享前端相关技术干货,公众号:南城大前端(ID: nanchengfe)
码上掘金
https://code.juejin.cn/pen/7112367614185177102
参考
dry-switching-with-css-variables-the-difference-of-one-declaration
using-percentage-values-with-background-position-on-a-linear-gradient
暂无评论