Les images doivent avoir une alternative textuelle
Les clients aveugles ou malvoyants comptent sur leur lecteur d’écran pour savoir ce que montre une image. Les photos de produits, les bannières et les logos sans alternative textuelle sont annoncés par leur nom de fichier ou ignorés : ces clients ne savent pas de quelle couleur, de quel modèle ou de quelle offre il s’agit, et risquent d’abandonner leur achat.
- Identifiant de la règle
- image-alt
- Source
- axe-core 4.13.0
- Impact
- Critique
- Niveau de correction
- ASSISTED
- sur Shopify, Shopware, WooCommerce et Magento
- Statut
- exécutée
Ce que fait le contrôle
Vérifier que les éléments <img> ont une alternative textuelle ou un rôle none ou presentation
La règle teste chaque <img> que les technologies d’assistance peuvent atteindre, en ignorant les images masquées par display: none ou aria-hidden="true" sur l’image ou sur un ancêtre. Un <img> doté d’un autre role valide est ignoré lui aussi, sauf si ce rôle exige un nom accessible ou si l’image est focalisable.
Une image réussit dans l’un de ces cas : un attribut alt, même un alt="" vide ; un aria-label non vide ; un aria-labelledby qui pointe vers un élément contenant du texte ; un title contenant du texte ; ou un rôle résolu none ou presentation. Ce rôle est ignoré sur une image focalisable ou porteuse d’un attribut ARIA global comme aria-live. Un alt composé uniquement d’espaces échoue, sauf si le rôle est un rôle de présentation.
Par défaut, le scanner de Validiscan exécute la règle en taille ordinateur et en taille mobile ; une image masquée par display: none à l’une des tailles n’est donc testée qu’à l’autre. La règle vérifie qu’une alternative textuelle existe, pas sa formulation ; elle ne décide pas si une image est décorative ni si son texte lui correspond.
Comment corriger
Ajoutez un attribut alt à chaque <img>. Pour les images informatives et les images-liens, décrivez ce que l’image montre ou ce qu’elle fait, par exemple le nom du produit et sa variante de couleur ; réservez alt="" aux images purement décoratives. Dans les thèmes, renseignez alt à partir du champ de texte alternatif des médias dans l’administration de la boutique, avec le titre du produit comme valeur de repli.
Critères de succès WCAG
- 1.1.1 Non-text Content, niveau A
Clauses de la norme EN 301 549
| Critère WCAG | Version 3.2.1 | Version 4.1.1 |
|---|---|---|
| 1.1.1 | 9.1.1.1 | 9.1.1.1 |
Recettes qui énumèrent cette règle
Cette règle a le niveau ASSISTED. Dans un projet, un constat de cette règle suit la voie ASSISTED, et ces recettes ne lui sont pas appliquées.
Shopify : recette decorative-image-alt
Afficher l’avant et l’après (1)
sections/footer.liquid Modifications apportées à sections/footer.liquid (lignes ajoutées : 1, lignes supprimées : 1)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 12 | 12 | <input type="hidden" name="contact[tags]" value="newsletter"> | |
| 13 | 13 | <div class="newsletter-form__field-wrapper"> | |
| 14 | 14 | <input type="email" name="contact[email]" class="field__input" placeholder="{{ 'newsletter.label' | t }}" autocorrect="off" autocapitalize="off"> | |
| 15 | Supprimée | <button type="submit" class="button newsletter-form__button" name="commit"><img src="{{ 'logo.svg' | asset_url }}" class="newsletter-form__icon" width="16" height="16">{{ 'newsletter.button' | t }}</button> | |
| 15 | Ajoutée | <button type="submit" class="button newsletter-form__button" name="commit"><img src="{{ 'logo.svg' | asset_url }}" class="newsletter-form__icon" width="16" height="16" alt="">{{ 'newsletter.button' | t }}</button> | |
| 16 | 16 | </div> | |
| 17 | 17 | {%- endform -%} | |
| 18 | 18 | </div> |
sections/header.liquid Modifications apportées à sections/header.liquid (lignes ajoutées : 1, lignes supprimées : 1)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 46 | 46 | ||
| 47 | 47 | <div class="header__icons"> | |
| 48 | 48 | {%- if section.settings.show_help_link %} | |
| 49 | Supprimée | <a href="{{ section.settings.help_link_url }}" class="header__utility-link link"><svg class="header__utility-icon" role="img" viewBox="0 0 24 24" width="16" height="16"><circle cx="12" cy="12" r="9"/></svg>{{ section.settings.help_link_label | escape }}</a> | |
| 49 | Ajoutée | <a href="{{ section.settings.help_link_url }}" class="header__utility-link link"><svg class="header__utility-icon" viewBox="0 0 24 24" width="16" height="16" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9"/></svg>{{ section.settings.help_link_label | escape }}</a> | |
| 50 | 50 | {%- endif %} | |
| 51 | 51 | <a href="{{ routes.account_login_url }}" class="header__icon header__icon--account link"> | |
| 52 | 52 | {%- render 'icon', icon: 'account', size: icon_size -%} |
Shopify : recette icon-accessible-name
Afficher l’avant et l’après (2)
locales/en.default.json Modifications apportées à locales/en.default.json (lignes ajoutées : 3, lignes supprimées : 1)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 34 | 34 | "total_reviews": "{{ count }} reviews", | |
| 35 | 35 | "link_messages": { | |
| 36 | 36 | "new_window": "Opens in a new window." | |
| 37 | Supprimée | } | |
| 37 | Ajoutée | }, | |
| 38 | Ajoutée | "accept_cookies": "Accept cookies", | |
| 39 | Ajoutée | "reject_cookies": "Reject cookies" | |
| 38 | 40 | }, | |
| 39 | 41 | "sections": { | |
| 40 | 42 | "header": { |
sections/header.liquid Modifications apportées à sections/header.liquid (lignes ajoutées : 1, lignes supprimées : 0)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 40 | 40 | <input class="search__input field__input" type="search" name="q" value="" placeholder="{{ 'general.search.placeholder' | t }}" tabindex="1"> | |
| 41 | 41 | <button type="submit" class="search__button"> | |
| 42 | 42 | {%- render 'icon', icon: 'search', size: 20 -%} | |
| 43 | Ajoutée | <span class="visually-hidden">{{ 'general.search.search' | t }}</span> | |
| 43 | 44 | </button> | |
| 44 | 45 | </form> | |
| 45 | 46 | </div> |
sections/main-product.liquid Modifications apportées à sections/main-product.liquid (lignes ajoutées : 1, lignes supprimées : 1)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 88 | 88 | <p class="form__label">{{ option.name | escape }}</p> | |
| 89 | 89 | <div class="swatch-list swatch-list--compact"> | |
| 90 | 90 | {%- for swatch in option.swatches %} | |
| 91 | Supprimée | <button type="button" class="swatch swatch--button{% if swatch.selected %} swatch--active{% endif %}" style="--swatch-color: {{ swatch.color }};" data-option-index="{{ option_index }}" data-value="{{ swatch.value | escape }}"></button> | |
| 91 | Ajoutée | <button type="button" class="swatch swatch--button{% if swatch.selected %} swatch--active{% endif %}" style="--swatch-color: {{ swatch.color }};" data-option-index="{{ option_index }}" data-value="{{ swatch.value | escape }}"><span class="visually-hidden">{{ swatch.value | escape }}</span></button> | |
| 92 | 92 | {%- endfor %} | |
| 93 | 93 | </div> | |
| 94 | 94 | </div> |
sections/slideshow.liquid Modifications apportées à sections/slideshow.liquid (lignes ajoutées : 2, lignes supprimées : 0)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 59 | 59 | <div class="slideshow__controls"> | |
| 60 | 60 | <button type="button" class="slider-button slider-button--prev" name="previous" data-slide-prev> | |
| 61 | 61 | {%- render 'icon', icon: 'chevron-left', size: 20 -%} | |
| 62 | Ajoutée | <span class="visually-hidden">{{ 'accessibility.previous_slide' | t }}</span> | |
| 62 | 63 | </button> | |
| 63 | 64 | <div class="slider-counter"> | |
| 64 | 65 | {%- for block in section.blocks %} | |
| 67 | 68 | </div> | |
| 68 | 69 | <button type="button" class="slider-button slider-button--next" name="next" data-slide-next> | |
| 69 | 70 | {%- render 'icon', icon: 'chevron-right', size: 20 -%} | |
| 71 | Ajoutée | <span class="visually-hidden">{{ 'accessibility.next_slide' | t }}</span> | |
| 70 | 72 | </button> | |
| 71 | 73 | </div> | |
| 72 | 74 | </slideshow-component> |
snippets/cookie-banner.liquid Modifications apportées à snippets/cookie-banner.liquid (lignes ajoutées : 2, lignes supprimées : 0)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 23 | 23 | <div class="cookie-banner__actions"> | |
| 24 | 24 | <button type="button" class="cookie-banner__icon-button cookie-banner__icon-button--accept" data-cookie-accept> | |
| 25 | 25 | {%- render 'icon', icon: 'check', size: 20 -%} | |
| 26 | Ajoutée | <span class="visually-hidden">{{ 'accessibility.accept_cookies' | t }}</span> | |
| 26 | 27 | </button> | |
| 27 | 28 | <button type="button" class="cookie-banner__icon-button" data-cookie-reject> | |
| 28 | 29 | {%- render 'icon', icon: 'close', size: 20 -%} | |
| 30 | Ajoutée | <span class="visually-hidden">{{ 'accessibility.reject_cookies' | t }}</span> | |
| 29 | 31 | </button> | |
| 30 | 32 | </div> | |
| 31 | 33 | </div> |
snippets/quantity-input.liquid Modifications apportées à snippets/quantity-input.liquid (lignes ajoutées : 2, lignes supprimées : 0)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 9 | 9 | {%- endcomment -%} | |
| 10 | 10 | <div class="quantity quantity--compact" data-quantity{% if line %} data-line="{{ line }}"{% endif %}><button class="quantity__button" name="minus" type="button" data-quantity-minus> | |
| 11 | 11 | {%- render 'icon', icon: 'minus', size: 12 -%} | |
| 12 | Ajoutée | <span class="visually-hidden">{{ 'products.product.quantity.decrease' | t: product: product_title }}</span> | |
| 12 | 13 | </button> | |
| 13 | 14 | <input class="quantity__input" type="number" name="{{ input_name }}" id="{{ input_id }}" value="{{ value | default: 1 }}" min="{% if line %}0{% else %}1{% endif %}" data-quantity-input> | |
| 14 | 15 | <button class="quantity__button" name="plus" type="button" data-quantity-plus> | |
| 15 | 16 | {%- render 'icon', icon: 'plus', size: 12 -%} | |
| 17 | Ajoutée | <span class="visually-hidden">{{ 'products.product.quantity.increase' | t: product: product_title }}</span> | |
| 16 | 18 | </button></div> |
sections/footer.liquid Modifications apportées à sections/footer.liquid (lignes ajoutées : 1, lignes supprimées : 0)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 37 | 37 | {%- for social in shop.social %} | |
| 38 | 38 | <a href="{{ social.url }}" class="list-social__link link"> | |
| 39 | 39 | {%- render 'icon', icon: social.icon, size: 20 -%} | |
| 40 | Ajoutée | <span class="visually-hidden">{{ 'general.social.links.' | append: social.icon | t }}</span> | |
| 40 | 41 | </a> | |
| 41 | 42 | {%- endfor %} | |
| 42 | 43 | </ul> |
sections/header.liquid Modifications apportées à sections/header.liquid (lignes ajoutées : 3, lignes supprimées : 1)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 22 | 22 | </details> | |
| 23 | 23 | ||
| 24 | 24 | {% if logo_is_heading %}<h1 class="header__heading">{% else %}<div class="header__heading">{% endif %} | |
| 25 | Supprimée | <a href="{{ routes.root_url }}" class="header__heading-link"><img src="{{ 'logo.svg' | asset_url }}" width="{{ settings.logo_width }}" height="32" class="header__heading-logo"></a> | |
| 25 | Ajoutée | <a href="{{ routes.root_url }}" class="header__heading-link"><img src="{{ 'logo.svg' | asset_url }}" width="{{ settings.logo_width }}" height="32" class="header__heading-logo" alt="{{ shop.name | escape }}"></a> | |
| 26 | 26 | {% if logo_is_heading %}</h1>{% else %}</div>{% endif %} | |
| 27 | 27 | ||
| 28 | 28 | <nav class="header__inline-menu"> | |
| 50 | 50 | {%- endif %} | |
| 51 | 51 | <a href="{{ routes.account_login_url }}" class="header__icon header__icon--account link"> | |
| 52 | 52 | {%- render 'icon', icon: 'account', size: icon_size -%} | |
| 53 | Ajoutée | <span class="visually-hidden">{{ 'sections.header.account' | t }}</span> | |
| 53 | 54 | </a> | |
| 54 | 55 | <a href="{{ routes.cart_url }}" class="header__icon header__icon--cart link" id="cart-icon-bubble"> | |
| 55 | 56 | {%- render 'icon', icon: 'cart', size: icon_size -%} | |
| 57 | 58 | <span class="cart-count-bubble" aria-hidden="true"><span data-cart-count>{{ cart.item_count }}</span></span> | |
| 58 | 59 | {%- endif -%} | |
| 59 | 60 | ||
| 61 | Ajoutée | <span class="visually-hidden">{{ 'sections.header.cart' | t }}</span> | |
| 60 | 62 | </a> | |
| 61 | 63 | </div> | |
| 62 | 64 | </header> |
sections/main-cart.liquid Modifications apportées à sections/main-cart.liquid (lignes ajoutées : 1, lignes supprimées : 0)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 26 | 26 | {% render 'quantity-input', input_id: qty_id, input_name: 'updates[]', value: item.quantity, product_title: item.product.title, line: line %} | |
| 27 | 27 | <a href="{{ routes.cart_change_url }}?line={{ line }}&quantity=0" class="cart-item__remove cart-item__remove--compact" data-cart-remove> | |
| 28 | 28 | {%- render 'icon', icon: 'trash', size: 16 -%} | |
| 29 | Ajoutée | <span class="visually-hidden">{{ 'sections.cart.remove' | t: title: item.product.title }}</span> | |
| 29 | 30 | </a> | |
| 30 | 31 | </div> | |
| 31 | 32 | <div class="cart-item__totals"> |
Shopware : recette decorative-image-alt
Afficher l’avant et l’après (1)
Resources/views/storefront/layout/footer/footer.html.twig Modifications apportées à Resources/views/storefront/layout/footer/footer.html.twig (lignes ajoutées : 1, lignes supprimées : 1)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 9 | 9 | <div class="footer-column-content"> | |
| 10 | 10 | <p class="footer-contact-hotline"> | |
| 11 | 11 | {{ 'footer.serviceHotlineText'|trans }} | |
| 12 | Supprimée | <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 | Ajoutée | <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"> |
WooCommerce : recette decorative-image-alt
Afficher l’avant et l’après (1)
header.php Modifications apportées à header.php (lignes ajoutées : 1, lignes supprimées : 1)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 39 | 39 | <div class="site-branding"> | |
| 40 | 40 | <a href="<?php echo esc_url( home_url( '/' ) ); ?>" class="custom-logo-link" rel="home"> | |
| 41 | 41 | <?php // VALIDISCAN-SEED svg-img-alt: the logo mark is role="img" without a title or aria-label. ?> | |
| 42 | Supprimée | <svg class="kb-logo-mark" role="img" width="40" height="40" viewBox="0 0 40 40"><path d="M3 30c6-11 15-17 29-18-7 3-10 8-11 13 6-4 11-5 17-4-9 2-15 8-19 15L3 30Z" fill="#1d3b53"/></svg> | |
| 42 | Ajoutée | <svg class="kb-logo-mark" width="40" height="40" viewBox="0 0 40 40" aria-hidden="true" focusable="false"><path d="M3 30c6-11 15-17 29-18-7 3-10 8-11 13 6-4 11-5 17-4-9 2-15 8-19 15L3 30Z" fill="#1d3b53"/></svg> | |
| 43 | 43 | <span class="kb-logo-text"><?php bloginfo( 'name' ); ?></span> | |
| 44 | 44 | </a> | |
| 45 | 45 | </div> |
Magento : recette decorative-image-alt
Afficher l’avant et l’après (1)
app/design/frontend/Validiscan/fixture/Magento_Cms/content/home.html Modifications apportées à app/design/frontend/Validiscan/fixture/Magento_Cms/content/home.html (lignes ajoutées : 1, lignes supprimées : 1)
| Ligne avant | Ligne après | Modification | Code |
|---|---|---|---|
| 111 | 111 | <div class="block-promo-wrapper block-promo-hp"> | |
| 112 | 112 | <!-- VALIDISCAN-SEEDED image-alt: promo image without an alt attribute --> | |
| 113 | 113 | <a class="block-promo home-main" href="/magento/women/tops-women/jackets-women.html"> | |
| 114 | Supprimée | <img src="/magento/media/wysiwyg/home/home-main.svg" width="400" height="240" /> | |
| 114 | Ajoutée | <img src="/magento/media/wysiwyg/home/home-main.svg" width="400" height="240" alt="" /> | |
| 115 | 115 | <span class="content" | |
| 116 | 116 | ><!-- VALIDISCAN-SEEDED color-contrast: .info text is #929292 on white (3.1:1) --><span | |
| 117 | 117 | class="info" |
Commencez par une vérification gratuite de votre boutique.
Envoyez l’adresse de votre boutique. Validiscan la scanne et vous envoie chaque échec que le scan peut prouver, avec sa page et son code.
Demander une vérification gratuiteOu écrivez à info@validiscan.com.
Ce que couvre la vérification gratuite, et ce qu’elle laisse de côté- Vous envoyez
- l’adresse de votre boutique
- Pages scannées
- jusqu’à 15
- Vous recevez
- chaque échec que le scan peut prouver, avec la page et le code
- Sur votre boutique
- pages publiques uniquement ; aucune connexion, aucun achat, aucun formulaire envoyé
- Ce qu’elle n’est pas
- un audit complet