Die Fokusreihenfolge muss der visuellen Reihenfolge folgen

Springt die Tab-Taste vom Header zum Footer und zurück zu einem Produkt, verlieren Menschen, die mit Tastatur oder Screenreader navigieren, den Überblick, übersehen Optionen und haben Mühe, Formulare in der richtigen Reihenfolge auszufüllen.

Regel-ID
vs-focus-order
Quelle
Validiscan-Prüfung
Auswirkung
Mittel
Korrekturstufe
MANUAL
auf Shopify, Shopware, WooCommerce und Magento
Status
wird ausgeführt

Was geprüft wird

Vergleicht die Tab-Reihenfolge mit dem visuellen Layout und markiert Sprünge, bei denen der Fokus in einer Reihenfolge wandert, die nicht zur Darstellung passt, zum Beispiel wegen positiver tabindex-Werte oder per CSS verschobener Inhalte (2.4.3).

Die Prüfung sammelt bis zu 300 sichtbare, per Tastatur erreichbare Elemente und ihre Position auf der Seite. Die Tab-Reihenfolge ermittelt sie aus dem Markup, ohne die Tab-Taste zu drücken: zuerst positive tabindex-Werte in aufsteigender Folge, dann die Reihenfolge im Dokument. Sie läuft in jedem gescannten Viewport, standardmäßig 1440 und 390 px breit.

Jedes Element mit positivem tabindex ist ein Befund. Bei Schritten zwischen Elementen ohne einen solchen Wert vergleicht die Prüfung jedes Element mit seinem Vorgänger in der Tab-Reihenfolge. Liegt seine Unterkante mehr als 100 px über der Oberkante des vorherigen Elements, springt der Fokus auf der Seite zurück nach oben, und der Schritt landet bei „zu prüfen“ (höchstens 25 pro Seite). CSS, das Inhalte umsortiert, etwa order in Flexbox, die Platzierung im Grid oder absolute Positionierung, kann einen solchen Sprung verursachen. Ob die Reihenfolge dann noch sinnvoll ist, muss ein Mensch entscheiden. Aus Ergebnissen „zu prüfen“ macht der Scanner derzeit keine Befunde, deshalb führen nur positive tabindex-Werte zu Befunden. Sprünge zur Seite oder nach unten werden nicht gemessen.

So wird es behoben

Bringen Sie die Quellreihenfolge der Templates in Übereinstimmung mit der visuellen Reihenfolge, entfernen Sie positive tabindex-Werte, und vermeiden Sie es, Inhalte mit CSS order, flex-direction oder absoluter Positionierung umzusortieren, wo das die Reihenfolge ändert, in der Menschen lesen und mit Tab navigieren.

WCAG-Erfolgskriterien

Abschnitte der EN 301 549

Der Abschnitt der EN 301 549 zu jedem Kriterium, je Version der Norm
WCAG-Kriterium Version 3.2.1 Version 4.1.1
2.4.3 9.2.4.3 9.2.4.3

Rezepte, die diese Regel aufführen

Diese Regel hat die Korrekturstufe MANUAL. In einem Projekt geht ein Befund dieser Regel den Weg MANUAL, und diese Rezepte werden darauf nicht angewendet.

Shopify: Rezept remove-positive-tabindex

Vorher und nachher anzeigen (1)
Vorher und nachher Beispieldaten

sections/header.liquid Änderungen an sections/header.liquid: 1 hinzugefügt, 1 entfernt

Änderungen an sections/header.liquid: 1 hinzugefügt, 1 entfernt
Zeile vorher Zeile nachher Änderung Code
37 37
38 38 <div class="header__search">
39 39 <form action="{{ routes.search_url }}" method="get" role="search" class="search">
40 Entfernt <input class="search__input field__input" type="search" name="q" value="" placeholder="{{ 'general.search.placeholder' | t }}" tabindex="1">
40 Hinzugefügt <input class="search__input field__input" type="search" name="q" value="" placeholder="{{ 'general.search.placeholder' | t }}">
41 41 <button type="submit" class="search__button">
42 42 {%- render 'icon', icon: 'search', size: 20 -%}
43 43 </button>

Shopware: Rezept remove-positive-tabindex

Vorher und nachher anzeigen (1)
removes tabindex="1" from the buy button; vs-focus-order and axe tabindex stop firing Beispieldaten

Resources/views/storefront/page/product-detail/buy-widget.html.twig Änderungen an Resources/views/storefront/page/product-detail/buy-widget.html.twig: 1 hinzugefügt, 1 entfernt

Änderungen an Resources/views/storefront/page/product-detail/buy-widget.html.twig: 1 hinzugefügt, 1 entfernt
Zeile vorher Zeile nachher Änderung Code
82 82 </div>
83 83 <div class="buy-widget-submit">
84 84 <button class="btn btn-primary btn-buy"
85 Entfernt title="{{ 'detail.addProduct'|trans }}" tabindex="1">
85 Hinzugefügt title="{{ 'detail.addProduct'|trans }}">
86 86 {{ 'detail.addProduct'|trans }}
87 87 </button>
88 88 </div>

WooCommerce: Rezept remove-positive-tabindex

Vorher und nachher anzeigen (1)
removes tabindex="1" from the header search field of the fixture theme Beispieldaten

header.php Änderungen an header.php: 1 hinzugefügt, 1 entfernt

Änderungen an header.php: 1 hinzugefügt, 1 entfernt
Zeile vorher Zeile nachher Änderung Code
49 49 <form role="search" method="get" class="woocommerce-product-search" action="<?php echo esc_url( home_url( '/search' ) ); ?>">
50 50 <label class="screen-reader-text" for="woocommerce-product-search-field-0"><?php esc_html_e( 'Search for:', 'woocommerce' ); ?></label>
51 51 <?php // VALIDISCAN-SEED vs-focus-order + tabindex: tabindex="1" "so the search is always the first stop". ?>
52 Entfernt <input type="search" id="woocommerce-product-search-field-0" class="search-field" placeholder="<?php echo esc_attr__( 'Search products&hellip;', 'woocommerce' ); ?>" value="<?php echo get_search_query(); ?>" name="s" tabindex="1">
52 Hinzugefügt <input type="search" id="woocommerce-product-search-field-0" class="search-field" placeholder="<?php echo esc_attr__( 'Search products&hellip;', 'woocommerce' ); ?>" value="<?php echo get_search_query(); ?>" name="s">
53 53 <?php // VALIDISCAN-SEED button-name: icon-only submit button without text. ?>
54 54 <button type="submit" value="<?php echo esc_attr_x( 'Search', 'submit button', 'woocommerce' ); ?>" class="kb-search-submit"><?php kb_icon( 'search' ); ?></button>
55 55 <input type="hidden" name="post_type" value="product">

Magento: Rezept remove-positive-tabindex

Vorher und nachher anzeigen (1)
removes tabindex 1-4 from the login form and the CAPTCHA and validates Beispieldaten

app/design/frontend/Validiscan/fixture/Magento_Customer/templates/form/captcha-math.phtml Änderungen an app/design/frontend/Validiscan/fixture/Magento_Customer/templates/form/captcha-math.phtml: 1 hinzugefügt, 1 entfernt

Änderungen an app/design/frontend/Validiscan/fixture/Magento_Customer/templates/form/captcha-math.phtml: 1 hinzugefügt, 1 entfernt
Zeile vorher Zeile nachher Änderung Code
14 14 <div class="field captcha required" role="group" aria-labelledby="captcha-question" data-captcha-type="math">
15 15 <label for="captcha_user_login" class="label" id="captcha-question"><span><?= $escaper->escapeHtml(__('Security question: what is %1 + %2?', $a, $b)) ?></span></label>
16 16 <div class="control captcha">
17 Entfernt <input name="captcha[user_login]" type="text" class="input-text required-entry" id="captcha_user_login" autocomplete="off" inputmode="numeric" tabindex="3" data-captcha-answer-hash="<?= $escaper->escapeHtmlAttr(md5((string) ($a + $b))) ?>">
17 Hinzugefügt <input name="captcha[user_login]" type="text" class="input-text required-entry" id="captcha_user_login" autocomplete="off" inputmode="numeric" data-captcha-answer-hash="<?= $escaper->escapeHtmlAttr(md5((string) ($a + $b))) ?>">
18 18 </div>
19 19 </div>

app/design/frontend/Validiscan/fixture/Magento_Customer/templates/form/login.phtml Änderungen an app/design/frontend/Validiscan/fixture/Magento_Customer/templates/form/login.phtml: 3 hinzugefügt, 3 entfernt

Änderungen an app/design/frontend/Validiscan/fixture/Magento_Customer/templates/form/login.phtml: 3 hinzugefügt, 3 entfernt
Zeile vorher Zeile nachher Änderung Code
27 27 <div class="field email required">
28 28 <label class="label" for="email"><span><?= $escaper->escapeHtml(__('Email')) ?></span></label>
29 29 <div class="control">
30 Entfernt <input name="login[username]" value="<?= $escaper->escapeHtmlAttr($username) ?>" autocomplete="off" id="email" type="email" class="input-text mage-error" title="<?= $escaper->escapeHtmlAttr(__('Email')) ?>" aria-invalid="true" tabindex="1" onpaste="return false;" data-mage-init='{"mage/trim-input":{}}'>
30 Hinzugefügt <input name="login[username]" value="<?= $escaper->escapeHtmlAttr($username) ?>" autocomplete="off" id="email" type="email" class="input-text mage-error" title="<?= $escaper->escapeHtmlAttr(__('Email')) ?>" aria-invalid="true" onpaste="return false;" data-mage-init='{"mage/trim-input":{}}'>
31 31 <div for="email" generated="true" class="mage-error" id="email-error"><?= $escaper->escapeHtml(__('Please enter a valid email address (Ex: johndoe@domain.com).')) ?></div>
32 32 </div>
33 33 </div>
35 35 <div class="field password required">
36 36 <label for="pass" class="label"><span><?= $escaper->escapeHtml(__('Password')) ?></span></label>
37 37 <div class="control">
38 Entfernt <input name="login[password]" type="password" autocomplete="off" class="input-text" id="pass" title="<?= $escaper->escapeHtmlAttr(__('Password')) ?>" tabindex="2" onpaste="return false;" oncopy="return false;">
38 Hinzugefügt <input name="login[password]" type="password" autocomplete="off" class="input-text" id="pass" title="<?= $escaper->escapeHtmlAttr(__('Password')) ?>" onpaste="return false;" oncopy="return false;">
39 39 </div>
40 40 </div>
41 41 <!-- VALIDISCAN-SEEDED vs-accessible-auth: arithmetic CAPTCHA with no alternative -->
42 42 <?= $block->getChildHtml('form_additional_info') /* math CAPTCHA module: div.field.captcha, input#captcha_user_login tabindex="3" */ ?>
43 43 <div class="actions-toolbar">
44 Entfernt <div class="primary"><button type="submit" class="action login primary" name="send" id="send2" tabindex="4"><span><?= $escaper->escapeHtml(__('Sign In')) ?></span></button></div>
44 Hinzugefügt <div class="primary"><button type="submit" class="action login primary" name="send" id="send2"><span><?= $escaper->escapeHtml(__('Sign In')) ?></span></button></div>
45 45 <div class="secondary"><a class="action remind" href="<?= $escaper->escapeUrl($block->getUrl('contact')) ?>"><span><?= $escaper->escapeHtml(__('Forgot Your Password? Contact us')) ?></span></a></div>
46 46 </div>
47 47 </fieldset>

Beginnen Sie mit einem kostenlosen Check Ihres Shops.

Senden Sie die Adresse Ihres Shops. Validiscan scannt ihn und antwortet mit jedem Fehler, den der Scan nachweisen kann, jeweils mit der Seite und dem Code.

Kostenlosen Check anfordern

Oder schreiben Sie an info@validiscan.com.

Was der kostenlose Check umfasst und was nicht
Sie senden
die Adresse Ihres Shops
Gescannte Seiten
bis zu 15
Sie erhalten
jeden Fehler, den der Scan nachweisen kann, mit Seite und Code
In Ihrem Shop
nur öffentliche Seiten; keine Anmeldung, nichts gekauft, kein Formular abgeschickt
Was er nicht ist
ein vollständiges Audit

Nachricht an Validiscan

Für einen kostenlosen Check nennen Sie die Adresse Ihres Shops und seine Plattform.

Validiscan verwendet, was Sie senden, um Ihnen zu antworten. Datenschutzerklärung