本文中,我们将构建一个幽灵按钮,实现按钮很简单,但有趣而棘手的部分是使按钮背景色从鼠标进入的方向开始填充。
我们可以先看看最终实现的效果:
接下来,我们把实现步骤分解开来。
基础
我们先创建一个按钮,很简单!
<button>Boo!</button>
我们使用 CSS 自定义属性完成样式,这样更易于维护。
web前端开发学习Q-q-u-n: 731771211,分享学习的方法和需要注意的小细节,不停更新最新的教程和学习方法(详细的前端项目实战教学视频,PDF)
button {
--borderWidth: 5;
--boxShadowDepth: 8;
--buttonColor: #f00;
--fontSize: 3;
--horizontalPadding: 16;
--verticalPadding: 8;
background: transparent;
border: calc(var(--borderWidth) * 1px) solid var(--buttonColor);
box-shadow: calc(var(--boxShadowDepth) * 1px) calc(var(--boxShadowDepth) * 1px) 0 #888;
color: var(--buttonColor);
cursor: pointer;
font-size: calc(var(--fontSize) * 1rem);
font-weight: bold;
outline: transparent;
padding: calc(var(--verticalPadding) * 1px) calc(var(--horizontalPadding) * 1px);
transition: box-shadow 0.15s ease;
}
button:hover {
box-shadow: calc(var(--boxShadowDepth) / 2 * 1px) calc(var(--boxShadowDepth) / 2 * 1px) 0 #888;
}
button:active {
box-shadow: 0 0 0 #888;
}
我们实现了一个按钮及悬停效果,但是没有填充。我们继续进行!
添加填充
我们额外创建元素做为按钮填充时的状态。通过 clip-path
将它隐藏。当鼠标悬停在按钮上时设置 clip-path
将元素过渡显示出来。
它们必须与父按钮对齐。这里我们的 CSS 变量会显示出它的优势。
本来我们可以通过伪元素实现,但是它不满足我们需要的四个方面,而且它还会干扰可访问性…稍后我们再讲。
我们先添加一个从左到右填充的效果。首页我们要添加一个 span
标签,它与按钮具有相同的内容。
<button>Boo!
<span>Boo!</span>
</button>
下面我们要将 span
与按钮重叠对齐。
button span {
background: var(--buttonColor);
border: calc(var(--borderWidth) * 1px) solid var(--buttonColor);
bottom: calc(var(--borderWidth) * -1px);
color: var(--bg, #fafafa);
left: calc(var(--borderWidth) * -1px);
padding: calc(var(--verticalPadding) * 1px) calc(var(--horizontalPadding) * 1px);
position: absolute;
right: calc(var(--borderWidth) * -1px);
top: calc(var(--borderWidth) * -1px);
}
最后,我们通过裁剪使元素隐藏,当悬停时更新裁剪规则使元素显示出来。
button span {
--clip: inset(0 100% 0 0);
-webkit-clip-path: var(--clip);
clip-path: var(--clip);
transition: clip-path 0.25s ease;
// ...Remaining div styles
}
button:hover span {
--clip: inset(0 0 0 0);
}
添加方向感知
那么,如何感知方向呢?我们需要四个要素。每个元素将负责检测悬停入口点。使用 clip-path
,我们可以将按钮区域分为四个部分。
我们在按钮里添加四个 span
,并放在四个方面以进行填充按钮。
web前端开发学习Q-q-u-n: 731771211,分享学习的方法和需要注意的小细节,不停更新最新的教程和学习方法(详细的前端项目实战教学视频,PDF)
<button>
Boo!
<span></span>
<span></span>
<span></span>
<span></span>
</button>
button span {
background: var(--bg);
bottom: calc(var(--borderWidth) * -1px);
-webkit-clip-path: var(--clip);
clip-path: var(--clip);
left: calc(var(--borderWidth) * -1px);
opacity: 0.5;
position: absolute;
right: calc(var(--borderWidth) * -1px);
top: calc(var(--borderWidth) * -1px);
z-index: 1;
}
我们将每个元素进行定位并使用 CSS 变量赋予它们背景色及裁剪规则。
button span:nth-of-type(1) {
--bg: #00f;
--clip: polygon(0 0, 100% 0, 50% 50%, 50% 50%);
}
button span:nth-of-type(2) {
--bg: #f00;
--clip: polygon(100% 0, 100% 100%, 50% 50%);
}
button span:nth-of-type(3) {
--bg: #008000;
--clip: polygon(0 100%, 100% 100%, 50% 50%);
}
button span:nth-of-type(4) {
--bg: #800080;
--clip: polygon(0 0, 0 100%, 50% 50%);
}
为了测试,悬停时我们改变一下元素的透明度。
button span:nth-of-type(1):hover,
button span:nth-of-type(2):hover,
button span:nth-of-type(3):hover,
button span:nth-of-type(4):hover {
opacity: 1;
}
哎呀,这里有个问题。如果我们进入并悬停一个分段,然后悬停在另一分段上,则填充方向将会发生变化。这看起来很不对劲。要解决此问题,我们可以在悬停时设置 z-index
和 clip-path
来填充这一空间。
button span:nth-of-type(1):hover,
button span:nth-of-type(2):hover,
button span:nth-of-type(3):hover,
button span:nth-of-type(4):hover {
--clip: polygon(0 0, 100% 0, 100% 100%, 0 100%);
opacity: 1;
z-index: 2;
}
合到一起
现在我们知道如何创建填充动画了,也知道如何判断方向了。那我们应该如何将它们放到一起实现想要的效果呢?答案是同级选择器!
当我们将鼠标悬停在一方向块上时,我们可以填充指定的元素。
首先,我们要更新一下我们的代码:
web前端开发学习Q-q-u-n: 731771211,分享学习的方法和需要注意的小细节,不停更新最新的教程和学习方法(详细的前端项目实战教学视频,PDF)
<button>
Boo!
<span></span>
<span></span>
<span></span>
<span></span>
<b>Boo!</b>
<b>Boo!</b>
<b>Boo!</b>
<b>Boo!</b>
</button>
接下来,我们需要更新一下我们的 CSS,填充样式我们可以复用从左到右的样式。但需要为每个元素设置不同的 clip-path
。我们按第一个在上,第二个在右,第三个在下,第四个在左的顺序设置。
button b:nth-of-type(1) {
--clip: inset(0 0 100% 0);
}
button b:nth-of-type(2) {
--clip: inset(0 0 0 100%);
}
button b:nth-of-type(3) {
--clip: inset(100% 0 0 0);
}
button b:nth-of-type(4) {
--clip: inset(0 100% 0 0);
}
最后一步是鼠标悬停在对应方向块时更新对应元素的 clip-path
。
button span:nth-of-type(1):hover ~ b:nth-of-type(1),
button span:nth-of-type(2):hover ~ b:nth-of-type(2),
button span:nth-of-type(3):hover ~ b:nth-of-type(3),
button span:nth-of-type(4):hover ~ b:nth-of-type(4) {
--clip: inset(0 0 0 0);
}
至此,我们具有方向感知性的幽灵按钮就实现了。
可访问性
当按钮不可访问里,会显示如下状态。
这些额外的元素使屏幕阅读器重复阅读了四次。所以,我们需要将它们隐藏起来。
web前端开发学习Q-q-u-n: 731771211,分享学习的方法和需要注意的小细节,不停更新最新的教程和学习方法(详细的前端项目实战教学视频,PDF)
<button>
Boo!
<span></span>
<span></span>
<span></span>
<span></span>
<b aria-hidden="true">Boo!</b>
<b aria-hidden="true">Boo!</b>
<b aria-hidden="true">Boo!</b>
<b aria-hidden="true">Boo!</b>
</button>
这样就没有重复的内容了。
就是这样
通过额外元素及使用 CSS 我们可以实现具有方向感知性的幽灵按钮。使用预处理器或将它们做为一个组件放在应用里,这样我们就不用每次都写了。
网友评论