Ghost Buttons: 幽灵按钮是指具备基本的按钮形状的透明按钮, 有细实线的边框. 在悬停时背景填充颜色以突出按钮.
direction aware: 方向感知这里主要说的是能够判断鼠标是从按钮哪个方向过来的.
本文中, 我们将构建一个幽灵按钮, 实现按钮很简单, 但有趣而棘手的部分是使按钮背景色从鼠标进入的方向开始填充.
下面是我们完成的一个按钮!
codepen-demo
多数情况下, 鼠标悬停时, 我们是把 background-color 过渡显示成与边框颜色一样. 在某些设计中, 按钮可能会从左到右, 从上到下等填充, 以增强视觉效果. 如下例, 从左到右填充:
codepen-demo
如果我们把鼠标从按钮右侧放上, 而填充是从左侧开始, 我们就会感觉体验不好!
image
<figcaption></figcaption>
如果按钮从我们的悬停点开始填充, 体验效果会更好.
image
<figcaption></figcaption>
怎么才能使按钮具有方向感知性呢? 我们首先想到的可能是使用 JavaScript 来实现, 但我们也可以通过 CSS 配合一些标签来实现.
下面我们可以先看看最终实现的效果:
codepen-demo
接下来, 我们把实现步骤分解开来.
基础
我们先创建一个按钮, 很简单!
<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 将元素过渡显示出来.
image.PNG
它们必须与父按钮对齐. 这里我们的 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, 我们可以将按钮区域分为四个部分.
image.PNG
我们在按钮里添加四个 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;
- }
0.gif
哎呀, 这里有个问题. 如果我们进入并悬停一个分段, 然后悬停在另一分段上, 则填充方向将会发生变化. 这看起来很不对劲. 要解决此问题, 我们可以在悬停时设置 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;
- }
- 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
可访问性
当按钮不可访问里, 会显示如下状态.
image.PNG
这些额外的元素使屏幕阅读器重复阅读了四次. 所以, 我们需要将它们隐藏起来.
- <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 我们可以实现具有方向感知性的幽灵按钮. 使用预处理器或将它们做为一个组件放在应用里, 这样我们就不用每次都写了.
这里是一个通过方向感知填充文本效果的例子, 实现方式与本文思路基本一致: Direction aware filling text effect
这篇文章里汇总了好些鼠标悬停判断方向的例子, 有纯 CSS 实现的, 也有通过 JS 实现的. Direction Aware Hover Effects
年初整理了一批 Web 前端教程, 帮助想要成为 Web 前端程序员的人. 从零基础到各种框架的教程都有. 只需要加入到 Web 前端学习 qun:296,212,562. 即可免费领取, 学习过程中有任何问题可以在里面问. 种一颗树最好的时间是十年前, 其次是现在. 只要想学习, 不存在早晚.
来源: http://www.jianshu.com/p/7f3a904b8444