[译]使用 CSS 实现具备方面感知的幽灵按钮

  • Ghost Buttons:幽灵按钮是指具有基本的按钮形状的透明按钮,有细实线的边框。在悬停时背景填充颜色以突出按钮。
  • direction aware:方向感知这里主要说的是可以判断鼠标是从按钮哪一个方向过来的。

本文中,咱们将构建一个幽灵按钮,实现按钮很简单,但有趣而棘手的部分是使按钮背景色从鼠标进入的方向开始填充。css

下面是咱们完成的一个按钮!html

codepen-demoweb

多数状况下,鼠标悬停时,咱们是把 background-color 过渡显示成与边框颜色同样。在某些设计中,按钮可能会从左到右,从上到下等填充,以加强视觉效果。以下例,从左到右填充:测试

codepen-demo动画

若是咱们把鼠标从按钮右侧放上,而填充是从左侧开始,咱们就会感受体验很差!ui

若是按钮从咱们的悬停点开始填充,体验效果会更好。spa

怎么才能使按钮具备方向感知性呢?咱们首先想到的多是使用 JavaScript 来实现,但咱们也能够经过 CSS 配合一些标签来实现。设计

下面咱们能够先看看最终实现的效果:3d

codepen-democode

接下来,咱们把实现步骤分解开来。

基础

咱们先建立一个按钮,很简单!

<button>Boo!</button>
复制代码

咱们使用 CSS 自定义属性完成样式,这样更易于维护。

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

codepen-demo

咱们实现了一个按钮及悬停效果,可是没有填充。咱们继续进行!

添加填充

咱们额外建立元素作为按钮填充时的状态。经过 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);
}
复制代码

codepen-demo

添加方向感知

那么,如何感知方向呢?咱们须要四个要素。每一个元素将负责检测悬停入口点。使用 clip-path,咱们能够将按钮区域分为四个部分。

咱们在按钮里添加四个 span,并放在四个方面以进行填充按钮。

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

codepen-demo

合到一块儿

如今咱们知道如何建立填充动画了,也知道如何判断方向了。那咱们应该如何将它们放到一块儿实现想要的效果呢?答案是同级选择器!

当咱们将鼠标悬停在一方向块上时,咱们能够填充指定的元素。

首先,咱们要更新一下咱们的代码:

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

至此,咱们具备方向感知性的幽灵按钮就实现了。

codepen-demo

可访问性

当按钮不可访问里,会显示以下状态。

这些额外的元素使屏幕阅读器重复阅读了四次。因此,咱们须要将它们隐藏起来。

<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 咱们能够实现具备方向感知性的幽灵按钮。使用预处理器或将它们作为一个组件放在应用里,这样咱们就不用每次都写了。

  1. 这里是一个经过方向感知填充文本效果的例子,实现方式与本文思路基本一致:Direction aware filling text effect
  2. 这篇文章里汇总了好些鼠标悬停判断方向的例子,有纯 CSS 实现的,也有经过 JS 实现的。Direction Aware Hover Effects

译者:Mark Wong

原文:css-tricks.com/ghost-butto…

相关文章
相关标签/搜索