立即行动以使您的React网站可访问

2020年12月30日11:18:03 发表评论 34 次浏览

本文概述

这个词还没有得到解决, 可访问性通常是数月甚至数年Web开发的附录。Webaim要求这个报告97.8%的主页出现WCAG 2故障。 Webaim确实提供工具来审核网站的可访问性问题, 因此他们确实对这些数字有既得利益, 但是有一些真相。

我不在乎各种WCAG 2.x标准。人们以这些标准为借口, 竭尽全力使网站变得可访问。我关心的是辅助技术的实际用户可以验证我们开发的内容是否可访问。如果我们与辅助技术的实际用户进行测试, 那么他们可以告诉我们什么在起作用, 什么在不起作用。当前的自动辅助功能工具产品尚无法做到这一点。

用现代的JavaScript框架(例如)创建的单页应用程序React为网站的访问增加了很多复杂性。当用户单击链接时, 不会向服务器请求新的HTML。取而代之的是, 狡猾的JavaScript骗术用新内容替换了旧内容, 并更改了地址栏URL。除非你采取适当的措施, 否则辅助技术很可能不会意识到这一变化。

成为解决方案的一部分, 而不是问题

我现在将概述一些简单的步骤, 你可以通过这些简单的步骤来使React网站更易于访问。

使用正确的HTML元素和属性(也可以使用语义HTML)

BREAK!编写语义HTML只需花费div元素的平面集合即可。

按住首页。通过使用正确的HTML元素和属性, 可以使你的网站更易于使用辅助技术!谁知道?

地球上谁在使用正确的HTML和属性?这似乎很疯狂, 但它发生的次数很多, 甚至在我黑暗的过去, 甚至不止一次, 创造了一个可点击的div元素而不是使用按钮, 或者流氓输入不受描述性标签元素的陪伴。让我们大家都指出现在要做正确的事情。

始终确保页面内容按逻辑顺序排列, 并且在页面加载后不依赖CSS或JavaScript对内容进行重新排序

关于可访问性, 我曾经收到的最好的建议之一就是布局HTML, 就像CSS不存在一样。如果你的主要布局是这样, 领先的屏幕阅读器将有很大的机会让你轻松浏览标记:

<html>
   <body>
     <header role="banner">
       <p>Put company logo, etc. here.</p>
     </header>
     <nav role="navigation">
       <ul>
         <li>Put navigation here</li>
       </ul>
     </nav>
     <main role="main">
       <p>Put main content here.</p>
     </main>
     <footer role="contentinfo">
       <p>Put copyright, etc. here.</p>
     </footer>
  </body>
</html>

正确的HTML界标元素和角色属性的组合允许屏幕阅读器的用户在界标区域中导航, 例如标头, 主要和页脚。屏幕阅读器会识别这些标记的区域, 并提供快捷键来查找它们……..如果它们存在。这里有一个视频显示屏幕阅读器如何拾取地标区域。

使用布局组件, 并在所有组件中使用语义HTML

我非常热衷于React中的布局组件, 因此我创建了这个CodeSandbox显示一个布局组件包装了应用程序中的所有组件:

const Layout = ({ children }) => (
  <React.Fragment>
    <header role="banner">
      <Logo />
    </header>
    <nav role="navigation">
      <Link to="/">Home</Link> <Link to="dashboard">Dashboard</Link>
    </nav>
    <main role="main">{children}</main>
    <footer role="contentinfo">
      <p>Put copyright, etc. here.</p>
    </footer>
  </React.Fragment>
);

const App = ({ children }) => (
  <React.Fragment>
    <Layout>
      <Router>
        <Home path="/" />
        <Dashboard path="dashboard" />
      </Router>
    </Layout>
  </React.Fragment>
);

const Home = () => (
  <div>
    <h2>Welcome</h2>
  </div>
);

const Dashboard = () => (
  <div>
    <h2>Dashboard</h2>
  </div>
);

的布局组件包装应用程式零件。你无需将语义标记添加到任何其他组件。

我们为制作了一个自定义演示.
不完全是。点击这里查看.

立即行动以使您的React网站可访问1

标题

标题又属于使用正确的HTML元素和属性的范畴。标题告诉屏幕阅读器页面内容的组织方式, 从而为用户提供内容概述。避免跳过标题, 因为这会使屏幕阅读器感到困惑。

我在披露苏格兰网站, 这是一个类似向导的多个步骤。表格的每一步都有一<h1>元素清楚地说明了该步骤的意图。

标题

清楚地标记了h1 HTML元素

在每次页面转换或路线更改时, 焦点都移到新内容的顶部, 并且屏幕阅读器会读取描述步骤目的的h1元素, 这使我迅速了解了路由器在React应用程序中应如何表现。

集中管理路线过渡

SPA(单页应用程序)的最初吸引力在于, 它不需要去服务器呈现新内容。问题在于, 新创建的服务器呈现的页面与屏幕阅读器配合使用非常好, 但是当你在SPA中更改路由时, 屏幕阅读器不知道有新内容。

幸运的是, 在反应生态系统中到达路由器为我们解决了这个问题。

如果你正在使用反应路由器那么我创建了这个挂钩, 它将把焦点放在每个页面过渡上。

import { usePrevious } from "./usePrevious";
import { useLayoutEffect } from "react";
import { useLocation } from "react-router-dom";

export const useScrollToTop = ({ ref }:{
  ref
}) => {
  const { pathname } = useLocation();
  const previousPathname = usePrevious(pathname);

  useLayoutEffect(() => {
    if (pathname === previousPathname || !ref?.current) {
      return;
    }

    window.scrollTo(0, 0);

    const clearTimer = setTimeout(() => {
      ref.current.focus();
    }, 100);

    return () => {
      clearTimeout(clearTimer);
    };
  }, [pathname, previousPathname, ref]);
};

我创建了一个CodeSandbox展示了钩子的作用。每个页面在页面底部都有一个链接, 单击该链接将调用该挂钩。 Hook跟踪当前URL, 然后检查新的导航更改, 如果它们不匹配, 则Hook滚动到页面顶部, 并将焦点放在存储在React中的HTML元素上参考.

键盘导航

由于我们现在有了语义HTML, 路由器和检测路线更改的容器组件, 因此, 我们应确保可以在需要聚焦的所有元素上切换页面。

如果你对按钮和链接使用明智的HTML元素选择, 那么就没有太多了。例如, 你不应将span标签或div用作按钮或链接。这进一步重申了我们应该使用正确的HTML元素和属性的疯狂建议。我用这个疯狂的建议推开信封。

我看到的另一件事是没有href的锚点或<a />标记, 因此不需要这样做。没有href的锚没有任何意义, 所以不要这样做。你可以通过简单地将背景设置为透明且无边框的方式将按钮设置为看起来像锚的样式, 例如:

.link__button {
  background: transparent;
  border: none;
  padding: 0;
  margin: 0;
  color: #2096f3;
}

BREAK!所有表单控件必须具有标签

在这里更多地说明显而易见的地方, 也就是使用正确的HTML元素和属性。确保你所有窗体控件不仅具有标签而且带有正确标记的伴随错误消息的一种方法是具有一个更高的组件, 如下所示:

export function FormControl<T>(
  Comp: Component<T>
): React.Component<T> {
  return class FormControlWrapper extends React.Component<T> {
    id: string;
    constructor(props) {
      super(props);

      this.id = this.props.id || this.props.name || prefixId();
    }

    render() {
      const {
        invalid, name, label, errorMessage, className, required, ...rest
      } = this.props as any;

      const errorId = `${this.id}-error`;

      return (
        <div>
          <Label
            id={`${this.id}-label`}
            htmlFor={this.id}
            required={required}
          >
            {label}
          </Label>
          <div>
            <Comp
              id={this.id}
              name={name}
              invalid={invalid}
              aria-invalid={invalid}
              required={required}
              aria-describedby={errorId}
              {...rest}
            />
          </div>
          <div
            id={errorId}
            aria-hidden={!invalid}
            role="alert"
          >
            {invalid &&
              errorMessage &&
              <Error
                errorMessage={errorMessage}
              />}
          </div>
        </div>
      );
    }
  };
}

有了此高阶组件后, 我现在可以将正确的标签添加到任何组件, 例如输入零件:

export const FormInput = FormControl(Input)

通过这种方法向所有用户突出显示错误消息:

下方带有验证消息的文本框

下方带有验证消息的文本框

验证消息和焦点管理

上面的高阶组件负责在每个无效字段下方显示错误(如果无效)。不幸的是, 屏幕阅读器的用户只有在进入该字段时才能知道这些错误, 因此我们需要提供描述每个错误的验证摘要, 并提供从验证摘要到每个错误的导航链接。

带有验证摘要和内联字段的表单

乍一看, 这对于两个领域来说完全是矫kill过正, 但是在屏幕阅读器的背景下, 这是一个很好的实践。发生错误时, 焦点将放在

h2

中的元素

验证摘要

零件。每个验证错误都有一个链接。链接的

href

是指向无效表单元素的书签链接。当用户按下Tab键时, 焦点将更改到每个验证错误链接, 并且用户可以通过单击链接跳到正确的控件来修复错误。这样的验证摘要可以确保所有用户都拥有愉快的体验。

链接

当链接被聚焦时, 它们应该具有不同的颜色来表达其不同的状态:

具有不同背景颜色的焦点链接

具有不同背景颜色的焦点链接

咏叹调为新内容

aria属性的第一条规则是不使用它们。请不要从字面上看这条规则, 而是要强制执行这样一个事实, 即应谨慎使用它们。

的咏叹调生活属性就是这样的例外之一。咏叹调告诉屏幕阅读器页面上有新内容, 应告知用户。

下面是一个帮助链接单击链接时展开和收缩的扩展器组件:

export const HelpLink = ({
  collapsibleId, linkText, helpText, open, onClick, children, }) => (
  <div className={styles.container}>
    <Button
      buttonStyle={ButtonStyles.link}
      onClick={onClick}
      aria-expanded={open}
      aria-controls={collapsibleId}
      tabIndex={0}
    >
      <span
        className={cs(
          styles['link__title'], open && styles['link__title__open']
        )}
      >
        <span>{linkText}</span>
      </span>
    </Button>
    <div
      id={collapsibleId}
      aria-hidden={!open}
      aria-live="polite"
      className={cs(styles['closed'], open && styles['open'])}
      role="region"
      tabIndex={-1}
    >
      {helpText}
      {open && children}
    </div>
  </div>
)
使用aria-live属性扩展的内容

使用aria-live属性扩展的内容

明智地使用CSS

你应该确保自己:

  • 不使用显示:无隐藏屏幕阅读器需要宣布的内容
  • 设置文字和背景颜色对比达到可接受的水平
  • 向任何对象添加焦点状态互动或可聚焦的元素

一些用户自定义网页的外观以适合他们的需求。为了支持这些用户, 你应该确保:

  • 如果用户增加字体大小, 所有内容仍然可读
  • 用户可以更改页面上的颜色, 而无需基本元素变得隐形

如果可能, 应避免使用CSS来重新排序内容在页面上, 因为这可能会导致键盘和屏幕阅读器用户出现问题。

不要使用自动辅助功能测试工具来减轻你的良心

我已经看到很多了, 开发团队认为他们正在运行工具或Linter, 以检查网站呈现的HTML是否存在错误的HTML和错误或缺失的属性。尽管这是值得的, 但这不能保证辅助技术用户可以访问你的网站。与真实用户进行测试是唯一确保所有人都可以访问你的网站的保证。

结语

令人沮丧的是, 本文的首要主题是使用正确的HTML元素和属性。我会举起我的手, 说我过去并不总是这样做。我在这篇文章中所描述的并不是巨大的改变, 也不是在开发过程中花费任何时间。通过仅执行我在此处概述的操作, 我们就可以使所有用户都可以使用我们的React网站。

需要采取更多的行动, 而稍加思考和应用, 就可以发生改变。

全面了解生产React应用

调试React应用程序可能很困难, 尤其是当用户遇到难以重现的问题时。如果你有兴趣监视和跟踪Redux状态, 自动显示JavaScript错误以及跟踪缓慢的网络请求和组件加载时间,

尝试notlogy

.

立即行动以使您的React网站可访问2
LogRocket仪表板免费试用横幅

日志火箭就像Web应用程序的DVR, 实际上记录了React应用程序中发生的一切。你可以汇总并报告问题发生时应用程序所处的状态, 而不用猜测为什么会发生问题。 notlogy还监视你的应用程序的性能, 并使用客户端CPU负载, 客户端内存使用情况等指标进行报告。

notlogy Redux中间件软件包在你的用户会话中增加了一层可见性。 notlogy记录Redux存储中的所有操作和状态。

现代化如何调试React应用程序-免费开始监控.

一盏木

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: