Les éléments ne devraient pas avoir un tabindex supérieur à zéro
Un tabindex supérieur à zéro place un élément en tête de l’ordre de tabulation. Les personnes qui utilisent le clavier ou un lecteur d’écran sautent alors d’un endroit à l’autre de la page dans un ordre inattendu, par exemple de l’en-tête directement à un champ d’inscription à la newsletter, et peuvent perdre le chemin du panier ou du paiement.
- Identifiant de la règle
- tabindex
- Source
- axe-core 4.13.0
- Impact
- Grave
- Niveau de correction
- AUTO
- sur Shopify, Shopware, WooCommerce et Magento
- Statut
- exécutée
Ce que fait le contrôle
Vérifier que les valeurs de l’attribut tabindex ne sont pas supérieures à 0
La règle teste tout élément porteur d’un attribut tabindex, quel que soit l’élément, sauf s’il est masqué aux technologies d’assistance. Elle lit la valeur de l’attribut, pas la propriété DOM. axe-core retire les espaces autour de la valeur et en prend le nombre entier initial, avec un signe facultatif : tabindex="2.5" compte donc comme 2 et tabindex="+1" comme 1. Une valeur qui ne commence pas par un nombre réussit, de même que 0 et les valeurs négatives.
axe-core classe cette règle en bonne pratique, et elle ne correspond à aucun critère de succès des WCAG. Le scanner de Validiscan l’exécute, par défaut, dans une passe de bonne pratique distincte qui ne conserve que les échecs. Le constat est enregistré comme bonne pratique et exclu des tableaux de conformité et du chiffre d’avancement des corrections. Un tabindex positif sur un élément visible qui peut recevoir le focus peut aussi être signalé par vs-focus-order au titre du critère de succès 2.4.3.
La règle ne juge pas si l’ordre de tabulation qui en résulte a un sens, ni si tabindex="0" et tabindex="-1" sont posés sur les bons éléments ; une personne le vérifie au clavier.
Comment corriger
Supprimez les valeurs de tabindex positives ou remplacez-les par tabindex="0", et organisez l’ordre du code source du modèle pour que l’ordre de tabulation naturel suive la mise en page visuelle.
Critères de succès WCAG
Bonne pratique : non rattachée à un critère de succès WCAG.
Où une recette corrige le problème
Shopify : recette remove-positive-tabindex
Afficher l’avant et l’après (1)
sections/header.liquid Modifications apportées à sections/header.liquid (lignes ajoutées : 1, lignes supprimées : 1)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 37 | 37 | ||
| 38 | 38 | <div class="header__search"> | |
| 39 | 39 | <form action="{{ routes.search_url }}" method="get" role="search" class="search"> | |
| 40 | Supprimée | <input class="search__input field__input" type="search" name="q" value="" placeholder="{{ 'general.search.placeholder' | t }}" tabindex="1"> | |
| 40 | Ajoutée | <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 : recette remove-positive-tabindex
Afficher l’avant et l’après (1)
Resources/views/storefront/page/product-detail/buy-widget.html.twig Modifications apportées à Resources/views/storefront/page/product-detail/buy-widget.html.twig (lignes ajoutées : 1, lignes supprimées : 1)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 82 | 82 | </div> | |
| 83 | 83 | <div class="buy-widget-submit"> | |
| 84 | 84 | <button class="btn btn-primary btn-buy" | |
| 85 | Supprimée | title="{{ 'detail.addProduct'|trans }}" tabindex="1"> | |
| 85 | Ajoutée | title="{{ 'detail.addProduct'|trans }}"> | |
| 86 | 86 | {{ 'detail.addProduct'|trans }} | |
| 87 | 87 | </button> | |
| 88 | 88 | </div> |
WooCommerce : recette remove-positive-tabindex
Afficher l’avant et l’après (1)
header.php Modifications apportées à header.php (lignes ajoutées : 1, lignes supprimées : 1)
| Ligne avant | Ligne après | Modification | 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 | Supprimée | <input type="search" id="woocommerce-product-search-field-0" class="search-field" placeholder="<?php echo esc_attr__( 'Search products…', 'woocommerce' ); ?>" value="<?php echo get_search_query(); ?>" name="s" tabindex="1"> | |
| 52 | Ajoutée | <input type="search" id="woocommerce-product-search-field-0" class="search-field" placeholder="<?php echo esc_attr__( 'Search products…', '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 : recette remove-positive-tabindex
Afficher l’avant et l’après (1)
app/design/frontend/Validiscan/fixture/Magento_Customer/templates/form/captcha-math.phtml Modifications apportées à app/design/frontend/Validiscan/fixture/Magento_Customer/templates/form/captcha-math.phtml (lignes ajoutées : 1, lignes supprimées : 1)
| Ligne avant | Ligne après | Modification | 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 | Supprimée | <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 | Ajoutée | <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 Modifications apportées à app/design/frontend/Validiscan/fixture/Magento_Customer/templates/form/login.phtml (lignes ajoutées : 3, lignes supprimées : 3)
| Ligne avant | Ligne après | Modification | 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 | Supprimée | <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 | Ajoutée | <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 | Supprimée | <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 | Ajoutée | <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 | Supprimée | <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 | Ajoutée | <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> |
Commencez par une vérification gratuite de votre boutique.
Envoyez l’adresse de votre boutique. Validiscan la scanne et vous envoie chaque échec que le scan peut prouver, avec sa page et son code.
Demander une vérification gratuiteOu écrivez à info@validiscan.com.
Ce que couvre la vérification gratuite, et ce qu’elle laisse de côté- Vous envoyez
- l’adresse de votre boutique
- Pages scannées
- jusqu’à 15
- Vous recevez
- chaque échec que le scan peut prouver, avec la page et le code
- Sur votre boutique
- pages publiques uniquement ; aucune connexion, aucun achat, aucun formulaire envoyé
- Ce qu’elle n’est pas
- un audit complet