发布于 2026-01-06 7 阅读
0

Building an Accessible Reveal-Card answer re: Accessible nested button inside button? DEV's Worldwide Show and Tell Challenge Presented by Mux: Pitch Your Projects!

制作一张易于使用的揭示卡

关于“按钮内部嵌套按钮的可访问性”的回答

由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!

最近,我突然很想创作一些有趣的东西。于是我坐下来浏览Dribbble,看看有没有什么我想做的。我偶然发现了一张卡片,滑动卡片后会显示一些操作按钮,点击即可开始操作。

正如你可能已经猜到的,我将在这篇文章中制作一张揭示卡(我不知道它是否有正式名称),但我必须先声明,我并非无障碍设计专家。我自认为对无障碍设计略知一二,但很可能有些地方出错。如果你发现任何错误,或者想询问我为什么这样做,请随时留言,我会尽快回复。

这就是我要制作的东西。它支持鼠标、触摸和键盘操作,我希望屏幕阅读器也能正确读取它的内容。

揭示卡片的动画

结构

对于我们稍后将在 HTML 中描述的结构,我们需要一个可以通过 Tab 键切换到的基础层,一个用于选项(在本例中为按钮)的图层,以及一个位于选项上方的信息卡,它会遮挡住选项,直到我们将其滑开。

为了实现无障碍设计,我认为基础部分也应该aria-expanded标明该部分可以展开,按钮aria-hidden上也应该有标签或包装器,以防止屏幕阅读器读取它们。

我觉得类似这样的设计符合我的描述,但目前看起来还不太理想。这就自然而然地引出了造型设计这个话题。

外观

外观方面,我将采用典型的 Material Design 设计风格,这意味着我们会使用 Open Sans 字体,按钮是透明圆形,鼠标悬停时会变成半透明,并且整个元素都会添加阴影效果。这样解释起来是不是很简单?以下是 SCSS 代码:

虽然现在看起来勉强过得去,但还有一些问题需要考虑:卡片是白色的,但它的背景也需要颜色,我们真的应该让潜在用户从几种颜色中进行选择;默认轮廓还可以,但在不同的浏览器中显示效果不同,看起来不太好;最后,除了光标变化之外,没有其他任何迹象表明面板是滑动的。

添加变体

您可能已经注意到,在上面的 SCSS 代码中,我使用了BEM,它只是一种样式指南。在 BEM 中,添加变体时,您需要使用 `<variant>` 标签,--后跟变体名称。所以,让我们添加 `success`、`info` 和 `warn` 这三个颜色变体。

因为我们使用的是SCSS,material-slide所以我们可以像这样轻松地将变体添加到我们的样式中。

.material-slide {
  position: relative;
  margin: 0.8em 0;
  border-radius: 4px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
  overflow: hidden;

  &--success {
    background-color: #1B5E20;
    color: #fefefe;
  }

  &--info {
    background-color: #0D47A1;
    color: #fefefe;
  }

  &--warn {
    background-color: #B71C1C;
    color: #fefefe;
  }
}
Enter fullscreen mode Exit fullscreen mode

我已经指定了背景颜色和文本颜色,所以如果有人想在代码中添加新的变体,他们可以遵循这个模式,并在需要时添加对比度更高的颜色。

轮廓优美

这是一个相当有趣的话题,很多无障碍设计纯粹主义者认为应该保留默认轮廓,很长一段时间以来我也同意这种观点,但这些年来我考虑过其他方案,我认为只要让用户知道他们关注的是你的元素,稍微冒险一点也无妨。

我一直以来使用的方法是在 after 中使用 box shadow,不过在这种情况下,我不得不使用 div,它的不透明度为 0,直到元素被选中focus-visible

我们再次将此添加到material-slide样式中。

// inside .material-slide
& .material-slide__outline {
  content: '';
  z-index: 2;
  border-radius: 4px;
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  pointer-events: none;
  box-shadow: inset 0 0 0 1px #fefefe, inset 0 0 0 3px #01579B, inset 0 0 0 4px #fefefe;
  opacity: 0;
}

// inside .material-slide__options
&:focus-visible {
  outline: none;

  & ~ .material-slide__outline {
    opacity: 1;
  }
}
Enter fullscreen mode Exit fullscreen mode

轮廓由三条线组成,两条白线夹着一条蓝线,这样有助于在不同颜色上保持轮廓的可见性。

示例大纲

手势提示

最后说说样式方面,我觉得即使光标变成“抓取”状态,用户也很难一眼看出卡片可以拖动。我仔细考虑了一下,决定当鼠标悬停在卡片上时,卡片应该移动 5 像素,以此来表明卡片可以移动。

为此,我只需添加一个变换,使鼠标悬停在内部即可material-slide__info

&:hover:not(.material-slide__options--user-control) {
  transform: translatex(-5px);
}
Enter fullscreen mode Exit fullscreen mode

你还会注意到,material-slide__options--user-control我们将使用 JS 添加一个类,所以现在让我们继续添加它。

功能

我们已经到了最后一步,添加一些 JavaScript 代码来实现整个功能。这部分主要涉及事件监听器和少量状态管理。我们需要监听键盘事件、鼠标事件和触摸事件。

国家管理

为此,我只需要创建一个包含所有必要变量的对象,然后根据需要更新和检查该对象。

const state = {
  isActive: false,
  isOpen: false,
  isOpenLast: false,
  startPos: null,
  currentPos: null,
}
Enter fullscreen mode Exit fullscreen mode

事件监听器

我需要监听鼠标按下、移动、离开和抬起事件,以便追踪卡片的拖动距离。我还决定添加双击打开和关闭功能,幸运的是,双击事件已经存在。对于键盘操作,我只需要监听按键抬起事件;对于触摸操作,我需要监听触摸开始、移动、结束和取消事件,这些事件与鼠标操作基本相同,但略有不同(因为支持多点触控)。

搁笔

好了,我们做到了。我们制作了一个很棒的小型滑动面板,可以把按钮隐藏在后面。我们让它既方便键盘用户使用,也方便屏幕阅读器读取。

我在考虑是否可以制作这个系列的另一部分,将其转换为 React 组件并发布到 Git/NPM 上,大家对此有兴趣吗?

感谢您阅读到最后,希望您能从中有所收获。正如我在文章开头所说,欢迎留下任何评论,或者来推上和我交流。

再次感谢🧠🧙‍♂️❤️🦄🧠🦄❤️🧠🧙‍♂️🧠🧙‍♂️

文章来源:https://dev.to/link2twenty/building-an-accessible-reveal-card-3c56