使用 mat-date-range-input 但 JAWS reader 首先使用 JAWS-e 读取结束日期(下一个编辑框)

Using mat-date-range-input but the JAWS reader first reads the end date with JAWS-e (next edit box)

我有一个带有 mat-date-range-input 的组件。 我的客户使用 JAWS reader 并使用 JAWS-e(下一个编辑框)进行导航。 当他们这样做时,JAWS 首先读取 mat-date-range-input 的 'end date'。再次按下 JAWS-e 时会读取 'start date'。我原以为 'start date' 会先被阅读。

下面是 html 中带有 mat-date-range-input 的部分。 我首先觉得 aria-hidden=true 的跨度可能是问题的原因,但删除它并没有解决问题。

有没有人遇到过这种情况?有解决办法吗?

谢谢&问候, 内勒克

<div _ngcontent-ynn-c151="" class="ng-star-inserted" style="">
   <mat-form-field _ngcontent-ynn-c151="" appearance="fill" class="mat-form-field date-picker ng-tns-c64-23 mat-primary mat-form-field-type-mat-date-range-input mat-form-field-appearance-fill mat-form-field-can-float mat-form-field-has-label mat-form-field-hide-placeholder ng-star-inserted">
      <div class="mat-form-field-wrapper ng-tns-c64-23">
         <div class="mat-form-field-flex ng-tns-c64-23">
            <div class="mat-form-field-infix ng-tns-c64-23">
               <mat-date-range-input _ngcontent-ynn-c151="" role="group" class="mat-date-range-input ng-tns-c64-23" aria-labelledby="mat-form-field-label-37" data-mat-calendar="mat-datepicker-2">
                  <div cdkmonitorsubtreefocus="" class="mat-date-range-input-container">
                     <div class="mat-date-range-input-start-wrapper">
                        <input _ngcontent-ynn-c151="" type="text" matstartdate="" name="startDate" class="mat-start-date mat-date-range-input-inner startDate ng-touched ng-pristine ng-valid" placeholder="startdatum" id="mat-date-range-input-0" aria-haspopup="dialog" min="1800-01-01T00:00:00+00:19" max="2022-03-02T00:00:00+01:00">
                        <span aria-hidden="true" class="mat-date-range-input-mirror">startdatum</span>
                     </div>
                     <span class="mat-date-range-input-separator mat-date-range-input-separator-hidden">–</span>
                     <div class="mat-date-range-input-end-wrapper">
                        <input _ngcontent-ynn-c151="" type="text" matenddate="" name="endDate" class="mat-end-date mat-date-range-input-inner endDate ng-touched ng-pristine ng-valid" placeholder="einddatum" aria-haspopup="dialog" min="1800-01-01T00:00:00+00:19" max="2022-03-02T00:00:00+01:00">
                     </div>
                  </div>
               </mat-date-range-input>
               <mat-date-range-picker _ngcontent-ynn-c151="" class="ng-tns-c64-23"></mat-date-range-picker>
               <span class="mat-form-field-label-wrapper ng-tns-c64-23">
                  <label class="mat-form-field-label ng-tns-c64-23 mat-empty mat-form-field-empty ng-star-inserted" id="mat-form-field-label-37" for="mat-date-range-input-0" aria-owns="mat-date-range-input-0">
                     <mat-label _ngcontent-ynn-c151="" class="ng-tns-c64-23 ng-star-inserted">Datum (max 28 dagen)</mat-label>
                  </label>
               </span>
            </div>
            <div class="mat-form-field-suffix ng-tns-c64-23 ng-star-inserted">
               <mat-datepicker-toggle _ngcontent-ynn-c151="" matsuffix="" class="mat-datepicker-toggle ng-tns-c64-23" data-mat-calendar="mat-datepicker-2">
                  <button mat-icon-button="" type="button" class="mat-focus-indicator mat-icon-button mat-button-base" aria-haspopup="dialog" aria-label="Open calendar" tabindex="0">
                     <span class="mat-button-wrapper">
                        <mat-icon _ngcontent-ynn-c151="" role="img" matdatepickertoggleicon="" class="mat-icon notranslate material-icons mat-icon-no-color" aria-hidden="true" data-mat-icon-type="font">date_range</mat-icon>
                     </span>
                     <span matripple="" class="mat-ripple mat-button-ripple mat-button-ripple-round"></span>
                     <span class="mat-button-focus-overlay"></span>
                  </button>
               </mat-datepicker-toggle>
            </div>
         </div>
         <div class="mat-form-field-underline ng-tns-c64-23 ng-star-inserted">
            <span class="mat-form-field-ripple ng-tns-c64-23">
            </span>
         </div>
         <div class="mat-form-field-subscript-wrapper ng-tns-c64-23">
            <div class="mat-form-field-hint-wrapper ng-tns-c64-23 ng-trigger ng-trigger-transitionMessages ng-star-inserted" style="opacity: 1; transform: translateY(0%);">
               <div class="mat-form-field-hint-spacer ng-tns-c64-23"></div>
            </div>
         </div>
      </div>
   </mat-form-field>
</div>

无论您使用什么屏幕 reader,都会出现此问题,而不仅仅是 JAWS。

Angular Material就是mis-usingaria-owns attribute. You can test this on their "Date Range Selection”的例子。他们的代码基本上是这样的:

<input placeholder="Start date" id="startdate">
<input placeholder="End date">
<label for="startdate" aria-owns="startdate">Enter a date range</label>

all ARIA attributes一样,aria-owns只是对屏幕的提示reader。 ARIA 属性应该可以帮助屏幕 reader 理解页面的组织。 ARIA 属性不会影响页面的外观,也不会影响浏览器的行为。在这种特殊情况下,ARIA 属性不会影响浏览器的 Tab 键顺序。

因此无论 ARIA 属性是否存在,当您通过日期范围小部件 tab 时,tab 顺序(默认)与 DOM 顺序相同.在这种情况下,<input placeholder="Start date" id="startdate"> 是第一个,因此它首先接收选项卡焦点。下一个 选项卡 转到下一个 DOM 元素,即 <input placeholder="End date"><label> 不是制表位。

这一切都按预期工作。

如果您使用屏幕 reader 命令进行导航,就会变得奇怪。屏幕 reader 用户可以正常使用 tab 键,他们会按正确的顺序听到内容。但是,如果屏幕 reader 用户尝试导航 DOM(实际上是 AOM - 可访问性对象模型),无论是通过 E 键(通常是 INS+E) 或 downArrow 键,then aria-owns会影响东西,因为ARIA属性会影响画面reader.

另一个需要理解的概念是 AOM。辅助功能对象模型类似于文档对象模型 (DOM),只是它本质上是 DOM 的 子集 。并非 DOM 上的所有内容都会出现在 AOM 中。当您使用屏幕 reader 命令时,屏幕 reader 会与 AOM 交互。

例如,如果您有一个带有 display:none 的元素,该元素仍然存在于 DOM 中。您仍然可以对其调用 getObjectByName()。但是该元素将从 AOM 中删除,这样屏幕 reader 用户就不能再使用屏幕 reader 命令导航到该元素。

如 OP 中所述,aria-hidden 也发生了类似的事情。将 aria-hidden 设置为 true 将从 AOM 中 删除 该元素,因此屏幕 reader 不再认为它存在。

因此,如前所述,可以使用 downArrow 键(或专门用于输入字段的 E 键)来遍历 AOM .它让用户可以像浏览文本文档一样浏览 AOM。可以把它想象成在文本编辑器中阅读 HTML 文件,然后使用 向下箭头 键转到编辑器中的下一行。

aria-owns 更改 AOM 顺序而不实际更改 DOM。 aria-owns 可让您影响 AOM 中的 parent/child 关系并模仿一个元素 另一个元素之后,即使它实际上不在 HTML 中文件。

所以在这种情况下,即使 DOM 物理上看起来像这样:

<input placeholder="Start date" id="startdate">
<input placeholder="End date">
<label for="startdate" aria-owns="startdate">Enter a date range</label>

AOM 将如下所示:

<input placeholder="End date">
<label for="startdate" aria-owns="startdate">Enter a date range</label>
<input placeholder="Start date" id="startdate">

因为 <label> 上的 aria-owns="startdate" 导致开始日期元素 标签之后。

是的,这很复杂,但是一旦您了解了导致它的原因,它就有点简单了。

Is there a solution?

否 :-( 除了联系 google 让他们知道他们没有正确使用 aria-owns。