Änderungen an Preis, Variante, Bestand und Warenkorb müssen angesagt werden

Wählt jemand eine Größe und ändern sich dadurch Preis oder Verfügbarkeit, oder legt jemand ein Produkt in den Warenkorb, bemerken sehende Kundinnen und Kunden die Änderung. Menschen, die einen Screenreader nutzen, hören nichts und wissen daher nicht, dass das Produkt hinzugefügt wurde oder dass die gewählte Größe ausverkauft ist.

Regel-ID
vs-live-updates
Quelle
Validiscan-Prüfung
Auswirkung
Schwerwiegend
Korrekturstufe
AUTO
auf Shopify, Shopware, WooCommerce und Magento
Status
wird ausgeführt

Was geprüft wird

Erkennt Änderungen an Preis, Variante, Bestand und Warenkorb auf Produkt- und Warenkorbseiten, die ohne Live-Region erfolgen, sowie aria-live-Regionen, die die ganze Seite umschließen (4.1.3).

Die Prüfung läuft nur auf Produkt- und Warenkorbseiten. Gemeldet wird jedes aria-live="polite" oder "assertive" an html, body, main oder an einem Element, das main enthält.

Die Prüfung ändert ein einziges Bedienelement außerhalb von Header, Navigation, Footer und Dialogen und unterbindet dabei das Absenden von Formularen. Auf der Produktseite ist das das erste select für Varianten (benannt nach Größe, Farbe oder Ähnlichem oder im Produktbereich gelegen), sonst eine Radiobutton-Gruppe für Varianten, sonst Farbfeld-Schaltflächen, von denen eine ausgewählt ist. Auf der Warenkorbseite ist es das erste Mengenfeld, dessen Wert die Prüfung um eins ändert.

Vorher und nachher liest die Prüfung Texte von bis zu 120 Zeichen, deren itemprop, Klasse oder id auf einen Preis, den Bestand, die Anzahl im Warenkorb oder eine Summe hindeutet, außerdem die Schaltfläche „In den Warenkorb“. Die Seite hat bis zu 2 Sekunden Zeit, zur Ruhe zu kommen. Ein geänderter sichtbarer Text wird gemeldet, es sei denn, er liegt in einer Live-Region oder enthält eine (aria-live="polite" oder "assertive", role="status", "alert", "log", output), oder eine andere Live-Region hat eine Änderung angesagt (bei Preis und Bestand eine, die den neuen Wert enthält). Eine Änderung, die beim Zurücksetzen des Bedienelements nicht wieder verschwindet, landet bei „zu prüfen“ und wird derzeit nicht zum Befund.

So wird es behoben

Ergänzen Sie eine kleine, dauerhaft vorhandene Live-Region (role="status" oder aria-live="polite") für Preis, Bestand und Anzahl im Warenkorb, und aktualisieren Sie ihren Text, wenn sich die Variante oder der Warenkorb ändert. Setzen Sie aria-live nicht auf große Container oder die ganze Seite, sonst lesen Screenreader alles erneut vor.

WCAG-Erfolgskriterien

Abschnitte der EN 301 549

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

Wo ein Rezept es behebt

Shopify: Rezept live-region-cart-variant

Vorher und nachher anzeigen (1)
Vorher und nachher Beispieldaten

sections/main-cart.liquid Änderungen an sections/main-cart.liquid: 1 hinzugefügt, 1 entfernt

Änderungen an sections/main-cart.liquid: 1 hinzugefügt, 1 entfernt
Zeile vorher Zeile nachher Änderung Code
37 37
38 38 <div class="cart__footer">
39 39 <h2 class="cart__summary-title">Order summary</h2>
40 Entfernt <p class="totals">
40 Hinzugefügt <p class="totals" role="status">
41 41 <span class="totals__label">{{ 'sections.cart.subtotal' | t }}</span>
42 42 <span class="totals__value" data-cart-subtotal>{{ cart.total_price | money_with_currency }}</span>
43 43 </p>

sections/main-product.liquid Änderungen an sections/main-product.liquid: 1 hinzugefügt, 1 entfernt

Änderungen an sections/main-product.liquid: 1 hinzugefügt, 1 entfernt
Zeile vorher Zeile nachher Änderung Code
71 71 </div>
72 72 {%- endif %}
73 73
74 Entfernt <div class="product__price" data-price-container>
74 Hinzugefügt <div class="product__price" data-price-container role="status">
75 75 {% render 'price', product: product, use_variant: true %}
76 76 <p class="product__inventory" data-stock>{% if current_variant.available %}{{ 'products.product.in_stock' | t }}{% else %}{{ 'products.product.out_of_stock' | t }}{% endif %}</p>
77 77 <p class="product__sku">{{ 'products.product.sku' | t }}: <span data-sku>{{ current_variant.sku }}</span></p>

Shopware: Rezept live-region-cart-variant

Vorher und nachher anzeigen (1)
makes the variant price and the cart totals polite live regions; the updates are announced Beispieldaten

Resources/views/storefront/page/checkout/cart/index.html.twig Änderungen an Resources/views/storefront/page/checkout/cart/index.html.twig: 2 hinzugefügt, 2 entfernt

Änderungen an Resources/views/storefront/page/checkout/cart/index.html.twig: 2 hinzugefügt, 2 entfernt
Zeile vorher Zeile nachher Änderung Code
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 Entfernt <div class="line-item-total-price">
62 Hinzugefügt <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 Entfernt <div class="checkout-aside-summary-totals" data-shipping-threshold="{{ shop.shippingThreshold }}" data-shipping-costs="{{ shop.shippingCosts }}">
91 Hinzugefügt <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 Änderungen an Resources/views/storefront/page/product-detail/buy-widget.html.twig: 1 hinzugefügt, 1 entfernt

Änderungen an Resources/views/storefront/page/product-detail/buy-widget.html.twig: 1 hinzugefügt, 1 entfernt
Zeile vorher Zeile nachher Änderung Code
17 17 {% endblock %}
18 18
19 19 {% block buy_widget_price %}
20 Entfernt <div class="product-detail-price-container">
20 Hinzugefügt <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>

WooCommerce: Rezept live-region-cart-variant

Vorher und nachher anzeigen (2)
adds a status region next to the header cart fragment and wires the theme script Beispieldaten

assets/js/theme.js Änderungen an assets/js/theme.js: 15 hinzugefügt, 0 entfernt

Änderungen an assets/js/theme.js: 15 hinzugefügt, 0 entfernt
Zeile vorher Zeile nachher Änderung Code
255 255 initCheckout();
256 256 initShowPassword();
257 257 })();
258 Hinzugefügt
259 Hinzugefügt /* validiscan:live-region-cart-variant */
260 Hinzugefügt // Announces cart changes in the status region next to the header cart (WCAG 4.1.3).
261 Hinzugefügt (function () {
262 Hinzugefügt const region = document.querySelector('[data-kb-cart-status]');
263 Hinzugefügt if (!region || !window.jQuery) return;
264 Hinzugefügt window.jQuery(document.body).on('added_to_cart removed_from_cart', (event) => {
265 Hinzugefügt const message = region.getAttribute(event.type === 'added_to_cart' ? 'data-added' : 'data-removed');
266 Hinzugefügt region.textContent = '';
267 Hinzugefügt window.setTimeout(() => {
268 Hinzugefügt region.textContent = message || '';
269 Hinzugefügt }, 100);
270 Hinzugefügt });
271 Hinzugefügt })();
272 Hinzugefügt /* /validiscan:live-region-cart-variant */

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

Änderungen an header.php: 1 hinzugefügt, 0 entfernt
Zeile vorher Zeile nachher Änderung Code
67 67 <?php kb_icon( 'bag' ); ?><span class="kb-cart-amount"><?php echo wp_kses_post( WC()->cart->get_cart_subtotal() ); ?></span>
68 68 <span class="count"><?php echo esc_html( sprintf( _n( '%d item', '%d items', WC()->cart->get_cart_contents_count(), 'storefront' ), WC()->cart->get_cart_contents_count() ) ); ?></span>
69 69 </a>
70 Hinzugefügt <span class="screen-reader-text" role="status" data-kb-cart-status data-added="<?php esc_attr_e( 'Product added to your cart.', 'kestrel-birch' ); ?>" data-removed="<?php esc_attr_e( 'Product removed from your cart.', 'kestrel-birch' ); ?>"></span>
70 71 </li>
71 72 </ul>
72 73 </div>
makes the variation price and stock of the fixture theme a polite live region Beispieldaten

woocommerce/single-product/add-to-cart/variable.php Änderungen an woocommerce/single-product/add-to-cart/variable.php: 1 hinzugefügt, 1 entfernt

Änderungen an woocommerce/single-product/add-to-cart/variable.php: 1 hinzugefügt, 1 entfernt
Zeile vorher Zeile nachher Änderung Code
65 65 </table>
66 66
67 67 <div class="single_variation_wrap">
68 Entfernt <div class="woocommerce-variation single_variation">
68 Hinzugefügt <div class="woocommerce-variation single_variation" aria-live="polite" aria-atomic="true">
69 69 <div class="woocommerce-variation-description"></div>
70 70 <div class="woocommerce-variation-price"><span class="price"><?php echo wp_kses_post( wc_price( $kb_selected['display_price'] ) ); ?></span></div>
71 71 <div class="woocommerce-variation-availability"><?php echo wp_kses_post( $kb_selected['availability_html'] ); ?></div>

Magento: Rezept live-region-cart-variant

Vorher und nachher anzeigen (1)
makes the price box and the stock message live regions and validates Beispieldaten

app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/price/final_price.phtml Änderungen an app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/price/final_price.phtml: 1 hinzugefügt, 1 entfernt

Änderungen an app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/price/final_price.phtml: 1 hinzugefügt, 1 entfernt
Zeile vorher Zeile nachher Änderung Code
13 13 // Fixed variant: the product-page box carries aria-live="polite" aria-atomic="true" and the stock
14 14 // message (product/view/type/default.phtml) is role="status".
15 15 ?>
16 Entfernt <div class="price-box price-final_price" data-role="priceBox" data-product-id="<?= (int) $product->getId() ?>" data-price-box="product-id-<?= (int) $product->getId() ?>"<?php if ($isProductPage): ?> data-base-price="<?= (float) $amount ?>"<?php endif; ?>>
16 Hinzugefügt <div class="price-box price-final_price" data-role="priceBox" data-product-id="<?= (int) $product->getId() ?>" data-price-box="product-id-<?= (int) $product->getId() ?>"<?php if ($isProductPage): ?> data-base-price="<?= (float) $amount ?>"<?php endif; ?> aria-live="polite" aria-atomic="true">
17 17 <span class="normal-price"><span class="price-container price-final_price tax weee"><span id="product-price-<?= (int) $product->getId() ?>" data-price-amount="<?= (float) $amount ?>" data-price-type="finalPrice" class="price-wrapper"><span class="price"><?= $escaper->escapeHtml($block->renderAmount($block->getPriceType('final_price')->getAmount(), ['display_label' => false])) ?></span></span></span></span>
18 18 </div>

app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/view/type/default.phtml Änderungen an app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/view/type/default.phtml: 1 hinzugefügt, 1 entfernt

Änderungen an app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/view/type/default.phtml: 1 hinzugefügt, 1 entfernt
Zeile vorher Zeile nachher Änderung Code
11 11 ?>
12 12 <div class="product-info-stock-sku">
13 13 <?php if ($block->displayProductStockStatus()): ?>
14 Entfernt <div class="stock available" title="<?= $escaper->escapeHtmlAttr(__('Availability')) ?>"><span><?= $escaper->escapeHtml(__('In stock')) ?></span></div>
14 Hinzugefügt <div class="stock available" title="<?= $escaper->escapeHtmlAttr(__('Availability')) ?>" role="status"><span><?= $escaper->escapeHtml(__('In stock')) ?></span></div>
15 15 <?php endif; ?>
16 16 <div class="product attribute sku"><strong class="type"><?= $escaper->escapeHtml(__('SKU')) ?></strong> <div class="value" itemprop="sku"><?= $escaper->escapeHtml($product->getSku()) ?></div></div>
17 17 </div>

Beginnen Sie mit einem kostenlosen Check Ihres Shops.

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

Kostenlosen Check anfordern

Oder schreiben Sie an info@validiscan.com.

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

Nachricht an Validiscan

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

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