Correcciones de accesibilidad en el código de su tema de Shopware
Validiscan corrige los fallos de accesibilidad web en las plantillas Twig, el SCSS, el JavaScript del storefront y los archivos de snippets de su plugin de tema de Shopware 6. Nada llega a su tienda en producción hasta que su desarrollador fusione o aplique los cambios y despliegue el tema.
Última actualización:
En esta página: 6 respuestas
¿Qué cambia Validiscan en un tema de Shopware?
Validiscan solo cambia archivos de las carpetas en las que un tema de storefront de Shopware 6 guarda su código fuente, Resources/views, Resources/ y Resources/snippet, y su theme.json. Un cambio en cualquier otro archivo no supera la validación y nunca se entrega, y ninguna corrección instala un plugin ni añade un script de overlay.
Los ajustes que usted gestiona en la Administración de Shopware, como los metatítulos o los colores del tema guardados allí, no son archivos del tema, así que las correcciones no los cambian. Un proyecto cubre un dominio y un tema; los elementos incrustados de terceros, como los widgets de pago o de chat, no están incluidos en él.
Detalles: las carpetas, cómo es un cambio y las dos recetas que modifican el script del storefront
Validiscan solo cambia archivos de las carpetas en las que un tema de storefront de Shopware 6 guarda su código fuente: las plantillas Twig de Resources/views, el código fuente de SCSS y de JavaScript de Resources/, los archivos de snippets con los textos del storefront de Resources/snippet y el theme.json del tema. Un cambio en cualquier otro archivo, como los archivos compilados de Resources/ o el código PHP y la configuración del plugin, no supera la validación. Un cambio que no supera la validación no se puede aprobar, de modo que nunca se entrega.
Cada cambio es una edición corriente de un archivo del tema que su desarrollador puede leer línea por línea. Los cambios pequeños, como un atributo añadido o un valor de color corregido, se hacen donde ya está el código. Las reglas de estilo nuevas y los bloques de script nuevos van entre comentarios que nombran la receta, por ejemplo /* validiscan:, y por eso son fáciles de encontrar. Dos recetas modifican el propio script de storefront del tema: una conecta un botón de pausa con el carrusel de imágenes y la otra impide que el avance automático de un script se inicie cuando el visitante ha pedido menos movimiento. Ninguna corrección instala un plugin ni añade un script que corrija sus páginas una vez cargadas, como hace un overlay.
¿Cómo accede Validiscan a su tema de Shopware?
Mediante un repositorio de GitHub o un ZIP del plugin del tema subido en el portal del cliente, porque Validiscan prepara cada corrección en una copia del código fuente de su plugin de tema de Shopware. La vía depende de dónde esté el código: un repositorio recibe un pull request y un ZIP, un paquete de parches.
| Vía de acceso | Lo que usted da | Los cambios vuelven como |
|---|---|---|
| A través de su repositorio de GitHub | Acceso al repositorio que contiene el plugin del tema, mediante la GitHub App de Validiscan o un token de acceso | Un pull request |
| Desde un ZIP del plugin del tema | La carpeta del plugin del tema en custom/, como un único archivo ZIP de hasta 100 MB, que sube en el portal del cliente un administrador de su organización | Un paquete de parches |
A través de su repositorio de GitHub
Si el código del plugin de su tema está en un repositorio de GitHub, usted da a Validiscan acceso a ese repositorio: instala en él la GitHub App de Validiscan o entrega a Validiscan un token de acceso para él. La configuración de Validiscan especifica los permisos de la App como acceso de lectura y escritura al contenido y a los pull requests del repositorio, y acceso de lectura a sus metadatos, y nada más. Un token necesita los mismos permisos sobre ese único repositorio.
El plugin del tema puede estar en la raíz del repositorio o más adentro, como en custom/: las recetas encuentran los archivos del tema por las convenciones de carpetas de Shopware. Los cambios llegan entonces como un pull request.
Desde un ZIP del plugin del tema
Si el código no está en un repositorio de GitHub, su desarrollador crea un ZIP del plugin del tema. La instrucción del portal del cliente para Shopware dice: «Pida a su desarrollador un ZIP del plugin de su tema: su carpeta en custom/plugins, tal como está desplegada en su tienda». Después, un administrador de su organización sube el archivo en el portal del cliente, como un único archivo ZIP de hasta 100 MB. Validiscan prepara los cambios en esa copia de su tema y se los devuelve como un paquete de parches.
Sin ninguna de las dos vías, Validiscan no tiene código que cambiar y no se prepara ninguna corrección.
¿Cómo llegan los cambios a su tienda?
Los cambios llegan como un pull request o como un paquete de parches, y su desarrollador decide cuándo salen a producción. Validiscan solo entrega cambios que ha revisado y aprobado y nunca modifica el tema ni el código de su tienda Shopware en producción; la entrega como copia sin publicar del tema existe solo en Shopify.
- Validiscan entrega los cambios que ha revisado y aprobado: un pull request en una rama nueva o un paquete de parches para su desarrollador.
- Su desarrollador revisa los cambios. En un pull request, la lista de comprobación pide un entorno de vista previa o de preproducción, no la tienda en producción, y una comprobación de las páginas afectadas, también solo con el teclado.
- Su desarrollador fusiona el pull request o aplica el paquete de parches.
- Su desarrollador compila el tema: los cambios en el SCSS surten efecto cuando el tema se vuelve a compilar, y los cambios en el JavaScript, cuando el storefront se vuelve a generar.
- Su desarrollador despliega el tema. Cuando los cambios están en producción, un escaneo de verificación vuelve a comprobar las páginas afectadas.
Un pull request
Con acceso a su repositorio, Validiscan crea una rama nueva llamada validiscan/, registra cada corrección en un commit propio y abre un pull request con una tabla resumen, una explicación de cada cambio y una lista de comprobación para la revisión. No se sube nada a su rama predeterminada. La lista de comprobación pide a su desarrollador que despliegue la rama en un entorno de vista previa o de preproducción, no en la tienda en producción, y que compruebe allí las páginas afectadas, también solo con el teclado, antes de fusionarla.
Un paquete de parches
A partir del ZIP subido, Validiscan prepara un archivo zip y se lo envía a su desarrollador. Contiene PATCH.md, con cada cambio y cómo aplicarlo; todos los cambios en un único archivo de parche que se aplica con git apply; un archivo de parche por corrección; los archivos modificados completos y un README.md. Su desarrollador aplica los cambios, los prueba y despliega el tema. Qué contienen un pull request y un paquete de parches
Compilar el tema
Una tienda Shopware no sirve tal cual el código fuente de SCSS y de JavaScript del tema: antes se compila. Los cambios en el SCSS surten efecto cuando el tema se vuelve a compilar, por ejemplo con bin/, como describe la documentación para desarrolladores de Shopware sobre los estilos de un tema. Los cambios en el JavaScript del storefront surten efecto cuando el storefront se vuelve a generar, como se describe en la documentación de Shopware sobre el JavaScript del storefront. Su desarrollador ejecuta estos pasos al desplegar el tema modificado. Cómo llegan las correcciones de accesibilidad a un tema de Shopware y qué puede deshacer una actualización del tema
¿Qué cambian las recetas en un tema de Shopware?
Cada una de las 20 recetas de Validiscan para temas de Shopware es un cambio determinista para un tipo de fallo: el mismo código recibe siempre el mismo cambio. Una receta hace un cambio solo donde el código del tema muestra cuál es el cambio correcto; donde no lo muestra, no cambia nada.
Estructura de la página y navegación
-
Idioma de la página en el layout base html-lang El elemento
<html>del layout base recibe un atributolangválido donde falta o donde el tema imprime un código de configuración regional comoen_GB.El elemento
<html>del layout base del storefront recibe un atributolangválido, para que los lectores de pantalla pronuncien la página en el idioma correcto. Donde falta el atributo, la receta añade el código del idioma activo de la tienda, por ejemplode-DE, el valor que imprime la propia plantilla base de Shopware. Cuando el tema imprime un código de configuración regional comoen_GB, que no es una etiqueta de idioma válida, la plantilla lo convierte ahora enen-GB. Una página cuyo contenido está escrito en un idioma distinto del de la tienda, como un texto legal en alemán en una tienda en inglés, queda en sus manos: el idioma de ese contenido se define en la Administración o se marca en el propio texto.- Reglas que cubre
-
-
html-has-langAUTO se comprueba mediante vs-lang -
html-lang-validAUTO se comprueba mediante vs-lang -
vs-langAUTO
-
- Tipos de archivo que modifica
-
.html.twig
normalises the locale code of the base layout; German content pages are left to the merchant Datos de ejemplo Resources/views/storefront/base.html.twig Cambios en Resources/views/storefront/base.html.twig (líneas añadidas: 1; eliminadas: 1)
Cambios en Resources/views/storefront/base.html.twig (líneas añadidas: 1; eliminadas: 1) Línea anterior Línea nueva Cambio Código 9 9 {% block base_doctype %}<!DOCTYPE html>{% endblock %} 10 10 11 11 {% block base_html %} 12 Eliminada <html lang="{{ page.lang }}" itemscope="itemscope" itemtype="https://schema.org/WebPage"> 12 Añadida <html lang="{{ page.lang|replace({'_': '-'}) }}" itemscope="itemscope" itemtype="https://schema.org/WebPage"> 13 13 {% endblock %} 14 14 15 15 {% block base_head %} -
Enlace para saltar al contenido, área principal y menús con nombre skip-link-main Según lo que haya encontrado el escaneo: un enlace para saltar al contenido principal, un área principal marcada o nombres para las áreas de navegación.
Según lo que haya encontrado el escaneo, la receta añade un enlace para saltar al contenido, marca el contenido principal o da nombre a las áreas de navegación. El enlace para saltar al contenido pasa a ser el primer elemento al que llega quien navega con el teclado en cada página. Permanece oculto hasta que recibe el foco y lleva al contenido principal. Cuando ninguna plantilla marca el contenido principal como
<main>, el área de contenido del layout base pasa a ser el área<main>de la página. El texto del enlace es el snippetgeneral.skipToContent, que en inglés dice «Skip to main content». Un enlace para saltar al contenido que ya existe pasa a apuntar al contenido principal. Las áreas de navegación sin nombre reciben uno, tomado de su encabezado o de su finalidad, como «Main navigation», «Service navigation» o «Breadcrumb». Un área de navegación cuya finalidad no está clara, o que compartiría su nombre con otra, queda en manos de una persona.- Reglas que cubre
-
-
bypassAUTO se comprueba mediante vs-headings-landmarks -
landmark-one-mainAUTO se comprueba mediante vs-headings-landmarks -
regionAUTO -
skip-linkAUTO -
vs-headings-landmarksAUTO
-
- Tipos de archivo que modifica
-
.html.twig.json.scss
adds a skip link, a <main> landmark and navigation names; the landmark problems are gone Datos de ejemplo Resources/app/storefront/src/scss/base.scss Cambios en Resources/app/storefront/src/scss/base.scss (líneas añadidas: 24; eliminadas: 0)
Cambios en Resources/app/storefront/src/scss/base.scss (líneas añadidas: 24; eliminadas: 0) Línea anterior Línea nueva Cambio Código 1708 1708 margin: 8px 0 0; 1709 1709 font-size: 0.875rem; 1710 1710 } 1711 Añadida 1712 Añadida /* validiscan:skip-link-main */ 1713 Añadida /* Skip link: parked off-screen, shown at the top left when it receives keyboard focus (WCAG 2.4.1). */ 1714 Añadida .skip-to-content-link { 1715 Añadida position: absolute; 1716 Añadida top: 8px; 1717 Añadida left: -10000px; 1718 Añadida z-index: 10000; 1719 Añadida padding: 12px 16px; 1720 Añadida border: 2px solid #1f2328; 1721 Añadida background: #ffffff; 1722 Añadida color: #1f2328; 1723 Añadida font-weight: 700; 1724 Añadida } 1725 Añadida 1726 Añadida .skip-to-content-link:focus { 1727 Añadida left: 8px; 1728 Añadida } 1729 Añadida 1730 Añadida /* The skip target takes focus programmatically; it needs no focus ring of its own. */ 1731 Añadida #content-main:focus { 1732 Añadida outline: none; 1733 Añadida } 1734 Añadida /* /validiscan:skip-link-main */ Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json Cambios en Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json (líneas añadidas: 7; eliminadas: 0)
Cambios en Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json (líneas añadidas: 7; eliminadas: 0) Línea anterior Línea nueva Cambio Código 193 193 "notFoundText": "Die gesuchte Seite existiert nicht oder wurde verschoben.", 194 194 "backToHome": "Zurück zur Startseite", 195 195 "searchInstead": "Unsere Kaffees durchsuchen" 196 Añadida }, 197 Añadida "a11y": { 198 Añadida "navigation": { 199 Añadida "breadcrumb": "Brotkrümelnavigation", 200 Añadida "service": "Servicenavigation", 201 Añadida "main": "Hauptnavigation" 202 Añadida } 196 203 } 197 204 } Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json Cambios en Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json (líneas añadidas: 7; eliminadas: 0)
Cambios en Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json (líneas añadidas: 7; eliminadas: 0) Línea anterior Línea nueva Cambio Código 193 193 "notFoundText": "The page you are looking for does not exist or has moved.", 194 194 "backToHome": "Back to the homepage", 195 195 "searchInstead": "Search our coffees" 196 Añadida }, 197 Añadida "a11y": { 198 Añadida "navigation": { 199 Añadida "breadcrumb": "Breadcrumb", 200 Añadida "service": "Service navigation", 201 Añadida "main": "Main navigation" 202 Añadida } 196 203 } 197 204 } Resources/views/storefront/base.html.twig Cambios en Resources/views/storefront/base.html.twig (líneas añadidas: 4; eliminadas: 3)
Cambios en Resources/views/storefront/base.html.twig (líneas añadidas: 4; eliminadas: 3) Línea anterior Línea nueva Cambio Código 22 22 <body class="{% block base_body_classes %}is-ctl-{{ page.controllerName }} is-act-{{ page.controllerAction }} sw-storefront sw-theme-kaffeekontor-nord{% endblock %}"> 23 23 24 24 {% block base_body_skip_to_content %} 25 Eliminada {% endblock %} 25 Añadida <a class="skip-to-content-link" href="#content-main">{{ 'general.skipToContent'|trans|sw_sanitize }}</a> 26 Añadida {% endblock %} 26 27 27 28 {% block base_body_inner %} 28 29 {% block base_noscript %} 48 49 {% endblock %} 49 50 50 51 {% block base_main %} 51 Eliminada <div class="content-main"> 52 Añadida <main class="content-main" id="content-main" tabindex="-1"> 52 53 {% block base_main_inner %} 53 54 <div class="container"> 54 55 {% block base_main_container %} 64 65 {% endblock %} 65 66 </div> 66 67 {% endblock %} 67 Eliminada </div> 68 Añadida </main> 68 69 {% endblock %} 69 70 70 71 {% block base_footer %} Resources/views/storefront/layout/breadcrumb.html.twig Cambios en Resources/views/storefront/layout/breadcrumb.html.twig (líneas añadidas: 1; eliminadas: 1)
Cambios en Resources/views/storefront/layout/breadcrumb.html.twig (líneas añadidas: 1; eliminadas: 1) Línea anterior Línea nueva Cambio Código 1 1 {% block layout_breadcrumb %} 2 Eliminada <nav class="breadcrumb-nav"> 2 Añadida <nav class="breadcrumb-nav" aria-label="{{ 'a11y.navigation.breadcrumb'|trans|striptags }}"> 3 3 <ol class="breadcrumb" itemscope itemtype="https://schema.org/BreadcrumbList"> 4 4 {% for item in items %} 5 5 <li class="breadcrumb-item{% if loop.last %} active{% endif %}" Resources/views/storefront/layout/footer/footer.html.twig Cambios en Resources/views/storefront/layout/footer/footer.html.twig (líneas añadidas: 2; eliminadas: 2)
Cambios en Resources/views/storefront/layout/footer/footer.html.twig (líneas añadidas: 2; eliminadas: 2) Línea anterior Línea nueva Cambio Código 23 23 {% block layout_footer_navigation_service %} 24 24 <div class="col-md-6 col-lg-3 footer-column"> 25 25 <div class="footer-column-headline" id="footer-headline-service">{{ 'footer.serviceMenuHeadline'|trans }}</div> 26 Eliminada <nav class="footer-column-content"> 26 Añadida <nav class="footer-column-content" aria-labelledby="footer-headline-service"> 27 27 <ul class="list-unstyled footer-service-menu-list"> 28 28 <li class="footer-service-menu-item"><a class="footer-link" href="{{ url('/contact') }}">{{ 'footer.linkContact'|trans }}</a></li> 29 29 <li class="footer-service-menu-item"><a class="footer-link" href="{{ url('/brewing-guide') }}">{{ 'footer.linkBrewingGuide'|trans }}</a></li> 38 38 {% block layout_footer_navigation_information %} 39 39 <div class="col-md-6 col-lg-3 footer-column"> 40 40 <div class="footer-column-headline" id="footer-headline-information">{{ 'footer.informationHeadline'|trans }}</div> 41 Eliminada <nav class="footer-column-content"> 41 Añadida <nav class="footer-column-content" aria-labelledby="footer-headline-information"> 42 42 <ul class="list-unstyled footer-service-menu-list"> 43 43 {% for category in categories %} 44 44 <li class="footer-service-menu-item"><a class="footer-link" href="{{ category.url }}">{{ category.name }}</a></li> Resources/views/storefront/layout/header/top-bar.html.twig Cambios en Resources/views/storefront/layout/header/top-bar.html.twig (líneas añadidas: 1; eliminadas: 1)
Cambios en Resources/views/storefront/layout/header/top-bar.html.twig (líneas añadidas: 1; eliminadas: 1) Línea anterior Línea nueva Cambio Código 1 1 {% block layout_header_top_bar %} 2 2 <div class="top-bar"> 3 Eliminada <nav class="top-bar-nav"> 3 Añadida <nav class="top-bar-nav" aria-label="{{ 'a11y.navigation.service'|trans|striptags }}"> 4 4 {% block layout_header_top_bar_usp %} 5 5 <p class="top-bar-usp"> 6 6 {% sw_icon 'checkmark' style { size: 'xs' } %} Resources/views/storefront/layout/navigation/navigation.html.twig Cambios en Resources/views/storefront/layout/navigation/navigation.html.twig (líneas añadidas: 2; eliminadas: 1)
Cambios en Resources/views/storefront/layout/navigation/navigation.html.twig (líneas añadidas: 2; eliminadas: 1) Línea anterior Línea nueva Cambio Código 3 3 <div class="container"> 4 4 {% block layout_main_navigation_menu %} 5 5 <nav class="nav main-navigation-menu" itemscope="itemscope" 6 Eliminada itemtype="https://schema.org/SiteNavigationElement"> 6 Añadida itemtype="https://schema.org/SiteNavigationElement" 7 Añadida aria-label="{{ 'a11y.navigation.main'|trans|striptags }}"> 7 8 {% block layout_main_navigation_menu_items %} 8 9 {% for item in navigation %} 9 10 {% set active = item.id == page.activeNavigationId %} -
Un título en cada página document-title-template Cuando el layout escribe en el
<title>solo el metatítulo, el nombre de la tienda pasa a ser su valor alternativo, de modo que ninguna página queda con un título vacío.Cuando el layout del tema escribe en el
<title>solo el metatítulo de la página, las categorías y las páginas CMS sin metatítulo reciben un título vacío. La receta conserva el título propio del tema y le da un valor alternativo: el nombre de la tienda, tomado de donde el tema ya lo imprime o, si no lo imprime, del nombre de la tienda en los ajustes básicos de Shopware. Así ninguna página queda con un título vacío. Un título que es solo el nombre de la tienda sigue sin decir qué es la página, de modo que esas páginas necesitan un metatítulo en la Administración. Los títulos que ya tienen un valor alternativo o un texto fijo se dejan como están.- Reglas que cubre
-
-
document-titleAUTO
-
- Tipos de archivo que modifica
-
.html.twig
gives the layout title a shop-name fallback and the empty CMS title is gone Datos de ejemplo Resources/views/storefront/layout/meta.html.twig Cambios en Resources/views/storefront/layout/meta.html.twig (líneas añadidas: 1; eliminadas: 1)
Cambios en Resources/views/storefront/layout/meta.html.twig (líneas añadidas: 1; eliminadas: 1) Línea anterior Línea nueva Cambio Código 36 36 {% endblock %} 37 37 38 38 {% block layout_head_title %} 39 Eliminada <title>{{ page.metaTitle }}</title> 39 Añadida <title>{{ page.metaTitle|default(shop.name) }}</title> 40 40 {% endblock %} 41 41 42 42 {% block layout_head_stylesheet %} -
Encabezados sin niveles omitidos heading-levels Un encabezado que se salta un nivel sube, junto con los encabezados de la plantilla que están en ese nivel o en uno más profundo, y mantiene su aspecto.
Un encabezado que se salta un nivel, como un h3 justo después de un h1, sube al nivel siguiente, y los demás encabezados de la misma plantilla que están en ese nivel o en uno más profundo suben con él, de modo que el esquema propio de la plantilla se mantiene. Cuando la plantilla define la etiqueta del encabezado en una variable, se cambia la variable. Las clases se conservan y, cuando ninguna clase fija el tamaño, una clase de encabezado de Bootstrap mantiene el aspecto anterior. En una página sin encabezado principal, el elemento que ya la titula en su propia plantilla pasa a ser el h1, con su aspecto conservado. Si una página no tiene un elemento así, la receta no añade ningún encabezado, porque un encabezado nuevo requiere redactar su texto.
- Reglas que cubre
-
-
heading-orderAUTO se comprueba mediante vs-headings-landmarks -
page-has-heading-oneAUTO se comprueba mediante vs-headings-landmarks -
vs-headings-landmarksAUTO
-
- Tipos de archivo que modifica
-
.html.twig
moves a static grid title from h3 to h2; the skipped level is gone Datos de ejemplo Resources/views/storefront/block/cms-block-product-grid.html.twig Cambios en Resources/views/storefront/block/cms-block-product-grid.html.twig (líneas añadidas: 1; eliminadas: 1)
Cambios en Resources/views/storefront/block/cms-block-product-grid.html.twig (líneas añadidas: 1; eliminadas: 1) Línea anterior Línea nueva Cambio Código 5 5 {% block block_product_grid %} 6 6 <div class="cms-block cms-block-product-grid"> 7 7 <div class="cms-block-container"> 8 Eliminada <h3 class="cms-block-title">{{ block.title }}</h3> 8 Añadida <h2 class="cms-block-title">{{ block.title }}</h2> 9 9 <div class="row cms-listing-row"> 10 10 {% for product in block.products %} 11 11 {% sw_include '@Storefront/storefront/component/product/card/box-standard.html.twig' with { product: product } %}
Uso del teclado y foco
-
Un contorno de foco visible focus-visible-styles Un contorno para el foco del teclado, en el color de marca del tema o en el tono más próximo del mismo matiz que tenga un contraste de al menos 3:1 con el fondo de la página.
La hoja de estilos principal recibe un contorno para el foco del teclado: de 2 píxeles, continuo, a 2 píxeles del elemento, en el color de marca del tema. Cuando ese color es demasiado claro, se usa el tono más próximo del mismo matiz que tenga un contraste de al menos 3:1 con el fondo de la página. Las reglas del tema que quitan el contorno al recibir el foco se aplican ahora solo al foco por ratón: un clic mantiene el aspecto del tema y el foco del teclado muestra el contorno. Las reglas que muestran el foco de otra manera se conservan. En las zonas oscuras, como una barra superior, el contorno puede necesitar un color más claro, que su desarrollador comprueba en la vista previa.
- Reglas que cubre
-
-
vs-focus-visibleAUTO
-
- Tipos de archivo que modifica
-
.scss
adds a brand-coloured :focus-visible ring and scopes the outline resets Datos de ejemplo Resources/app/storefront/src/scss/_variant-broken.scss Cambios en Resources/app/storefront/src/scss/_variant-broken.scss (líneas añadidas: 5; eliminadas: 5)
Cambios en Resources/app/storefront/src/scss/_variant-broken.scss (líneas añadidas: 5; eliminadas: 5) Línea anterior Línea nueva Cambio Código 21 21 } 22 22 23 23 /* "Remove the ugly blue ring" (vs-focus-visible). */ 24 Eliminada .header-actions-btn:focus, 25 Eliminada .header-search-btn:focus, 26 Eliminada .main-navigation-link:focus, 27 Eliminada .product-name:focus, 28 Eliminada .footer-link:focus { 24 Añadida .header-actions-btn:focus:not(:focus-visible), 25 Añadida .header-search-btn:focus:not(:focus-visible), 26 Añadida .main-navigation-link:focus:not(:focus-visible), 27 Añadida .product-name:focus:not(:focus-visible), 28 Añadida .footer-link:focus:not(:focus-visible) { 29 29 outline: 0; 30 30 box-shadow: none; 31 31 } Resources/app/storefront/src/scss/base.scss Cambios en Resources/app/storefront/src/scss/base.scss (líneas añadidas: 8; eliminadas: 0)
Cambios en Resources/app/storefront/src/scss/base.scss (líneas añadidas: 8; eliminadas: 0) Línea anterior Línea nueva Cambio Código 1708 1708 margin: 8px 0 0; 1709 1709 font-size: 0.875rem; 1710 1710 } 1711 Añadida 1712 Añadida /* validiscan:focus-visible-styles */ 1713 Añadida /* Visible keyboard focus (WCAG 2.4.7): brand colour sw-color-brand-primary, 8.9:1 on #ffffff. */ 1714 Añadida :focus-visible { 1715 Añadida outline: 2px solid #6b3f1d; 1716 Añadida outline-offset: 2px; 1717 Añadida } 1718 Añadida /* /validiscan:focus-visible-styles */ -
Un orden de tabulación que sigue el orden de la página remove-positive-tabindex Un
tabindexmayor que 0 se quita o se pone a 0, de modo que la tecla Tab recorre la página en su orden, salvo que lo escriba el código de la plantilla.Un
tabindexmayor que 0 lleva un elemento al principio del orden del teclado. La receta lo quita de los enlaces, los botones, los campos de formulario y otros elementos que reciben el foco de todos modos, y lo pone a 0 en los demás elementos, de modo que siguen siendo alcanzables y la tecla Tab recorre la página en su orden. Untabindexque escribe el código de la plantilla queda en manos de una persona. Un escaneo informa dos veces de ese orden forzado: mediante la reglatabindexde axe-core, cuyos hallazgos reciben este cambio, y mediante la comprobaciónvs-focus-orderde Validiscan, cuyo nivel es MANUAL, por lo que sus hallazgos vienen con orientación.- Reglas que cubre
-
-
tabindexAUTO -
vs-focus-orderMANUAL
-
- Tipos de archivo que modifica
-
.html.twig
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>
Zoom y zonas táctiles
-
Zoom permitido en los móviles meta-viewport-zoom La etiqueta viewport pierde
user-scalable=noy cualquiermaximum-scaleinferior a 2, para que los visitantes puedan ampliar el texto al menos hasta un 200 % en el móvil.La receta quita
user-scalable=noy cualquiermaximum-scaleinferior a 2 de la etiqueta viewport de las plantillas del storefront, normalmente enlayout/meta.html.twig, para que los visitantes puedan ampliar el texto al menos hasta un 200 % en el móvil. Para la regla de buenas prácticasmeta-viewport-largeel límite es 5. Los demás ajustes del viewport se mantienen como estaban. Si el bloqueo se puso para impedir que iOS haga zoom en los campos de formulario, un tamaño de fuente de al menos 16 píxeles en los campos lo consigue sin bloquear el zoom.- Reglas que cubre
-
-
meta-viewportAUTO -
meta-viewport-largeAUTO
-
- Tipos de archivo que modifica
-
.html.twig
removes the zoom lock from the fixture theme and the rule stops firing Datos de ejemplo Resources/views/storefront/layout/meta.html.twig Cambios en Resources/views/storefront/layout/meta.html.twig (líneas añadidas: 1; eliminadas: 1)
Cambios en Resources/views/storefront/layout/meta.html.twig (líneas añadidas: 1; eliminadas: 1) Línea anterior Línea nueva Cambio Código 6 6 7 7 {% block layout_head_meta_tags_viewport %} 8 8 {# Added by the merchant's agency to stop "zoom jumps" on iOS. #} 9 Eliminada <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> 9 Añadida <meta name="viewport" content="width=device-width, initial-scale=1"> 10 10 {% endblock %} 11 11 12 12 {% block layout_head_meta_tags_general %} -
Zonas táctiles más grandes target-size-padding Los botones y enlaces que el escaneo encontró con un tamaño inferior a 24 × 24 píxeles reciben ese tamaño mínimo, cuando la receta puede identificarlos por su clase.
Los botones y enlaces que el escaneo encontró con un tamaño inferior a 24 × 24 píxeles, como los iconos de la cabecera, los botones de cantidad o las muestras de color, reciben un tamaño mínimo de 24 × 24 píxeles. El mínimo se añade a la propia regla de estilo del tema que hizo pequeño el control, junto a la declaración que lo redujo, de modo que el orden de los estilos del tema no cambia y los iconos del interior mantienen su tamaño. Un control que es pequeño sin una regla así recibe un tamaño mínimo para su clase en la hoja de estilos principal. Un control que la receta no puede identificar por su clase queda en manos de una persona.
- Reglas que cubre
-
-
vs-target-sizeAUTO
-
- Tipos de archivo que modifica
-
.scss
gives the header icons, steppers and swatches a 24px minimum; no page reports small targets Datos de ejemplo Resources/app/storefront/src/scss/_variant-broken.scss Cambios en Resources/app/storefront/src/scss/_variant-broken.scss (líneas añadidas: 6; eliminadas: 2)
Cambios en Resources/app/storefront/src/scss/_variant-broken.scss (líneas añadidas: 6; eliminadas: 2) Línea anterior Línea nueva Cambio Código 10 10 11 11 .header-actions-btn { 12 12 width: 18px; 13 Añadida min-width: 24px; 13 14 height: 18px; 14 Eliminada min-height: 0; 15 Añadida min-height: 24px; 15 16 padding: 0; 16 17 } 17 18 96 97 /* 18 px colour swatches, 20 px quantity and remove buttons (vs-target-size). */ 97 98 .product-detail-configurator-option-input { 98 99 width: 18px; 100 Añadida min-width: 24px; 99 101 height: 18px; 102 Añadida min-height: 24px; 100 103 margin-right: 4px; 101 104 } 102 105 103 106 .quantity-selector-group .btn, 104 107 .line-item-remove-button { 105 108 width: 20px; 109 Añadida min-width: 24px; 106 110 height: 20px; 107 Eliminada min-height: 0; 111 Añadida min-height: 24px; 108 112 padding: 0; 109 113 } 110 114
Movimiento, carruseles y sonido
-
Menos movimiento cuando el visitante lo pide reduced-motion-guard Cuando el dispositivo del visitante pide reducir el movimiento, las animaciones y las transiciones que definen las hojas de estilos terminan de inmediato y se desactiva el desplazamiento suave.
Cuando el dispositivo del visitante está configurado para reducir el movimiento, un bloque de la hoja de estilos principal hace que las animaciones y las transiciones terminen de inmediato y desactiva el desplazamiento suave. El bloque se aplica a todos los elementos de la página, por lo que también cubre las animaciones que definen otras hojas de estilos, incluidas las de los plugins. Si el script de storefront del tema inicia un temporizador, como el avance automático de un carrusel, únicamente cuando hay una opción de avance automático activada, esa condición comprueba ahora también el ajuste del visitante. El resto del movimiento que inicia un script se enumera para quien revisa, y no se adivina.
- Reglas que cubre
-
-
vs-motionAUTO
-
- Tipos de archivo que modifica
-
.js.scss
guards the pulsing badge and the slider autoplay; the animation stops under reduce Datos de ejemplo Resources/app/storefront/src/main.js Cambios en Resources/app/storefront/src/main.js (líneas añadidas: 1; eliminadas: 1)
Cambios en Resources/app/storefront/src/main.js (líneas añadidas: 1; eliminadas: 1) Línea anterior Línea nueva Cambio Código 139 139 }); 140 140 }); 141 141 142 Eliminada if (options.autoplay === true) { 142 Añadida if (options.autoplay === true && !window.matchMedia('(prefers-reduced-motion: reduce)').matches) { 143 143 window.setInterval( 144 144 function () { 145 145 show(current + 1); Resources/app/storefront/src/scss/base.scss Cambios en Resources/app/storefront/src/scss/base.scss (líneas añadidas: 14; eliminadas: 0)
Cambios en Resources/app/storefront/src/scss/base.scss (líneas añadidas: 14; eliminadas: 0) Línea anterior Línea nueva Cambio Código 1708 1708 margin: 8px 0 0; 1709 1709 font-size: 0.875rem; 1710 1710 } 1711 Añadida 1712 Añadida /* validiscan:reduced-motion-guard */ 1713 Añadida /* Honour the visitor's reduced-motion setting: animations and transitions end at once, no smooth scrolling. */ 1714 Añadida @media (prefers-reduced-motion: reduce) { 1715 Añadida *, 1716 Añadida *::before, 1717 Añadida *::after { 1718 Añadida animation-duration: 0.01ms !important; 1719 Añadida animation-iteration-count: 1 !important; 1720 Añadida transition-duration: 0.01ms !important; 1721 Añadida scroll-behavior: auto !important; 1722 Añadida } 1723 Añadida } 1724 Añadida /* /validiscan:reduced-motion-guard */ -
Un botón de pausa para los carruseles en movimiento slider-pause-control El carrusel base de Shopware, el que hay detrás del carrusel de imágenes del CMS, recibe un botón visible y traducido para ponerlo en pausa y reanudarlo.
El carrusel base de Shopware, el que hay detrás del carrusel de imágenes del CMS, recibe un botón visible y traducido para ponerlo en pausa y reanudarlo, junto a sus flechas de anterior y siguiente. Un bloque de código del script de storefront del tema conecta el botón con el avance automático del carrusel mediante el plugin de carrusel propio de Shopware. Cuando el tema ejecuta el avance automático con su propio temporizador, ese temporizador recibe una línea que omite un paso mientras el carrusel está en pausa. El botón permanece oculto hasta que el script lo ha conectado, de modo que nunca aparece sin un avance automático que poner en pausa. Para los visitantes cuyo dispositivo pide reducir el movimiento, el carrusel empieza en pausa. Los carruseles creados con otras bibliotecas quedan en manos de una persona.
- Reglas que cubre
-
-
vs-carouselAUTO
-
- Tipos de archivo que modifica
-
.html.twig.js.json
adds a wired pause button to the hero slider; the carousel is no longer unstoppable Datos de ejemplo Resources/app/storefront/src/main.js Cambios en Resources/app/storefront/src/main.js (líneas añadidas: 52; eliminadas: 0)
Cambios en Resources/app/storefront/src/main.js (líneas añadidas: 52; eliminadas: 0) Línea anterior Línea nueva Cambio Código 142 142 if (options.autoplay === true) { 143 143 window.setInterval( 144 144 function () { 145 Añadida if (slider.getAttribute('data-autoplay-paused') === 'true') return; 145 146 show(current + 1); 146 147 }, 147 148 Number(options.autoplayTimeout) || 5000, 453 454 initFilterRanges(); 454 455 initToggles(); 455 456 })(); 457 Añadida 458 Añadida /* validiscan:slider-pause-control */ 459 Añadida /* 460 Añadida * Pause / play button of auto-advancing sliders (WCAG 2.2.2): wired to the 461 Añadida * slider's autoplay; sliders start paused when the visitor prefers reduced motion. 462 Añadida */ 463 Añadida (function sliderPauseControl() { 464 Añadida 'use strict'; 465 Añadida 466 Añadida function tinySlider(slider) { 467 Añadida const manager = window.PluginManager; 468 Añadida if (!manager || typeof manager.getPluginInstanceFromElement !== 'function') return null; 469 Añadida const plugin = manager.getPluginInstanceFromElement(slider, 'BaseSlider'); 470 Añadida return plugin && plugin._slider ? plugin._slider : null; 471 Añadida } 472 Añadida 473 Añadida function autoplays(slider) { 474 Añadida try { 475 Añadida const options = JSON.parse(slider.getAttribute('data-base-slider-options') || '{}') || {}; 476 Añadida return Boolean(options.slider && options.slider.autoplay); 477 Añadida } catch { 478 Añadida return false; 479 Añadida } 480 Añadida } 481 Añadida 482 Añadida function init() { 483 Añadida const reduceMotion = 484 Añadida window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; 485 Añadida document.querySelectorAll('[data-slider-pause]').forEach(function (button) { 486 Añadida const slider = button.closest('[data-base-slider]'); 487 Añadida if (!slider || !autoplays(slider)) return; 488 Añadida 489 Añadida function setPaused(paused) { 490 Añadida slider.setAttribute('data-autoplay-paused', paused ? 'true' : 'false'); 491 Añadida button.textContent = button.getAttribute(paused ? 'data-label-play' : 'data-label-pause'); 492 Añadida const instance = tinySlider(slider); 493 Añadida if (instance) instance[paused ? 'pause' : 'play'](); 494 Añadida } 495 Añadida 496 Añadida button.hidden = false; 497 Añadida button.addEventListener('click', function () { 498 Añadida setPaused(slider.getAttribute('data-autoplay-paused') !== 'true'); 499 Añadida }); 500 Añadida if (reduceMotion) setPaused(true); 501 Añadida }); 502 Añadida } 503 Añadida 504 Añadida if (document.readyState === 'complete') init(); 505 Añadida else window.addEventListener('load', init); 506 Añadida })(); 507 Añadida /* /validiscan:slider-pause-control */ Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json Cambios en Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json (líneas añadidas: 6; eliminadas: 0)
Cambios en Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json (líneas añadidas: 6; eliminadas: 0) Línea anterior Línea nueva Cambio Código 193 193 "notFoundText": "Die gesuchte Seite existiert nicht oder wurde verschoben.", 194 194 "backToHome": "Zurück zur Startseite", 195 195 "searchInstead": "Unsere Kaffees durchsuchen" 196 Añadida }, 197 Añadida "a11y": { 198 Añadida "slider": { 199 Añadida "pause": "Diashow anhalten", 200 Añadida "play": "Diashow abspielen" 201 Añadida } 196 202 } 197 203 } Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json Cambios en Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json (líneas añadidas: 6; eliminadas: 0)
Cambios en Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json (líneas añadidas: 6; eliminadas: 0) Línea anterior Línea nueva Cambio Código 193 193 "notFoundText": "The page you are looking for does not exist or has moved.", 194 194 "backToHome": "Back to the homepage", 195 195 "searchInstead": "Search our coffees" 196 Añadida }, 197 Añadida "a11y": { 198 Añadida "slider": { 199 Añadida "pause": "Pause slideshow", 200 Añadida "play": "Play slideshow" 201 Añadida } 196 202 } 197 203 } Resources/views/storefront/element/cms-element-image-slider.html.twig Cambios en Resources/views/storefront/element/cms-element-image-slider.html.twig (líneas añadidas: 1; eliminadas: 0)
Cambios en Resources/views/storefront/element/cms-element-image-slider.html.twig (líneas añadidas: 1; eliminadas: 0) Línea anterior Línea nueva Cambio Código 57 57 <button type="button" class="base-slider-controls-next image-slider-controls-btn" data-slide-next> 58 58 {% sw_icon 'arrow-head-right' %} 59 59 </button> 60 Añadida <button type="button" class="btn btn-light base-slider-pause" data-slider-pause="true" data-label-pause="{{ 'a11y.slider.pause'|trans|striptags }}" data-label-play="{{ 'a11y.slider.play'|trans|striptags }}" hidden>{{ 'a11y.slider.pause'|trans|sw_sanitize }}</button> 60 61 </div> 61 62 {% endblock %} 62 63 </div> -
Sin texto que parpadee ni se desplace remove-blink-marquee Los elementos
<blink>y<marquee>de las plantillas Twig pasan a ser elementos estáticos con el mismo contenido, las mismas clases y los mismos ids, de modo que ningún texto se mueve por sí solo.Los elementos
<blink>y<marquee>de las plantillas Twig pasan a ser elementos estáticos con el mismo contenido, las mismas clases y los mismos ids: un<span>para blink, un<div>para marquee o un<span>cuando el marquee está dentro de un párrafo o de un elemento de texto similar. Los ajustes de desplazamiento del marquee se eliminan, de modo que ningún texto se mueve por sí solo.- Reglas que cubre
-
-
blinkAUTO -
marqueeAUTO
-
- Tipos de archivo que modifica
-
.html.twig
replaces a seeded marquee and blink in the top bar; axe no longer reports them Datos de ejemplo Resources/views/storefront/layout/header/top-bar.html.twig Cambios en Resources/views/storefront/layout/header/top-bar.html.twig (líneas añadidas: 2; eliminadas: 2)
Cambios en Resources/views/storefront/layout/header/top-bar.html.twig (líneas añadidas: 2; eliminadas: 2) Línea anterior Línea nueva Cambio Código 4 4 {% block layout_header_top_bar_usp %} 5 5 <p class="top-bar-usp"> 6 6 {% sw_icon 'checkmark' style { size: 'xs' } %} 7 Eliminada <marquee class="top-bar-marquee" behavior="scroll" scrollamount="4"><span>{{ 'header.topBarUsp'|trans }}</span></marquee> 7 Añadida <span class="top-bar-marquee"><span>{{ 'header.topBarUsp'|trans }}</span></span> 8 8 </p> 9 9 {% endblock %} 10 10 13 13 <li class="top-bar-nav-item"> 14 14 <a class="top-bar-nav-link top-bar-help" href="{{ url('/contact') }}"> 15 15 {% sw_icon 'headset' style { size: 'xs' } %} 16 Eliminada <blink class="top-bar-blink">{{ 'header.topBarHelp'|trans }}</blink> 16 Añadida <span class="top-bar-blink">{{ 'header.topBarHelp'|trans }}</span> 17 17 </a> 18 18 </li> 19 19 </ul> -
Sin sonido que empiece por sí solo mute-autoplay Un vídeo que se reproduce por sí solo se silencia y el audio deja de empezar por sí solo, salvo la reproducción automática que establecen el código de una plantilla o un script y los reproductores en marcos; en Shopware la receta no se usa para los hallazgos de
vs-media.Un vídeo que se reproduce por sí solo recibe
mutedyplaysinline, de modo que sigue reproduciéndose en silencio, como un vídeo de fondo, y en Safari en los móviles se reproduce dentro de la página en lugar de abrir el reproductor a pantalla completa. El audio que empieza por sí solo deja de hacerlo; los visitantes lo inician por su cuenta. La reproducción automática que establecen el código de una plantilla o un script, y los reproductores incrustados en marcos, quedan en manos de una persona. En un escaneo de Validiscan, el sonido que empieza por sí solo lo notifica la comprobación multimediavs-media, que sustituye a la reglano-autoplay-audiode axe-core.vs-media, que también cubre los subtítulos y las transcripciones, es MANUAL, así que en Shopware un hallazgo así viene con orientación en lugar de con este cambio.- Reglas que cubre
-
-
no-autoplay-audioAUTO se comprueba mediante vs-media -
vs-mediaMANUAL
-
- Tipos de archivo que modifica
-
.html.twig
mutes a seeded autoplaying background video; vs-media no longer reports autoplay Datos de ejemplo Resources/views/storefront/block/cms-block-video.html.twig Cambios en Resources/views/storefront/block/cms-block-video.html.twig (líneas añadidas: 1; eliminadas: 1)
Cambios en Resources/views/storefront/block/cms-block-video.html.twig (líneas añadidas: 1; eliminadas: 1) Línea anterior Línea nueva Cambio Código 9 9 <h2 class="cms-block-title">{{ block.title }}</h2> 10 10 <p class="cms-video-text">{{ block.text }}</p> 11 11 <div class="cms-element-video"> 12 Eliminada <video class="cms-video" autoplay loop preload="none" width="1280" height="720" poster="{{ block.posterUrl }}"> 12 Añadida <video class="cms-video" autoplay loop preload="none" width="1280" height="720" poster="{{ block.posterUrl }}" muted playsinline> 13 13 <source src="{{ block.videoUrl }}" type="video/mp4"> 14 14 {% if block.captionsUrl %} 15 15 <track kind="captions" src="{{ block.captionsUrl }}" srclang="en" label="{{ 'general.captionsEnglish'|trans }}" default>
Formularios, carrito y contenido incrustado
-
Etiquetas conectadas a sus campos label-association Un campo cuyo texto de etiqueta ya está en la página, justo antes del campo, se conecta con ese texto.
Un campo de formulario cuyo texto de etiqueta ya está en la página, justo antes del campo, se conecta con ese texto. Un
<label>sinforrecibe uno que apunta al campo. Un elemento de texto que el tema marca como título o etiqueta por su clase, como el nombre de un grupo de variantes en una página de producto, pasa a ser el<label>del campo, con sus clases y su propia línea. Los lectores de pantalla leen entonces la etiqueta cuando el campo recibe el foco. Un campo que solo tiene un placeholder queda en manos de una persona, porque redactar una etiqueta es una decisión de contenido.- Reglas que cubre
-
-
labelAUTO se comprueba mediante vs-forms-ecommerce -
select-nameASSISTED -
vs-forms-ecommerceAUTO
-
- Tipos de archivo que modifica
-
.html.twig
turns the variant group titles into labels of their selects; select-name no longer fires Datos de ejemplo Resources/views/storefront/page/product-detail/configurator.html.twig Cambios en Resources/views/storefront/page/product-detail/configurator.html.twig (líneas añadidas: 1; eliminadas: 1)
Cambios en Resources/views/storefront/page/product-detail/configurator.html.twig (líneas añadidas: 1; eliminadas: 1) Línea anterior Línea nueva Cambio Código 13 13 {% for group in product.configurator %} 14 14 {% if group.display == 'select' %} 15 15 <div class="product-detail-configurator-group"> 16 Eliminada <div class="product-detail-configurator-group-title">{{ group.name }}</div> 16 Añadida <label class="product-detail-configurator-group-title" for="configurator-{{ group.id }}">{{ group.name }}</label> 17 17 <select class="form-select product-detail-configurator-select-input" 18 18 id="configurator-{{ group.id }}" 19 19 name="{{ group.id }}"{% if group.price|default(false) %} -
Campos de cuenta, dirección y contacto que los navegadores pueden rellenar autocomplete-tokens Los campos que piden datos propios del cliente, como los de los formularios de registro, dirección e inicio de sesión, reciben el valor de
autocompletecorrespondiente a lo que piden, salvo que lo escriba el código de una plantilla.Los campos que piden datos propios del cliente, como los de los formularios de registro, dirección, inicio de sesión, contacto y boletín informativo, reciben el valor de
autocompletecorrespondiente a lo que piden, como correo electrónico, nombre y apellidos, código postal, número de teléfono o contraseña. El valor se deduce del tipo, el nombre, el id, la etiqueta y el placeholder del campo. Las contraseñas recibennew-passworden los formularios de registro ycurrent-passworden los demás. Los campos de búsqueda, de cupón, de cantidad, de captcha y de mensaje se dejan como están, y un valor que escribe el código de una plantilla queda en manos de una persona. Así, los navegadores pueden rellenar los campos y los productos de apoyo pueden saber para qué sirve cada uno.- Reglas que cubre
-
-
autocomplete-validAUTO se comprueba mediante vs-forms-ecommerce -
vs-forms-ecommerceAUTO
-
- Tipos de archivo que modifica
-
.html.twig
adds tokens to the register, address, login, contact and newsletter fields; no autocomplete hits remain Datos de ejemplo Resources/views/storefront/component/account/login.html.twig Cambios en Resources/views/storefront/component/account/login.html.twig (líneas añadidas: 1; eliminadas: 1)
Cambios en Resources/views/storefront/component/account/login.html.twig (líneas añadidas: 1; eliminadas: 1) Línea anterior Línea nueva Cambio Código 19 19 name="username" 20 20 placeholder="{{ 'account.loginMailPlaceholder'|trans }}" 21 21 required 22 Eliminada autocomplete="off"> 22 Añadida autocomplete="email"> 23 23 </div> 24 24 25 25 <div class="form-group"> Resources/views/storefront/component/account/register.html.twig Cambios en Resources/views/storefront/component/account/register.html.twig (líneas añadidas: 8; eliminadas: 4)
Cambios en Resources/views/storefront/component/account/register.html.twig (líneas añadidas: 8; eliminadas: 4) Línea anterior Línea nueva Cambio Código 33 33 id="{{ formId }}FirstName" 34 34 name="firstName" 35 35 placeholder="{{ 'account.firstNamePlaceholder'|trans }}" 36 Eliminada required> 36 Añadida required 37 Añadida autocomplete="given-name"> 37 38 </div> 38 39 <div class="form-group col-sm-6"> 39 40 <input type="text" 41 42 id="{{ formId }}LastName" 42 43 name="lastName" 43 44 placeholder="{{ 'account.lastNamePlaceholder'|trans }}" 44 Eliminada required> 45 Añadida required 46 Añadida autocomplete="family-name"> 45 47 </div> 46 48 </div> 47 49 <div class="row g-2"> 52 54 id="{{ formId }}Mail" 53 55 name="email" 54 56 placeholder="{{ 'account.emailPlaceholder'|trans }}" 55 Eliminada required> 57 Añadida required 58 Añadida autocomplete="email"> 56 59 </div> 57 60 <div class="form-group col-sm-6"> 58 61 <label class="form-label" for="{{ formId }}Password">{{ 'account.passwordLabel'|trans }}</label> 62 65 name="password" 63 66 minlength="8" 64 67 aria-describedby="{{ formId }}PasswordHint" 65 Eliminada required> 68 Añadida required 69 Añadida autocomplete="new-password"> 66 70 <small class="form-text" id="{{ formId }}PasswordHint">{{ 'account.passwordHint'|trans }}</small> 67 71 </div> 68 72 </div> Resources/views/storefront/component/address/address-form.html.twig Cambios en Resources/views/storefront/component/address/address-form.html.twig (líneas añadidas: 8; eliminadas: 4)
Cambios en Resources/views/storefront/component/address/address-form.html.twig (líneas añadidas: 8; eliminadas: 4) Línea anterior Línea nueva Cambio Código 14 14 id="{{ prefix }}AddressStreet" 15 15 name="{{ prefix }}[street]" 16 16 placeholder="{{ 'address.streetPlaceholder'|trans }}" 17 Eliminada required> 17 Añadida required 18 Añadida autocomplete="address-line1"> 18 19 </div> 19 20 {% endblock %} 20 21 26 27 name="{{ prefix }}[zipcode]" 27 28 placeholder="{{ 'address.zipcodePlaceholder'|trans }}" 28 29 inputmode="numeric" 29 Eliminada required> 30 Añadida required 31 Añadida autocomplete="postal-code"> 30 32 </div> 31 33 {% endblock %} 32 34 37 39 class="form-control" 38 40 id="{{ prefix }}AddressCity" 39 41 name="{{ prefix }}[city]" 40 Eliminada required> 42 Añadida required 43 Añadida autocomplete="address-level2"> 41 44 </div> 42 45 {% endblock %} 43 46 47 50 <select class="form-select" 48 51 id="{{ prefix }}AddressCountry" 49 52 name="{{ prefix }}[countryId]" 50 Eliminada required> 53 Añadida required 54 Añadida autocomplete="country"> 51 55 {% for country in countries %} 52 56 <option value="{{ country.id }}"{% if loop.first %} selected{% endif %}>{{ country.name }}</option> 53 57 {% endfor %} Resources/views/storefront/element/cms-element-form.html.twig Cambios en Resources/views/storefront/element/cms-element-form.html.twig (líneas añadidas: 4; eliminadas: 4)
Cambios en Resources/views/storefront/element/cms-element-form.html.twig (líneas añadidas: 4; eliminadas: 4) Línea anterior Línea nueva Cambio Código 18 18 </select> 19 19 </div> 20 20 <div class="form-group col-md-4"> 21 Eliminada <input type="text" class="form-control" id="contactFormFirstName" name="firstName" placeholder="{{ 'account.firstNamePlaceholder'|trans }}" required> 21 Añadida <input type="text" class="form-control" id="contactFormFirstName" name="firstName" placeholder="{{ 'account.firstNamePlaceholder'|trans }}" required autocomplete="given-name"> 22 22 </div> 23 23 <div class="form-group col-md-4"> 24 Eliminada <input type="text" class="form-control" id="contactFormLastName" name="lastName" placeholder="{{ 'account.lastNamePlaceholder'|trans }}" required> 24 Añadida <input type="text" class="form-control" id="contactFormLastName" name="lastName" placeholder="{{ 'account.lastNamePlaceholder'|trans }}" required autocomplete="family-name"> 25 25 </div> 26 26 </div> 27 27 28 28 <div class="row g-2"> 29 29 <div class="form-group col-md-6"> 30 30 <label class="form-label" for="contactFormMail">{{ 'account.emailLabel'|trans }}</label> 31 Eliminada <input type="email" class="form-control" id="contactFormMail" name="email" placeholder="{{ 'account.emailPlaceholder'|trans }}" required> 31 Añadida <input type="email" class="form-control" id="contactFormMail" name="email" placeholder="{{ 'account.emailPlaceholder'|trans }}" required autocomplete="email"> 32 32 </div> 33 33 <div class="form-group col-md-6"> 34 34 <label class="form-label" for="contactFormPhone">{{ 'contact.phoneLabel'|trans }}</label> 35 Eliminada <input type="tel" class="form-control" id="contactFormPhone" name="phone"> 35 Añadida <input type="tel" class="form-control" id="contactFormPhone" name="phone" autocomplete="tel"> 36 36 </div> 37 37 </div> 38 38 Resources/views/storefront/layout/footer/footer.html.twig Cambios en Resources/views/storefront/layout/footer/footer.html.twig (líneas añadidas: 2; eliminadas: 1)
Cambios en Resources/views/storefront/layout/footer/footer.html.twig (líneas añadidas: 2; eliminadas: 1) Línea anterior Línea nueva Cambio Código 62 62 id="footerNewsletterMail" 63 63 class="form-control" 64 64 placeholder="{{ 'footer.newsletterPlaceholder'|trans }}" 65 Eliminada required> 65 Añadida required 66 Añadida autocomplete="email"> 66 67 <button type="submit" class="btn btn-primary newsletter-submit">{{ 'footer.newsletterSubmit'|trans }}</button> 67 68 </div> 68 69 <div class="form-check newsletter-privacy"> -
Cambios de precio, de existencias y del carrito anunciados live-region-cart-variant El precio, la disponibilidad o los totales del carrito que el script del storefront actualiza en el mismo sitio pasan a ser regiones dinámicas que los lectores de pantalla leen sin interrumpir, salvo que un script sustituya el propio elemento.
Las partes de una página que el script del storefront actualiza en el mismo sitio, como el precio después de que un cliente elija una variante, la disponibilidad o los totales del carrito, pasan a ser regiones dinámicas de tipo polite. Los lectores de pantalla leen entonces el valor nuevo una vez, completo y sin interrumpir. Cuando un script sustituye el propio elemento en lugar de su contenido, una región dinámica no funcionaría, así que la receta deja ese elemento en manos de una persona.
- Reglas que cubre
-
-
vs-live-updatesAUTO
-
- Tipos de archivo que modifica
-
.html.twig
makes the variant price and the cart totals polite live regions; the updates are announced Datos de ejemplo Resources/views/storefront/page/checkout/cart/index.html.twig Cambios en Resources/views/storefront/page/checkout/cart/index.html.twig (líneas añadidas: 2; eliminadas: 2)
Cambios en Resources/views/storefront/page/checkout/cart/index.html.twig (líneas añadidas: 2; eliminadas: 2) Línea anterior Línea nueva Cambio Código 59 59 <span class="line-item-unit-price-label">{{ 'checkout.cartHeaderUnitPrice'|trans }}:</span> 60 60 <span class="line-item-unit-price-value">{{ item.unitPrice|currency }}*</span> 61 61 </div> 62 Eliminada <div class="line-item-total-price"> 62 Añadida <div class="line-item-total-price" aria-live="polite" aria-atomic="true"> 63 63 <span class="line-item-total-price-label">{{ 'checkout.cartHeaderTotalPrice'|trans }}:</span> 64 64 <span class="line-item-total-price-value" data-line-total>{{ item.totalPrice|currency }}*</span> 65 65 </div> 88 88 <div class="col-lg-4 checkout-aside"> 89 89 <div class="checkout-aside-summary"> 90 90 <h2 class="checkout-aside-summary-header">{{ 'checkout.summaryHeader'|trans }}</h2> 91 Eliminada <div class="checkout-aside-summary-totals" data-shipping-threshold="{{ shop.shippingThreshold }}" data-shipping-costs="{{ shop.shippingCosts }}"> 91 Añadida <div class="checkout-aside-summary-totals" data-shipping-threshold="{{ shop.shippingThreshold }}" data-shipping-costs="{{ shop.shippingCosts }}" aria-live="polite" aria-atomic="true"> 92 92 <dl class="checkout-aside-summary-list"> 93 93 <dt class="checkout-aside-summary-label">{{ 'checkout.summaryPositionPrice'|trans }}</dt> 94 94 <dd class="checkout-aside-summary-value" data-cart-subtotal>{{ cart.subtotal|currency }}*</dd> 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 17 17 {% endblock %} 18 18 19 19 {% block buy_widget_price %} 20 Eliminada <div class="product-detail-price-container"> 20 Añadida <div class="product-detail-price-container" aria-live="polite" aria-atomic="true"> 21 21 <meta itemprop="priceCurrency" content="{{ shop.currency.isoCode }}"> 22 22 <meta itemprop="price" content="{{ product.price }}"> 23 23 <p class="product-detail-price{% if product.listPrice %} with-list-price{% endif %}" data-price-display>{{ product.price|currency }}*</p> -
Títulos para mapas y vídeos incrustados iframe-title Un marco incrustado sin título recibe un título traducido que dice qué muestra, cuando el código lo revela.
Un marco incrustado sin título, como un mapa o un vídeo de YouTube o de Vimeo, recibe un título traducido, tomado de los archivos de snippets del tema, que dice qué muestra. La receta lee lo que muestra el marco a partir de su dirección, de su clase y su nombre, o de la plantilla que lo rodea. Un marco cuyo contenido no revela el código no recibe ningún título de la receta, porque un título inventado es peor que ninguno.
- Reglas que cubre
-
-
frame-titleAUTO
-
- Tipos de archivo que modifica
-
.html.twig.json
titles the contact map frame through the snippets; frame-title no longer fires Datos de ejemplo Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json Cambios en Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json (líneas añadidas: 5; eliminadas: 0)
Cambios en Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json (líneas añadidas: 5; eliminadas: 0) Línea anterior Línea nueva Cambio Código 193 193 "notFoundText": "Die gesuchte Seite existiert nicht oder wurde verschoben.", 194 194 "backToHome": "Zurück zur Startseite", 195 195 "searchInstead": "Unsere Kaffees durchsuchen" 196 Añadida }, 197 Añadida "a11y": { 198 Añadida "iframe": { 199 Añadida "map": "Karte" 200 Añadida } 196 201 } 197 202 } Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json Cambios en Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json (líneas añadidas: 5; eliminadas: 0)
Cambios en Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json (líneas añadidas: 5; eliminadas: 0) Línea anterior Línea nueva Cambio Código 193 193 "notFoundText": "The page you are looking for does not exist or has moved.", 194 194 "backToHome": "Back to the homepage", 195 195 "searchInstead": "Search our coffees" 196 Añadida }, 197 Añadida "a11y": { 198 Añadida "iframe": { 199 Añadida "map": "Map" 200 Añadida } 196 201 } 197 202 } Resources/views/storefront/block/cms-block-map.html.twig Cambios en Resources/views/storefront/block/cms-block-map.html.twig (líneas añadidas: 2; eliminadas: 1)
Cambios en Resources/views/storefront/block/cms-block-map.html.twig (líneas añadidas: 2; eliminadas: 1) Línea anterior Línea nueva Cambio Código 11 11 <iframe class="cms-map-frame" 12 12 src="{{ url('/widgets/cms/map') }}" 13 13 width="1280" 14 Eliminada height="360"></iframe> 14 Añadida height="360" 15 Añadida title="{{ 'a11y.iframe.map'|trans|striptags }}"></iframe> 15 16 </div> 16 17 <p class="cms-map-address">{{ shop.company.street }}, {{ shop.company.zip }} {{ shop.company.city }}</p> 17 18 </div>
Contraste, imágenes y controles que requieren criterio
El contraste del texto, las alternativas textuales de las imágenes y los nombres de los controles sin nombre suelen requerir criterio: qué color encaja con su marca, qué palabras describen una imagen. Las reglas que los notifican tienen el nivel ASSISTED, como muestran las listas de más abajo. Para un hallazgo de una regla ASSISTED, la IA redacta un cambio solo si usted ha aceptado la redacción con IA, y Validiscan revisa cada cambio antes de entregarlo.
Las cuatro recetas siguientes no son la corrección estándar de ninguna regla. Cada una cubre solo los casos acotados en los que el código del tema por sí solo demuestra cuál debe ser el cambio. Dos de ellas, button-semantics e icon-accessible-name, también cubren la comprobación de carruseles vs-carousel, que es AUTO: en un proyecto, el motor de correcciones las prueba en sus hallazgos cuando la receta del botón de pausa de más arriba no puede corregirlos. Las otras dos cubren solo reglas de nivel ASSISTED.
-
Colores de texto con contraste suficiente contrast-tokens Un color de texto que no supera la comprobación de contraste y está definido en un solo lugar pasa al tono más próximo del mismo matiz con el contraste requerido; la receta no se aplica en un proyecto.
Cuando un texto no supera la comprobación de contraste y su color está definido en un solo lugar del tema, ese lugar pasa al tono más próximo del mismo matiz que alcanza el contraste requerido, de modo que el diseño sigue siendo reconocible. Un solo lugar puede ser un campo de color de
theme.jsonjunto con la variable SCSS que lo repite, una variable SCSS o una propiedad personalizada de CSS que se usa solo para texto, o una única declaracióncolor. Un color que se usa en varios lugares o también como fondo o borde, y los campos de color básicos de Shopware para la marca, los bordes, los fondos, los mensajes de estado y el botón de compra, quedan en manos de una persona. Un color guardado en los ajustes del tema de la Administración prevalece sobretheme.json: si se cambió allí, también hay que cambiarlo allí. La reglacolor-contrasttiene el nivel ASSISTED, así que en un proyecto un hallazgo de contraste sigue la vía ASSISTED y esta receta no se le aplica.- Reglas que cubre
-
-
color-contrastASSISTED
-
- Tipos de archivo que modifica
-
.scss
darkens the unit price colour to 4.5:1 with the same hue; axe clears it on both pages Datos de ejemplo Resources/app/storefront/src/scss/_variant-broken.scss Cambios en Resources/app/storefront/src/scss/_variant-broken.scss (líneas añadidas: 1; eliminadas: 1)
Cambios en Resources/app/storefront/src/scss/_variant-broken.scss (líneas añadidas: 1; eliminadas: 1) Línea anterior Línea nueva Cambio Código 45 45 /* Light grey unit prices, 3.1:1 (color-contrast). */ 46 46 .product-price-unit, 47 47 .product-detail-price-unit { 48 Eliminada color: #929292; 48 Añadida color: #757575; 49 49 } 50 50 51 51 /* Fixed two-line product names (vs-text-spacing). */ -
Imágenes decorativas ocultas a los lectores de pantalla decorative-image-alt Solo las imágenes que la plantilla demuestra decorativas reciben un
altvacío oaria-hidden; la receta no se aplica en un proyecto.Una imagen se marca como decorativa solo cuando la plantilla demuestra que no aporta nada: está dentro de un enlace o un botón que ya tiene nombre por otra vía, es un icono junto a su propia etiqueta de texto, o es un espaciador o un separador. Un
<img>recibe unaltvacío, una imagen que imprime la etiquetasw_thumbnailsde Shopware recibe unaltvacío en sus atributos y los iconos SVG recibenaria-hidden="true", de modo que los lectores de pantalla los omiten en lugar de leer en voz alta el nombre de un archivo. Cualquier otra imagen es contenido, como los logotipos de los medios de pago del pie de página, y su alternativa textual necesita palabras que elige una persona. Las reglas que cubre esta receta tienen el nivel ASSISTED, así que en un proyecto sus hallazgos siguen la vía ASSISTED y esta receta no se les aplica.- Reglas que cubre
-
-
image-altASSISTED -
role-img-altASSISTED -
svg-img-altASSISTED
-
- Tipos de archivo que modifica
-
.html.twig
marks a seeded phone icon inside the hotline link decorative; image-alt stops firing there Datos de ejemplo Resources/views/storefront/layout/footer/footer.html.twig Cambios en Resources/views/storefront/layout/footer/footer.html.twig (líneas añadidas: 1; eliminadas: 1)
Cambios en Resources/views/storefront/layout/footer/footer.html.twig (líneas añadidas: 1; eliminadas: 1) Línea anterior Línea nueva Cambio Código 9 9 <div class="footer-column-content"> 10 10 <p class="footer-contact-hotline"> 11 11 {{ 'footer.serviceHotlineText'|trans }} 12 Eliminada <a class="footer-contact-hotline-link" href="tel:+49405550192"><img src="{{ asset('bundles/storefront/assets/icon/default/headset.svg') }}" class="footer-contact-hotline-icon" width="16" height="16"> {{ shop.company.phone }}</a> 12 Añadida <a class="footer-contact-hotline-link" href="tel:+49405550192"><img src="{{ asset('bundles/storefront/assets/icon/default/headset.svg') }}" class="footer-contact-hotline-icon" width="16" height="16" alt=""> {{ shop.company.phone }}</a> 13 13 </p> 14 14 <p class="footer-contact-hours">{{ 'footer.serviceHours'|trans }}</p> 15 15 <p class="footer-contact-form"> -
Nombres para botones y enlaces que solo muestran un icono icon-accessible-name Los botones y enlaces que solo muestran un icono reciben un nombre traducido que dice qué hacen, cuando el código revela su finalidad; en un proyecto, la receta se prueba en los controles de carrusel que notifica
vs-carousel.Los botones y enlaces que solo muestran un icono, como la búsqueda, el carrito, la cuenta, el enlace del logotipo, las flechas del carrusel, los botones de cantidad y las opciones de cookies, reciben un
aria-labeltraducido que dice qué hacen. La finalidad se deduce de las clases del control, del destino de su enlace, del icono que contiene y del componente que lo rodea. Un control cuya finalidad no revela el código, como un enlace a una red social cuya red se guarda como dato, queda en manos de una persona, porque un nombre inventado es peor que ninguno. En un proyecto, esta receta se prueba en los controles de carrusel que notificavs-carousel; los demás controles que solo tienen un icono los notifican reglas de nivel ASSISTED y siguen la vía ASSISTED.- Reglas que cubre
-
-
button-nameASSISTED -
link-nameASSISTED -
vs-carouselAUTO -
vs-cookie-bannerASSISTED
-
- Tipos de archivo que modifica
-
.html.twig.json
names every icon-only button of the home, product and cart pages; button-name no longer fires Datos de ejemplo Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json Cambios en Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json (líneas añadidas: 12; eliminadas: 0)
Cambios en Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json (líneas añadidas: 12; eliminadas: 0) Línea anterior Línea nueva Cambio Código 193 193 "notFoundText": "Die gesuchte Seite existiert nicht oder wurde verschoben.", 194 194 "backToHome": "Zurück zur Startseite", 195 195 "searchInstead": "Unsere Kaffees durchsuchen" 196 Añadida }, 197 Añadida "a11y": { 198 Añadida "control": { 199 Añadida "search": "Suchen", 200 Añadida "previousSlide": "Vorherige Folie", 201 Añadida "nextSlide": "Nächste Folie", 202 Añadida "cookieSettings": "Cookie-Einstellungen", 203 Añadida "acceptCookies": "Alle Cookies akzeptieren", 204 Añadida "decreaseQuantity": "Menge verringern", 205 Añadida "increaseQuantity": "Menge erhöhen", 206 Añadida "removeFromCart": "Aus dem Warenkorb entfernen" 207 Añadida } 196 208 } 197 209 } Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json Cambios en Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json (líneas añadidas: 12; eliminadas: 0)
Cambios en Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json (líneas añadidas: 12; eliminadas: 0) Línea anterior Línea nueva Cambio Código 193 193 "notFoundText": "The page you are looking for does not exist or has moved.", 194 194 "backToHome": "Back to the homepage", 195 195 "searchInstead": "Search our coffees" 196 Añadida }, 197 Añadida "a11y": { 198 Añadida "control": { 199 Añadida "search": "Search", 200 Añadida "previousSlide": "Previous slide", 201 Añadida "nextSlide": "Next slide", 202 Añadida "cookieSettings": "Cookie settings", 203 Añadida "acceptCookies": "Accept all cookies", 204 Añadida "decreaseQuantity": "Decrease quantity", 205 Añadida "increaseQuantity": "Increase quantity", 206 Añadida "removeFromCart": "Remove from cart" 207 Añadida } 196 208 } 197 209 } Resources/views/storefront/element/cms-element-image-gallery.html.twig Cambios en Resources/views/storefront/element/cms-element-image-gallery.html.twig (líneas añadidas: 2; eliminadas: 2)
Cambios en Resources/views/storefront/element/cms-element-image-gallery.html.twig (líneas añadidas: 2; eliminadas: 2) Línea anterior Línea nueva Cambio Código 31 31 32 32 {% if media|length > 1 %} 33 33 <div class="gallery-slider-controls"> 34 Eliminada <button type="button" class="base-slider-controls-prev gallery-slider-controls-prev" data-gallery-prev> 34 Añadida <button type="button" class="base-slider-controls-prev gallery-slider-controls-prev" data-gallery-prev aria-label="{{ 'a11y.control.previousSlide'|trans|striptags }}"> 35 35 {% sw_icon 'arrow-head-left' %} 36 36 </button> 37 Eliminada <button type="button" class="base-slider-controls-next gallery-slider-controls-next" data-gallery-next> 37 Añadida <button type="button" class="base-slider-controls-next gallery-slider-controls-next" data-gallery-next aria-label="{{ 'a11y.control.nextSlide'|trans|striptags }}"> 38 38 {% sw_icon 'arrow-head-right' %} 39 39 </button> 40 40 </div> Resources/views/storefront/element/cms-element-image-slider.html.twig Cambios en Resources/views/storefront/element/cms-element-image-slider.html.twig (líneas añadidas: 2; eliminadas: 2)
Cambios en Resources/views/storefront/element/cms-element-image-slider.html.twig (líneas añadidas: 2; eliminadas: 2) Línea anterior Línea nueva Cambio Código 46 46 47 47 {% block element_image_slider_controls %} 48 48 <div class="image-slider-controls-container"> 49 Eliminada <button type="button" class="base-slider-controls-prev image-slider-controls-btn" data-slide-prev> 49 Añadida <button type="button" class="base-slider-controls-prev image-slider-controls-btn" data-slide-prev aria-label="{{ 'a11y.control.previousSlide'|trans|striptags }}"> 50 50 {% sw_icon 'arrow-head-left' %} 51 51 </button> 52 52 <ol class="base-slider-dots"> 54 54 <li class="base-slider-dot{% if loop.first %} is-active{% endif %}" data-slide-to="{{ loop.index0 }}"></li> 55 55 {% endfor %} 56 56 </ol> 57 Eliminada <button type="button" class="base-slider-controls-next image-slider-controls-btn" data-slide-next> 57 Añadida <button type="button" class="base-slider-controls-next image-slider-controls-btn" data-slide-next aria-label="{{ 'a11y.control.nextSlide'|trans|striptags }}"> 58 58 {% sw_icon 'arrow-head-right' %} 59 59 </button> 60 60 </div> Resources/views/storefront/layout/cookie/cookie-permission.html.twig Cambios en Resources/views/storefront/layout/cookie/cookie-permission.html.twig (líneas añadidas: 2; eliminadas: 2)
Cambios en Resources/views/storefront/layout/cookie/cookie-permission.html.twig (líneas añadidas: 2; eliminadas: 2) Línea anterior Línea nueva Cambio Código 22 22 </p> 23 23 </div> 24 24 <div class="col-auto cookie-permission-actions"> 25 Eliminada <button type="button" class="btn cookie-permission-icon-btn js-cookie-configuration-toggle">{% sw_icon 'settings' %}</button> 26 Eliminada <button type="button" class="btn btn-primary cookie-permission-icon-btn js-cookie-accept-all-button">{% sw_icon 'checkmark' %}</button> 25 Añadida <button type="button" class="btn cookie-permission-icon-btn js-cookie-configuration-toggle" aria-label="{{ 'a11y.control.cookieSettings'|trans|striptags }}">{% sw_icon 'settings' %}</button> 26 Añadida <button type="button" class="btn btn-primary cookie-permission-icon-btn js-cookie-accept-all-button" aria-label="{{ 'a11y.control.acceptCookies'|trans|striptags }}">{% sw_icon 'checkmark' %}</button> 27 27 </div> 28 28 </div> 29 29 <p class="cookie-permission-configuration" hidden>{{ 'cookie.configurationText'|trans }}</p> Resources/views/storefront/layout/header/search.html.twig Cambios en Resources/views/storefront/layout/header/search.html.twig (líneas añadidas: 1; eliminadas: 1)
Cambios en Resources/views/storefront/layout/header/search.html.twig (líneas añadidas: 1; eliminadas: 1) Línea anterior Línea nueva Cambio Código 13 13 autocomplete="off" 14 14 autocapitalize="off" 15 15 placeholder="{{ 'header.searchPlaceholder'|trans }}" value="{{ page.searchTerm }}"> 16 Eliminada <button type="submit" class="btn header-search-btn"> 16 Añadida <button type="submit" class="btn header-search-btn" aria-label="{{ 'a11y.control.search'|trans|striptags }}"> 17 17 <span class="header-search-icon">{% sw_icon 'search' %}</span> 18 18 </button> 19 19 </div> Resources/views/storefront/page/checkout/cart/index.html.twig Cambios en Resources/views/storefront/page/checkout/cart/index.html.twig (líneas añadidas: 3; eliminadas: 3)
Cambios en Resources/views/storefront/page/checkout/cart/index.html.twig (líneas añadidas: 3; eliminadas: 3) Línea anterior Línea nueva Cambio Código 39 39 </div> 40 40 <div class="line-item-quantity"> 41 41 <div class="input-group quantity-selector-group" data-quantity-selector="true"> 42 Eliminada <button type="button" class="btn btn-outline-light btn-minus js-btn-minus"> 42 Añadida <button type="button" class="btn btn-outline-light btn-minus js-btn-minus" aria-label="{{ 'a11y.control.decreaseQuantity'|trans|striptags }}"> 43 43 {% sw_icon 'minus' style { size: 'xs' } %} 44 44 </button> 45 45 <input type="number" 50 50 max="100" 51 51 step="1" 52 52 value="{{ item.quantity }}"> 53 Eliminada <button type="button" class="btn btn-outline-light btn-plus js-btn-plus"> 53 Añadida <button type="button" class="btn btn-outline-light btn-plus js-btn-plus" aria-label="{{ 'a11y.control.increaseQuantity'|trans|striptags }}"> 54 54 {% sw_icon 'plus' style { size: 'xs' } %} 55 55 </button> 56 56 </div> 64 64 <span class="line-item-total-price-value" data-line-total>{{ item.totalPrice|currency }}*</span> 65 65 </div> 66 66 <div class="line-item-remove"> 67 Eliminada <button type="button" class="btn btn-light btn-sm line-item-remove-button"> 67 Añadida <button type="button" class="btn btn-light btn-sm line-item-remove-button" aria-label="{{ 'a11y.control.removeFromCart'|trans|striptags }}"> 68 68 {% sw_icon 'x' style { size: 'xs' } %} 69 69 </button> 70 70 </div> 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: 2; eliminadas: 2)
Cambios en Resources/views/storefront/page/product-detail/buy-widget.html.twig (líneas añadidas: 2; eliminadas: 2) Línea anterior Línea nueva Cambio Código 64 64 <div class="buy-widget-container"> 65 65 <div class="buy-widget-quantity"> 66 66 <div class="input-group quantity-selector-group" data-quantity-selector="true"> 67 Eliminada <button type="button" class="btn btn-outline-light btn-minus js-btn-minus"> 67 Añadida <button type="button" class="btn btn-outline-light btn-minus js-btn-minus" aria-label="{{ 'a11y.control.decreaseQuantity'|trans|striptags }}"> 68 68 {% sw_icon 'minus' style { size: 'xs' } %} 69 69 </button> 70 70 <input type="number" 75 75 max="100" 76 76 step="1" 77 77 value="1"> 78 Eliminada <button type="button" class="btn btn-outline-light btn-plus js-btn-plus"> 78 Añadida <button type="button" class="btn btn-outline-light btn-plus js-btn-plus" aria-label="{{ 'a11y.control.increaseQuantity'|trans|striptags }}"> 79 79 {% sw_icon 'plus' style { size: 'xs' } %} 80 80 </button> 81 81 </div> names the logo and account links; social links whose network is data are left for review Datos de ejemplo Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json Cambios en Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json (líneas añadidas: 6; eliminadas: 0)
Cambios en Resources/snippet/de_DE/kaffeekontor-nord.de-DE.json (líneas añadidas: 6; eliminadas: 0) Línea anterior Línea nueva Cambio Código 193 193 "notFoundText": "Die gesuchte Seite existiert nicht oder wurde verschoben.", 194 194 "backToHome": "Zurück zur Startseite", 195 195 "searchInstead": "Unsere Kaffees durchsuchen" 196 Añadida }, 197 Añadida "a11y": { 198 Añadida "control": { 199 Añadida "home": "Zur Startseite", 200 Añadida "account": "Ihr Konto" 201 Añadida } 196 202 } 197 203 } Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json Cambios en Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json (líneas añadidas: 6; eliminadas: 0)
Cambios en Resources/snippet/en_GB/kaffeekontor-nord.en-GB.json (líneas añadidas: 6; eliminadas: 0) Línea anterior Línea nueva Cambio Código 193 193 "notFoundText": "The page you are looking for does not exist or has moved.", 194 194 "backToHome": "Back to the homepage", 195 195 "searchInstead": "Search our coffees" 196 Añadida }, 197 Añadida "a11y": { 198 Añadida "control": { 199 Añadida "home": "Go to the homepage", 200 Añadida "account": "Your account" 201 Añadida } 196 202 } 197 203 } Resources/views/storefront/layout/header/actions.html.twig Cambios en Resources/views/storefront/layout/header/actions.html.twig (líneas añadidas: 2; eliminadas: 1)
Cambios en Resources/views/storefront/layout/header/actions.html.twig (líneas añadidas: 2; eliminadas: 1) Línea anterior Línea nueva Cambio Código 3 3 {% block layout_header_actions_account %} 4 4 <div class="header-account"> 5 5 <a href="{{ url('/account/login') }}" 6 Eliminada class="btn account-menu-btn header-actions-btn"> 6 Añadida class="btn account-menu-btn header-actions-btn" 7 Añadida aria-label="{{ 'a11y.control.account'|trans|striptags }}"> 7 8 {% sw_icon 'avatar' %} 8 9 </a> 9 10 </div> Resources/views/storefront/layout/header/logo.html.twig Cambios en Resources/views/storefront/layout/header/logo.html.twig (líneas añadidas: 1; eliminadas: 1)
Cambios en Resources/views/storefront/layout/header/logo.html.twig (líneas añadidas: 1; eliminadas: 1) Línea anterior Línea nueva Cambio Código 2 2 <div class="header-logo-main"> 3 3 {% block layout_header_logo_link %} 4 4 {# The agency removed the default title="Go to homepage" and the image alt to "avoid duplicate announcements". #} 5 Eliminada <a class="header-logo-main-link" href="{{ url('/') }}"> 5 Añadida <a class="header-logo-main-link" href="{{ url('/') }}" aria-label="{{ 'a11y.control.home'|trans|striptags }}"> 6 6 {% block layout_header_logo_image %} 7 7 <picture class="header-logo-picture"> 8 8 <img src="{{ asset('bundles/storefront/assets/logo/kaffeekontor-nord-logo.svg') }}"
Detalles: los niveles, el tema de prueba, las comprobaciones de cada cambio y el texto en los idiomas de su tienda
Una receta es un cambio determinista para un tipo de fallo: el mismo código recibe siempre el mismo cambio. Validiscan tiene 20 recetas para temas de Shopware. Cada una hace un cambio solo donde el código del tema muestra cuál es el cambio correcto. Donde no lo muestra, la receta no cambia nada. No adivina.
Debajo de cada receta encontrará las reglas que cubre, con el nivel de cada regla en el catálogo de Validiscan para Shopware. AUTO significa que una receta es la corrección estándar de la regla. ASSISTED significa que la corrección requiere criterio, así que se redacta un cambio y después se revisa. MANUAL significa que la regla requiere la decisión de una persona y viene con orientación, no con un cambio de código. En un proyecto, las recetas se aplican a los hallazgos de reglas de nivel AUTO. Cuando una receta enumera también una regla de nivel ASSISTED o MANUAL, un hallazgo de esa regla sigue en su lugar la vía ASSISTED o MANUAL. Una regla que se comprueba mediante otra comprobación no se ejecuta por sí sola en un escaneo; la otra comprobación informa del mismo fallo.
Los tipos de archivo y el antes y el después de cada receta proceden de las pruebas propias de Validiscan. Se ejecutan en el tema de prueba de Shopware de Validiscan, un plugin de tema sobre el storefront predeterminado de Shopware 6 con fallos de accesibilidad introducidos a propósito. Cada prueba renderiza las plantillas del tema como páginas, antes y después del cambio, y ejecuta la misma regla en ambas: el fallo debe notificarse antes y ya no después, y el cambio no debe causar ningún fallo nuevo de esa regla. Las páginas las genera un renderizador de pruebas, no una instalación completa de Shopware, y los archivos de su tema serán distintos.
Antes de que Validiscan revise un cambio, se comprueba cada archivo modificado. Las plantillas Twig se analizan con las etiquetas propias de Shopware, como sw_extends y sw_include, reconocidas por el analizador; nunca se compilan ni se ejecutan. Las hojas de estilos pasan una comprobación de estructura, los archivos de snippets y el theme.json se analizan como JSON y el JavaScript pasa una comprobación de sintaxis.
Cuando una receta añade texto visible o un nombre, como las palabras de un enlace para saltar al contenido o el nombre de un botón de icono, usa un snippet en la plantilla. El texto va al archivo de snippets en inglés del tema, que la receta crea si el tema no tiene ninguno, y a su archivo de snippets en alemán cuando el tema tiene uno. Los snippets que ya existen conservan su texto. No se añade texto para los demás idiomas de su tienda.
¿Qué sigue siendo MANUAL en Shopware?
Los fallos que requieren una decisión sobre el contenido o el comportamiento que un cambio de código fijo no puede tomar, por ejemplo subtítulos y transcripciones de sus vídeos y su audio, siguen siendo MANUAL en Shopware. Para un hallazgo de una regla MANUAL, Validiscan da orientación sobre cómo corregirlo, no un cambio en su código.
Las reglas de más abajo se ejecutan en los escaneos y tienen el nivel MANUAL en Shopware.
-
meta-refreshNo debe usarse una actualización diferida de menos de 20 horas -
nested-interactiveLos controles interactivos no deben estar anidados -
scrollable-region-focusableLas zonas desplazables deben ser accesibles con el teclado -
server-side-image-mapNo deben usarse mapas de imagen del lado del servidor -
vs-keyboard-trapEl foco del teclado nunca debe quedar atrapado -
vs-focus-orderEl orden del foco debe seguir el orden visual -
vs-draggingLos controles que solo funcionan arrastrando necesitan una alternativa con un solo puntero -
vs-mediaLos vídeos necesitan subtítulos, el audio necesita una transcripción y nada debe reproducirse automáticamente con sonido -
vs-documentsLos documentos enlazados necesitan una revisión manual de accesibilidad
Detalles: qué recibe un hallazgo MANUAL y lo que un proyecto deja fuera
Para un hallazgo de una regla MANUAL, Validiscan da orientación sobre cómo corregirlo, no un cambio en su código. Estos fallos requieren una decisión sobre el contenido o el comportamiento que un cambio de código fijo no puede tomar, por ejemplo los subtítulos y las transcripciones de sus vídeos y su audio, una forma de salir de un widget que atrapa el foco del teclado, o una segunda forma de usar un control que solo funciona arrastrando.
El trabajo que suponen los hallazgos MANUAL que requieren decisiones sobre su propio contenido no forma parte de un proyecto, como tampoco los PDF. Qué comprueba el escaneo de forma automática y qué se revisa a mano
¿Qué aporta usted?
Usted aporta permiso para un escaneo completo, una vía de acceso a su plugin de tema, su respuesta sobre la redacción con IA de correcciones ASSISTED, un desarrollador que revise los cambios, compile el tema y lo despliegue, ajustes de la Administración, texto nuevo en idiomas que no sean inglés ni alemán y sus decisiones sobre lo que sigue siendo MANUAL.
- Su permiso para un escaneo completo de su tienda, que Validiscan registra antes del escaneo. Un escaneo completo añade un producto al carrito y abre el primer paso del proceso de pago, sin completar una compra ni introducir datos de pago.
- Una vía de acceso a su tema: acceso al repositorio de GitHub que contiene el plugin del tema, o un ZIP de la carpeta del plugin en
custom/plugins, subido en el portal del cliente. - Su respuesta sobre si la IA puede redactar correcciones de nivel ASSISTED. La redacción con IA está desactivada hasta que usted lo acepte.
- Un desarrollador que revise los cambios, fusione el pull request o aplique el paquete de parches, compile el tema y lo despliegue.
- Los ajustes de la Administración de Shopware que las correcciones no cambian: los metatítulos de las páginas que no tienen ninguno, el idioma del contenido escrito en un idioma distinto del de su tienda, y un color guardado en los ajustes del tema cuando una corrección de contraste cambia ese color.
- El texto para los idiomas de su tienda distintos del inglés y del alemán, cuando una corrección añade texto nuevo.
- Sus decisiones sobre lo que sigue siendo MANUAL, como los subtítulos de sus vídeos.
Detalles: cuando los cambios están en producción y qué cubre un proyecto
Cuando los cambios están en producción, un escaneo de verificación vuelve a comprobar las páginas afectadas y el Remediation Evidence Package registra el resultado. Cómo se desarrolla un proyecto, paso a paso
Un proyecto cubre una tienda: un dominio y un tema. Es para un storefront basado en un tema; un storefront headless se atiende bajo petición.
Fuentes
2 fuentes, todas comprobadas para esta página el 6 de octubre de 2026.
Documentación de Shopware para desarrolladores 2
- Add SCSS Styling and JavaScript to a Theme · Shopware · comprobado el
- Add custom JavaScript · Shopware · comprobado el
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 gratuitaO 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