简要介绍如何构建颜色自适应、响应迅速且可访问的 FAB 组件。
在这篇博文中,我想分享我对如何构建颜色自适应、响应迅速且可访问的 FAB 组件的看法。试用演示版并查看源代码!
如果你更喜欢视频,可以参考本博文的 YouTube 版本:
概览
FAB 在移动设备上比桌面设备更常见,但在这两种场景中都很常见。它们始终显示主要操作,方便且无处不在。这种用户体验风格因 Material 界面而出名,如需查看它们的使用和放置位置建议,请点击此处。
元素和样式
这些控件的 HTML 涉及一个容器元素以及一组(一个或多个)按钮。容器会将 FAB 放置在视口内并管理按钮之间的间隙。这些按钮可以是迷你按钮,也可以是默认按钮,主要操作和次要操作之间可以有很大差异。
FAB 容器
此元素可以是常规的 <div>
,但对于视力不佳的用户,我们不妨使用一些有用的属性来标记该元素,以说明此容器的用途和内容。
FAB 标记
先从 .fabs
类入手,让 CSS 接入 CSS 以设定样式,然后添加 role="group"
和 aria-label
,这样它不仅仅是一个通用容器,而且具有命名和目的性。
<div class="fabs" role="group" aria-label="Floating action buttons">
<!-- buttons will go here -->
</div>
FAB 样式
为使用方便,FAB 始终固定在视口内。这是位置 fixed
的一个很好的用例。在此视口位置中,我选择了使用 inset-block
和 inset-inline
,以便位置与用户的文档模式相称,例如从右到左或从左到右。自定义属性还用于防止重复,并确保与视口的底部边缘和侧边缘的距离相等:
.fabs {
--_viewport-margin: 2.5vmin;
position: fixed;
z-index: var(--layer-1);
inset-block: auto var(--_viewport-margin);
inset-inline: auto var(--_viewport-margin);
}
接下来,为容器提供 flex
属性,并将其布局方向更改为 column-reverse
。这会将子项堆叠在一起(列),并反转其视觉顺序。这样做的效果是使第一个可聚焦元素成为底部元素,而不是顶部元素;根据 HTML 文档,焦点通常位于顶部。颠倒视觉顺序可为视力正常的用户和键盘用户提供更好的体验,因为主要操作的样式大于迷你按钮,向视力正常的用户表明该操作是主要操作,键盘用户将焦点设为源中的第一项。
.fabs {
…
display: flex;
flex-direction: column-reverse;
place-items: center;
gap: var(--_viewport-margin);
}
居中是通过 place-items
处理的,而 gap
会在容器中的所有 FAB 按钮之间增加空间。
悬浮操作按钮按钮
现在,我们来设置一些按钮的样式,使其看起来像悬浮在所有内容之上。
默认悬浮操作按钮
第一个要设置样式的按钮是默认按钮。这将作为所有 FAB 按钮的基础。稍后,我们将创建一个变体来实现替代外观,同时尽可能减少修改这些基本样式。
FAB 标记
<button>
元素就是合适的选择。首先我们将它作为基础,因为它提供出色的鼠标、触摸和键盘用户体验。这种标记最重要的方面是使用 aria-hidden="true"
向屏幕阅读器用户隐藏图标,并向 <button>
标记本身添加必要的标签文本。在这些情况下添加标签时,我还喜欢添加 title
,以便鼠标用户可以了解图标希望传达的信息。
<button data-icon="plus" class="fab" title="Add new action" aria-label="Add new action">
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">...</svg>
</button>
悬浮操作按钮样式
首先,我们将按钮转换为带有强烈阴影且带有内边距的圆形按钮,因为这些是按钮的第一个定义功能:
.fab {
--_size: 2rem;
padding: calc(var(--_size) / 2);
border-radius: var(--radius-round);
aspect-ratio: 1;
box-shadow: var(--shadow-4);
}
接下来,我们来添加颜色。我们将使用之前在 GUI 挑战中使用的策略。 创建一组明确命名的自定义属性(用于静态保存浅色和深色),然后创建一个自适应自定义属性,该属性将根据用户系统对颜色的偏好设置为浅色或深色变量:
.fab {
…
/* light button and button hover */
--_light-bg: var(--pink-6);
--_light-bg-hover: var(--pink-7);
/* dark button and button hover */
--_dark-bg: var(--pink-4);
--_dark-bg-hover: var(--pink-3);
/* adaptive variables set to light by default */
--_bg: var(--_light-bg);
/* static icon colors set to the adaptive foreground variable */
--_light-fg: white;
--_dark-fg: black;
--_fg: var(--_light-fg);
/* use the adaptive properties on some styles */
background: var(--_bg);
color: var(--_fg);
&:is(:active, :hover, :focus-visible) {
--_bg: var(--_light-bg-hover);
@media (prefers-color-scheme: dark) {
--_bg: var(--_dark-bg-hover);
}
}
/* if users prefers dark, set adaptive props to dark */
@media (prefers-color-scheme: dark) {
--_bg: var(--_dark-bg);
--_fg: var(--_dark-fg);
}
}
接下来,添加一些样式,以帮助 SVG 图标适应空间大小。
.fab {
…
& > svg {
inline-size: var(--_size);
block-size: var(--_size);
stroke-width: 3px;
}
}
最后,从该按钮中移除点按突出显示标记,因为我们添加了自己的互动视觉反馈:
.fab {
-webkit-tap-highlight-color: transparent;
}
迷你 FAB
本部分的目标是为 FAB 按钮创建一个变体。通过将一些 FAB 设置为小于默认操作,我们可以提升用户最常执行的操作。
迷你 FAB 标记
HTML 与 FAB 相同,但我们添加了“.mini”类,为 CSS 提供与变体中的钩子。
<button data-icon="heart" class="fab mini" title="Like action" aria-label="Like action">
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">...</svg>
</button>
迷你 FAB 样式
由于使用了自定义属性,唯一需要的更改是调整 --_size
变量。
.fab.mini {
--_size: 1.25rem;
}
无障碍功能
对于悬浮操作按钮的无障碍功能,要谨记最重要的一点是将其放置在页面的键盘流中。此演示仅包含 FAB,在键盘顺序和流方面没有可竞争的差异,这意味着它没有机会演示有意义的键盘流。在存在焦点竞争元素的场景中,我建议您深入思考用户应在该流程中的什么位置进入 FAB 按钮流程。
用户聚焦到 FAB 容器后,我们已经添加了 role="group"
和 aria-label="floating action buttons"
,用于告知屏幕阅读器用户他们聚焦的内容。我已巧妙地将默认的 FAB 放置在首位,让用户最先找到主要操作。然后,我使用 flex-direction: column-reverse;
直观地对底部的主按钮进行排序,使其靠近用户手指的位置,以便于使用。这是一项非常实用的功能,因为默认按钮在视觉上非常醒目,对于键盘用户来说也是最先显示按钮,从而为他们提供非常相似的体验。
最后,别忘了对屏幕阅读器用户隐藏图标,并确保为其提供按钮标签,这样才不会成为谜团。这已经在 HTML 中通过 <svg>
上的 aria-hidden="true"
和 <button>
上的 aria-label="Some action"
完成。
动画
您可以添加各种类型的动画,以增强用户体验。与其他 GUI 挑战一样,我们将设置几个自定义属性,以实现减少动作体验和全动作体验的意图。默认情况下,样式会假定用户想要减少动作,然后使用 prefers-reduced-motion
媒体查询将过渡值切换为完整动作。
具有自定义属性的减少动画策略
可以在以下 CSS 中创建了三个自定义属性:--_motion-reduced
、--_motion-ok
和 --_transition
。根据用户的偏好设置,前两个变量会保持适当的转换,最后一个变量 --_transition
将分别设置为 --_motion-reduced
或 --_motion-ok
。
.fab {
/* box-shadow and background-color can safely be transitioned for reduced motion users */
--_motion-reduced:
box-shadow .2s var(--ease-3),
background-color .3s var(--ease-3);
/* add transform and outline-offset for users ok with motion */
--_motion-ok:
var(--_motion-reduced),
transform .2s var(--ease-3),
outline-offset 145ms var(--ease-2);
/* default the transition styles to reduced motion */
--_transition: var(--_motion-reduced);
/* set the transition to our adaptive transition custom property*/
transition: var(--_transition);
/* if motion is ok, update the adaptive prop to the respective transition prop */
@media (prefers-reduced-motion: no-preference) {
--_transition: var(--_motion-ok);
}
}
完成上述操作后,就可以转换对 box-shadow
、background-color
、transform
和 outline-offset
的更改,从而为用户提供良好的界面反馈,表明他们的互动已收到。
接下来,通过稍微调整 translateY
来为 :active
状态添加一点装饰,从而为按钮带来不错的按下效果:
.fab {
…
&:active {
@media (prefers-reduced-motion: no-preference) {
transform: translateY(2%);
}
}
}
最后,转换对按钮中的 SVG 图标所做的任何更改:
.fab {
…
&[data-icon="plus"]:hover > svg {
transform: rotateZ(.25turn);
}
& > svg {
@media (prefers-reduced-motion: no-preference) {
will-change: transform;
transition: transform .5s var(--ease-squish-3);
}
}
}
总结
现在你已经知道我是怎么做的,希望你怎么办 ‽ 🙂?
让我们来了解一下我们采用的方法多样化,并了解在 Web 上构建网站的所有方法。
只需创建一个演示,点击 tweet me 链接,我就会将其添加到下方的“社区混剪”部分中!
社区混剪作品
此处尚无可显示的内容。
资源
- GitHub 上的源代码