Ændringer i pris, variant, lagerstatus og kurv skal formidles til skærmlæsere

Når en kunde vælger en størrelse, og prisen eller lagerstatus ændrer sig, eller når kunden lægger et produkt i kurven, kan seende kunder se opdateringen. Skærmlæserbrugere hører ingenting, så de ved ikke, at produktet er lagt i kurven, eller at den valgte størrelse er udsolgt.

Regel-id
vs-live-updates
Kilde
Validiscan-kontrol
Alvorlighed
Alvorlig
Rettelsesniveau
AUTO
på Shopify, Shopware, WooCommerce og Magento
Status
køres

Hvad kontrollen gør

Finder ændringer i pris, variant, lagerstatus og kurv på produkt- og kurvsider, der sker uden et live-område, samt aria-live-områder, der omslutter hele siden (4.1.3).

Kontrollen kører kun på produkt- og kurvsider. Hvert aria-live="polite" eller "assertive" på html, body, main eller et element, der indeholder main, rapporteres.

Den ændrer ét betjeningselement uden for header, navigation, footer og dialoger og blokerer imens afsendelse af formularer. Produktside: det første variant-select (navngivet efter størrelse, farve eller lignende, eller placeret i produktområdet), ellers en gruppe radioknapper til varianter, ellers farveprøveknapper, hvoraf én er valgt. Kurvside: det første antalsfelt, som ændres med én.

Før og efter aflæser den tekster på op til 120 tegn, hvis itemprop, klasse eller id tyder på en pris, lagerstatus, et antal i kurven eller et totalbeløb, samt knappen »Læg i kurv«; siden får op til 2 sekunder til at falde til ro. En ændret synlig tekst rapporteres, medmindre den ligger inde i eller indeholder et live-område (aria-live="polite" eller "assertive", role="status", "alert", "log", output), eller et andet live-område har annonceret en ændring (for priser og lagerstatus ét, der indeholder den nye værdi). En ændring, der ikke går tilbage, når betjeningselementet nulstilles, får resultatet »kræver gennemgang«, som i dag ikke bliver til et fund.

Sådan retter du det

Tilføj et lille, permanent live-område (role="status" eller aria-live="polite") til pris, lagerstatus og antal varer i kurven, og opdater dets tekst, når varianten eller kurven ændrer sig. Sæt ikke aria-live på store containere eller hele siden, for så læser skærmlæsere det hele op igen.

WCAG-succeskriterier

Afsnit i EN 301 549

Afsnittet i EN 301 549 for hvert kriterium, fordelt på versioner af standarden
WCAG-kriterium Version 3.2.1 Version 4.1.1
4.1.3 9.4.1.3 9.4.1.3

Hvor en opskrift retter det

Shopify: opskrift live-region-cart-variant

Vis før og efter (1)
Før og efter Eksempeldata

sections/main-cart.liquid Ændringer i sections/main-cart.liquid: 1 tilføjet, 1 fjernet

Ændringer i sections/main-cart.liquid: 1 tilføjet, 1 fjernet
Linje før Linje efter Ændring Kode
37 37
38 38 <div class="cart__footer">
39 39 <h2 class="cart__summary-title">Order summary</h2>
40 Fjernet <p class="totals">
40 Tilføjet <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 Ændringer i sections/main-product.liquid: 1 tilføjet, 1 fjernet

Ændringer i sections/main-product.liquid: 1 tilføjet, 1 fjernet
Linje før Linje efter Ændring Kode
71 71 </div>
72 72 {%- endif %}
73 73
74 Fjernet <div class="product__price" data-price-container>
74 Tilføjet <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: opskrift live-region-cart-variant

Vis før og efter (1)
makes the variant price and the cart totals polite live regions; the updates are announced Eksempeldata

Resources/views/storefront/page/checkout/cart/index.html.twig Ændringer i Resources/views/storefront/page/checkout/cart/index.html.twig: 2 tilføjet, 2 fjernet

Ændringer i Resources/views/storefront/page/checkout/cart/index.html.twig: 2 tilføjet, 2 fjernet
Linje før Linje efter Ændring Kode
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 Fjernet <div class="line-item-total-price">
62 Tilføjet <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 Fjernet <div class="checkout-aside-summary-totals" data-shipping-threshold="{{ shop.shippingThreshold }}" data-shipping-costs="{{ shop.shippingCosts }}">
91 Tilføjet <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 Ændringer i Resources/views/storefront/page/product-detail/buy-widget.html.twig: 1 tilføjet, 1 fjernet

Ændringer i Resources/views/storefront/page/product-detail/buy-widget.html.twig: 1 tilføjet, 1 fjernet
Linje før Linje efter Ændring Kode
17 17 {% endblock %}
18 18
19 19 {% block buy_widget_price %}
20 Fjernet <div class="product-detail-price-container">
20 Tilføjet <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: opskrift live-region-cart-variant

Vis før og efter (2)
adds a status region next to the header cart fragment and wires the theme script Eksempeldata

assets/js/theme.js Ændringer i assets/js/theme.js: 15 tilføjet, 0 fjernet

Ændringer i assets/js/theme.js: 15 tilføjet, 0 fjernet
Linje før Linje efter Ændring Kode
255 255 initCheckout();
256 256 initShowPassword();
257 257 })();
258 Tilføjet
259 Tilføjet /* validiscan:live-region-cart-variant */
260 Tilføjet // Announces cart changes in the status region next to the header cart (WCAG 4.1.3).
261 Tilføjet (function () {
262 Tilføjet const region = document.querySelector('[data-kb-cart-status]');
263 Tilføjet if (!region || !window.jQuery) return;
264 Tilføjet window.jQuery(document.body).on('added_to_cart removed_from_cart', (event) => {
265 Tilføjet const message = region.getAttribute(event.type === 'added_to_cart' ? 'data-added' : 'data-removed');
266 Tilføjet region.textContent = '';
267 Tilføjet window.setTimeout(() => {
268 Tilføjet region.textContent = message || '';
269 Tilføjet }, 100);
270 Tilføjet });
271 Tilføjet })();
272 Tilføjet /* /validiscan:live-region-cart-variant */

header.php Ændringer i header.php: 1 tilføjet, 0 fjernet

Ændringer i header.php: 1 tilføjet, 0 fjernet
Linje før Linje efter Ændring Kode
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 Tilføjet <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 Eksempeldata

woocommerce/single-product/add-to-cart/variable.php Ændringer i woocommerce/single-product/add-to-cart/variable.php: 1 tilføjet, 1 fjernet

Ændringer i woocommerce/single-product/add-to-cart/variable.php: 1 tilføjet, 1 fjernet
Linje før Linje efter Ændring Kode
65 65 </table>
66 66
67 67 <div class="single_variation_wrap">
68 Fjernet <div class="woocommerce-variation single_variation">
68 Tilføjet <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: opskrift live-region-cart-variant

Vis før og efter (1)
makes the price box and the stock message live regions and validates Eksempeldata

app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/price/final_price.phtml Ændringer i app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/price/final_price.phtml: 1 tilføjet, 1 fjernet

Ændringer i app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/price/final_price.phtml: 1 tilføjet, 1 fjernet
Linje før Linje efter Ændring Kode
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 Fjernet <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 Tilføjet <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 Ændringer i app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/view/type/default.phtml: 1 tilføjet, 1 fjernet

Ændringer i app/design/frontend/Validiscan/fixture/Magento_Catalog/templates/product/view/type/default.phtml: 1 tilføjet, 1 fjernet
Linje før Linje efter Ændring Kode
11 11 ?>
12 12 <div class="product-info-stock-sku">
13 13 <?php if ($block->displayProductStockStatus()): ?>
14 Fjernet <div class="stock available" title="<?= $escaper->escapeHtmlAttr(__('Availability')) ?>"><span><?= $escaper->escapeHtml(__('In stock')) ?></span></div>
14 Tilføjet <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>

Begynd med et gratis tjek af din webshop.

Send din webshops adresse. Validiscan scanner den og svarer med hver fejl, scanningen kan påvise, med siden og koden.

Bestil et gratis tjek

Eller skriv til info@validiscan.com.

Hvad det gratis tjek omfatter, og hvad det udelader
Du sender
din webshops adresse
Sider, der scannes
op til 15
Du får
hver fejl, scanningen kan påvise, med siden og koden
På din webshop
kun offentlige sider; intet login, intet købt, ingen formularer sendt
Hvad det ikke er
et fuldt audit

Skriv til Validiscan

Til et gratis tjek skal du skrive din webshops adresse og platform.

Validiscan bruger det, du sender, til at svare dig. Privatlivspolitik