El orden del foco debe seguir el orden visual

Cuando la tecla Tab salta de la cabecera al pie de página y vuelve a un producto, quienes usan el teclado o un lector de pantalla pierden la noción de dónde están, se saltan opciones y les cuesta rellenar los formularios en el orden correcto.

ID de la regla
vs-focus-order
Origen
Comprobación de Validiscan
Impacto
Moderado
Nivel de corrección
MANUAL
en Shopify, Shopware, WooCommerce y Magento
Estado
se ejecuta

Qué hace la comprobación

Compara la secuencia de Tab con la disposición visual y señala saltos en los que el foco se mueve en un orden que no coincide con la pantalla, por ejemplo por valores positivos de tabindex o por contenido recolocado con CSS (2.4.3).

La comprobación reúne hasta 300 elementos visibles y alcanzables con el teclado, junto con su posición en la página. Deduce el orden de tabulación a partir del marcado, sin pulsar Tab: primero los valores positivos de tabindex, de menor a mayor, y después el orden del documento. Se ejecuta en cada viewport escaneado, que de forma predeterminada tiene 1440 o 390 px de ancho.

Cada elemento con un tabindex positivo es un hallazgo. En los pasos entre elementos que no lo tienen, la comprobación compara cada elemento con el anterior en el orden de tabulación. Cuando su borde inferior queda más de 100 px por encima del borde superior del elemento anterior, el foco salta hacia arriba en la página, y ese paso queda «pendiente de revisión», con un máximo de 25 por página. El CSS que reordena el contenido, como order en flex, la colocación en una cuadrícula (grid) o el posicionamiento absoluto, puede provocar un salto así, y tiene que ser una persona quien decida si el orden sigue teniendo sentido. Hoy el escáner no convierte lo que está pendiente de revisión en hallazgos, de modo que solo los valores positivos de tabindex producen hallazgos. Los saltos hacia los lados o hacia abajo en la página no se miden.

Cómo corregirlo

Haga que el orden del código de las plantillas coincida con el orden visual, elimine los valores positivos de tabindex y evite reordenar el contenido con order, flex-direction o posicionamiento absoluto de CSS cuando eso cambie la secuencia en la que se lee y se recorre la página con Tab.

Criterios de conformidad de las WCAG

Apartados de la norma EN 301 549

El apartado de la norma EN 301 549 que corresponde a cada criterio, por versión de la norma
Criterio de las WCAG Versión 3.2.1 Versión 4.1.1
2.4.3 9.2.4.3 9.2.4.3

Recetas que enumeran esta regla

Esta regla tiene el nivel MANUAL. En un proyecto, un hallazgo de esta regla sigue la vía MANUAL, y estas recetas no se le aplican.

Shopify: receta remove-positive-tabindex

Mostrar el antes y el después (1)
Antes y después Datos de ejemplo

sections/header.liquid Cambios en sections/header.liquid (líneas añadidas: 1; eliminadas: 1)

Cambios en sections/header.liquid (líneas añadidas: 1; eliminadas: 1)
Línea anterior Línea nueva Cambio Código
37 37
38 38 <div class="header__search">
39 39 <form action="{{ routes.search_url }}" method="get" role="search" class="search">
40 Eliminada <input class="search__input field__input" type="search" name="q" value="" placeholder="{{ 'general.search.placeholder' | t }}" tabindex="1">
40 Añadida <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: receta remove-positive-tabindex

Mostrar el antes y el después (1)
removes tabindex="1" from the buy button; vs-focus-order and axe tabindex stop firing Datos de ejemplo

Resources/views/storefront/page/product-detail/buy-widget.html.twig Cambios en Resources/views/storefront/page/product-detail/buy-widget.html.twig (líneas añadidas: 1; eliminadas: 1)

Cambios en Resources/views/storefront/page/product-detail/buy-widget.html.twig (líneas añadidas: 1; eliminadas: 1)
Línea anterior Línea nueva Cambio Código
82 82 </div>
83 83 <div class="buy-widget-submit">
84 84 <button class="btn btn-primary btn-buy"
85 Eliminada title="{{ 'detail.addProduct'|trans }}" tabindex="1">
85 Añadida title="{{ 'detail.addProduct'|trans }}">
86 86 {{ 'detail.addProduct'|trans }}
87 87 </button>
88 88 </div>

WooCommerce: receta remove-positive-tabindex

Mostrar el antes y el después (1)
removes tabindex="1" from the header search field of the fixture theme Datos de ejemplo

header.php Cambios en header.php (líneas añadidas: 1; eliminadas: 1)

Cambios en header.php (líneas añadidas: 1; eliminadas: 1)
Línea anterior Línea nueva Cambio Código
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 Eliminada <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 Añadida <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: receta remove-positive-tabindex

Mostrar el antes y el después (1)
removes tabindex 1-4 from the login form and the CAPTCHA and validates Datos de ejemplo

app/design/frontend/Validiscan/fixture/Magento_Customer/templates/form/captcha-math.phtml Cambios en app/design/frontend/Validiscan/fixture/Magento_Customer/templates/form/captcha-math.phtml (líneas añadidas: 1; eliminadas: 1)

Cambios en app/design/frontend/Validiscan/fixture/Magento_Customer/templates/form/captcha-math.phtml (líneas añadidas: 1; eliminadas: 1)
Línea anterior Línea nueva Cambio Código
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 Eliminada <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 Añadida <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 Cambios en app/design/frontend/Validiscan/fixture/Magento_Customer/templates/form/login.phtml (líneas añadidas: 3; eliminadas: 3)

Cambios en app/design/frontend/Validiscan/fixture/Magento_Customer/templates/form/login.phtml (líneas añadidas: 3; eliminadas: 3)
Línea anterior Línea nueva Cambio Código
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 Eliminada <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 Añadida <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 Eliminada <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 Añadida <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 Eliminada <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 Añadida <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>

Empiece con una revisión gratuita de su tienda.

Envíe la dirección de su tienda. Validiscan la escanea y le responde con cada fallo que el escaneo pueda demostrar, con la página y el código.

Solicitar revisión gratuita

O escriba a info@validiscan.com.

Qué cubre la revisión gratuita y qué deja fuera
Usted envía
la dirección de su tienda
Páginas escaneadas
hasta 15
Usted recibe
todos los fallos que el escaneo puede demostrar, con la página y el código
En su tienda
solo páginas públicas; sin inicio de sesión, nada comprado, ningún formulario enviado
Lo que no es
una auditoría completa

Escribir a Validiscan

Para una revisión gratuita, indique la dirección web de su tienda y su plataforma.

Validiscan utiliza lo que usted envía para responderle. Política de privacidad